1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.shared.recents.model; 18 19 import static android.view.Display.DEFAULT_DISPLAY; 20 21 import android.app.ActivityManager; 22 import android.app.ActivityManager.TaskDescription; 23 import android.app.TaskInfo; 24 import android.content.ComponentName; 25 import android.content.Intent; 26 import android.content.pm.ActivityInfo; 27 import android.graphics.Color; 28 import android.graphics.drawable.Drawable; 29 import android.view.ViewDebug; 30 31 import com.android.systemui.shared.recents.utilities.Utilities; 32 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 import java.util.Objects; 36 37 /** 38 * A task in the recent tasks list. 39 */ 40 public class Task { 41 42 public static final String TAG = "Task"; 43 44 /* Task callbacks */ 45 @Deprecated 46 public interface TaskCallbacks { 47 /* Notifies when a task has been bound */ onTaskDataLoaded(Task task, ThumbnailData thumbnailData)48 void onTaskDataLoaded(Task task, ThumbnailData thumbnailData); 49 /* Notifies when a task has been unbound */ onTaskDataUnloaded()50 void onTaskDataUnloaded(); 51 /* Notifies when a task's windowing mode has changed. */ onTaskWindowingModeChanged()52 void onTaskWindowingModeChanged(); 53 } 54 55 /* The Task Key represents the unique primary key for the task */ 56 public static class TaskKey { 57 @ViewDebug.ExportedProperty(category="recents") 58 public final int id; 59 @ViewDebug.ExportedProperty(category="recents") 60 public int windowingMode; 61 @ViewDebug.ExportedProperty(category="recents") 62 public final Intent baseIntent; 63 @ViewDebug.ExportedProperty(category="recents") 64 public final int userId; 65 @ViewDebug.ExportedProperty(category="recents") 66 public long lastActiveTime; 67 68 /** 69 * The id of the task was running from which display. 70 */ 71 @ViewDebug.ExportedProperty(category = "recents") 72 public final int displayId; 73 74 // The source component name which started this task 75 public final ComponentName sourceComponent; 76 77 private int mHashCode; 78 TaskKey(TaskInfo t)79 public TaskKey(TaskInfo t) { 80 ComponentName sourceComponent = t.origActivity != null 81 // Activity alias if there is one 82 ? t.origActivity 83 // The real activity if there is no alias (or the target if there is one) 84 : t.realActivity; 85 this.id = t.taskId; 86 this.windowingMode = t.configuration.windowConfiguration.getWindowingMode(); 87 this.baseIntent = t.baseIntent; 88 this.sourceComponent = sourceComponent; 89 this.userId = t.userId; 90 this.lastActiveTime = t.lastActiveTime; 91 this.displayId = t.displayId; 92 updateHashCode(); 93 } 94 TaskKey(int id, int windowingMode, Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime)95 public TaskKey(int id, int windowingMode, Intent intent, 96 ComponentName sourceComponent, int userId, long lastActiveTime) { 97 this.id = id; 98 this.windowingMode = windowingMode; 99 this.baseIntent = intent; 100 this.sourceComponent = sourceComponent; 101 this.userId = userId; 102 this.lastActiveTime = lastActiveTime; 103 this.displayId = DEFAULT_DISPLAY; 104 updateHashCode(); 105 } 106 TaskKey(int id, int windowingMode, Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime, int displayId)107 public TaskKey(int id, int windowingMode, Intent intent, 108 ComponentName sourceComponent, int userId, long lastActiveTime, int displayId) { 109 this.id = id; 110 this.windowingMode = windowingMode; 111 this.baseIntent = intent; 112 this.sourceComponent = sourceComponent; 113 this.userId = userId; 114 this.lastActiveTime = lastActiveTime; 115 this.displayId = displayId; 116 updateHashCode(); 117 } 118 setWindowingMode(int windowingMode)119 public void setWindowingMode(int windowingMode) { 120 this.windowingMode = windowingMode; 121 updateHashCode(); 122 } 123 getComponent()124 public ComponentName getComponent() { 125 return this.baseIntent.getComponent(); 126 } 127 getPackageName()128 public String getPackageName() { 129 if (this.baseIntent.getComponent() != null) { 130 return this.baseIntent.getComponent().getPackageName(); 131 } 132 return this.baseIntent.getPackage(); 133 } 134 135 @Override equals(Object o)136 public boolean equals(Object o) { 137 if (!(o instanceof TaskKey)) { 138 return false; 139 } 140 TaskKey otherKey = (TaskKey) o; 141 return id == otherKey.id 142 && windowingMode == otherKey.windowingMode 143 && userId == otherKey.userId; 144 } 145 146 @Override hashCode()147 public int hashCode() { 148 return mHashCode; 149 } 150 151 @Override toString()152 public String toString() { 153 return "id=" + id + " windowingMode=" + windowingMode + " user=" + userId 154 + " lastActiveTime=" + lastActiveTime; 155 } 156 updateHashCode()157 private void updateHashCode() { 158 mHashCode = Objects.hash(id, windowingMode, userId); 159 } 160 } 161 162 @ViewDebug.ExportedProperty(deepExport=true, prefix="key_") 163 public TaskKey key; 164 165 /** 166 * The temporary sort index in the stack, used when ordering the stack. 167 */ 168 @Deprecated 169 public int temporarySortIndexInStack; 170 171 /** 172 * The icon is the task description icon (if provided), which falls back to the activity icon, 173 * which can then fall back to the application icon. 174 */ 175 public Drawable icon; 176 public ThumbnailData thumbnail; 177 @ViewDebug.ExportedProperty(category="recents") 178 @Deprecated 179 public String title; 180 @ViewDebug.ExportedProperty(category="recents") 181 public String titleDescription; 182 @ViewDebug.ExportedProperty(category="recents") 183 public int colorPrimary; 184 @ViewDebug.ExportedProperty(category="recents") 185 public int colorBackground; 186 @ViewDebug.ExportedProperty(category="recents") 187 @Deprecated 188 public boolean useLightOnPrimaryColor; 189 190 /** 191 * The task description for this task, only used to reload task icons. 192 */ 193 public TaskDescription taskDescription; 194 195 /** 196 * The state isLaunchTarget will be set for the correct task upon launching Recents. 197 */ 198 @ViewDebug.ExportedProperty(category="recents") 199 @Deprecated 200 public boolean isLaunchTarget; 201 @ViewDebug.ExportedProperty(category="recents") 202 @Deprecated 203 public boolean isStackTask; 204 @ViewDebug.ExportedProperty(category="recents") 205 @Deprecated 206 public boolean isSystemApp; 207 @ViewDebug.ExportedProperty(category="recents") 208 public boolean isDockable; 209 210 /** 211 * Resize mode. See {@link ActivityInfo#resizeMode}. 212 */ 213 @ViewDebug.ExportedProperty(category="recents") 214 @Deprecated 215 public int resizeMode; 216 217 @ViewDebug.ExportedProperty(category="recents") 218 public ComponentName topActivity; 219 220 @ViewDebug.ExportedProperty(category="recents") 221 public boolean isLocked; 222 223 @Deprecated 224 private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>(); 225 Task()226 public Task() { 227 // Do nothing 228 } 229 230 /** 231 * Creates a task object from the provided task info 232 */ from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked)233 public static Task from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked) { 234 ActivityManager.TaskDescription td = taskInfo.taskDescription; 235 return new Task(taskKey, 236 td != null ? td.getPrimaryColor() : 0, 237 td != null ? td.getBackgroundColor() : 0, 238 taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity); 239 } 240 Task(TaskKey key)241 public Task(TaskKey key) { 242 this.key = key; 243 this.taskDescription = new TaskDescription(); 244 } 245 Task(TaskKey key, int colorPrimary, int colorBackground, boolean isDockable, boolean isLocked, TaskDescription taskDescription, ComponentName topActivity)246 public Task(TaskKey key, int colorPrimary, int colorBackground, 247 boolean isDockable, boolean isLocked, TaskDescription taskDescription, 248 ComponentName topActivity) { 249 this.key = key; 250 this.colorPrimary = colorPrimary; 251 this.colorBackground = colorBackground; 252 this.taskDescription = taskDescription; 253 this.isDockable = isDockable; 254 this.isLocked = isLocked; 255 this.topActivity = topActivity; 256 } 257 258 @Deprecated Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title, String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp, boolean isDockable, TaskDescription taskDescription, int resizeMode, ComponentName topActivity, boolean isLocked)259 public Task(TaskKey key, Drawable icon, ThumbnailData thumbnail, String title, 260 String titleDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget, 261 boolean isStackTask, boolean isSystemApp, boolean isDockable, 262 TaskDescription taskDescription, int resizeMode, ComponentName topActivity, 263 boolean isLocked) { 264 this.key = key; 265 this.icon = icon; 266 this.thumbnail = thumbnail; 267 this.title = title; 268 this.titleDescription = titleDescription; 269 this.colorPrimary = colorPrimary; 270 this.colorBackground = colorBackground; 271 this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary, 272 Color.WHITE) > 3f; 273 this.taskDescription = taskDescription; 274 this.isLaunchTarget = isLaunchTarget; 275 this.isStackTask = isStackTask; 276 this.isSystemApp = isSystemApp; 277 this.isDockable = isDockable; 278 this.resizeMode = resizeMode; 279 this.topActivity = topActivity; 280 this.isLocked = isLocked; 281 } 282 283 /** 284 * Copies the metadata from another task, but retains the current callbacks. 285 */ 286 @Deprecated copyFrom(Task o)287 public void copyFrom(Task o) { 288 this.key = o.key; 289 this.icon = o.icon; 290 this.thumbnail = o.thumbnail; 291 this.title = o.title; 292 this.titleDescription = o.titleDescription; 293 this.colorPrimary = o.colorPrimary; 294 this.colorBackground = o.colorBackground; 295 this.useLightOnPrimaryColor = o.useLightOnPrimaryColor; 296 this.taskDescription = o.taskDescription; 297 this.isLaunchTarget = o.isLaunchTarget; 298 this.isStackTask = o.isStackTask; 299 this.isSystemApp = o.isSystemApp; 300 this.isDockable = o.isDockable; 301 this.resizeMode = o.resizeMode; 302 this.isLocked = o.isLocked; 303 this.topActivity = o.topActivity; 304 } 305 306 /** 307 * Add a callback. 308 */ 309 @Deprecated addCallback(TaskCallbacks cb)310 public void addCallback(TaskCallbacks cb) { 311 if (!mCallbacks.contains(cb)) { 312 mCallbacks.add(cb); 313 } 314 } 315 316 /** 317 * Remove a callback. 318 */ 319 @Deprecated removeCallback(TaskCallbacks cb)320 public void removeCallback(TaskCallbacks cb) { 321 mCallbacks.remove(cb); 322 } 323 324 /** Updates the task's windowing mode. */ 325 @Deprecated setWindowingMode(int windowingMode)326 public void setWindowingMode(int windowingMode) { 327 key.setWindowingMode(windowingMode); 328 int callbackCount = mCallbacks.size(); 329 for (int i = 0; i < callbackCount; i++) { 330 mCallbacks.get(i).onTaskWindowingModeChanged(); 331 } 332 } 333 334 /** Notifies the callback listeners that this task has been loaded */ 335 @Deprecated notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon)336 public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) { 337 this.icon = applicationIcon; 338 this.thumbnail = thumbnailData; 339 int callbackCount = mCallbacks.size(); 340 for (int i = 0; i < callbackCount; i++) { 341 mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData); 342 } 343 } 344 345 /** Notifies the callback listeners that this task has been unloaded */ 346 @Deprecated notifyTaskDataUnloaded(Drawable defaultApplicationIcon)347 public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) { 348 icon = defaultApplicationIcon; 349 thumbnail = null; 350 for (int i = mCallbacks.size() - 1; i >= 0; i--) { 351 mCallbacks.get(i).onTaskDataUnloaded(); 352 } 353 } 354 355 /** 356 * Returns the top activity component. 357 */ getTopComponent()358 public ComponentName getTopComponent() { 359 return topActivity != null 360 ? topActivity 361 : key.baseIntent.getComponent(); 362 } 363 364 @Override equals(Object o)365 public boolean equals(Object o) { 366 // Check that the id matches 367 Task t = (Task) o; 368 return key.equals(t.key); 369 } 370 371 @Override toString()372 public String toString() { 373 return "[" + key.toString() + "] " + title; 374 } 375 dump(String prefix, PrintWriter writer)376 public void dump(String prefix, PrintWriter writer) { 377 writer.print(prefix); writer.print(key); 378 if (!isDockable) { 379 writer.print(" dockable=N"); 380 } 381 if (isLaunchTarget) { 382 writer.print(" launchTarget=Y"); 383 } 384 if (isLocked) { 385 writer.print(" locked=Y"); 386 } 387 writer.print(" "); writer.print(title); 388 writer.println(); 389 } 390 } 391