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.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 20 import static android.view.Display.DEFAULT_DISPLAY; 21 22 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES; 23 import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE; 24 25 import android.app.ActivityManager; 26 import android.app.ActivityManager.TaskDescription; 27 import android.app.TaskInfo; 28 import android.content.ComponentName; 29 import android.content.Intent; 30 import android.graphics.Point; 31 import android.graphics.Rect; 32 import android.graphics.drawable.Drawable; 33 import android.os.Parcel; 34 import android.os.Parcelable; 35 import android.view.ViewDebug; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 40 import com.android.internal.util.ArrayUtils; 41 42 import java.io.PrintWriter; 43 import java.util.Objects; 44 45 /** 46 * A task in the recent tasks list. 47 * TODO: Move this into Launcher or see if we can remove now 48 */ 49 public class Task { 50 51 public static final String TAG = "Task"; 52 53 /** 54 * The Task Key represents the unique primary key for the task 55 */ 56 public static class TaskKey implements Parcelable { 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 @NonNull 63 public final Intent baseIntent; 64 @ViewDebug.ExportedProperty(category="recents") 65 public final int userId; 66 @ViewDebug.ExportedProperty(category="recents") 67 public long lastActiveTime; 68 69 /** 70 * The id of the task was running from which display. 71 */ 72 @ViewDebug.ExportedProperty(category = "recents") 73 public final int displayId; 74 75 // The source component name which started this task 76 public final ComponentName sourceComponent; 77 78 private int mHashCode; 79 TaskKey(TaskInfo t)80 public TaskKey(TaskInfo t) { 81 ComponentName sourceComponent = t.origActivity != null 82 // Activity alias if there is one 83 ? t.origActivity 84 // The real activity if there is no alias (or the target if there is one) 85 : t.realActivity; 86 this.id = t.taskId; 87 this.windowingMode = t.configuration.windowConfiguration.getWindowingMode(); 88 this.baseIntent = t.baseIntent; 89 this.sourceComponent = sourceComponent; 90 this.userId = t.userId; 91 this.lastActiveTime = t.lastActiveTime; 92 this.displayId = t.displayId; 93 updateHashCode(); 94 } 95 TaskKey(int id, int windowingMode, @NonNull Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime)96 public TaskKey(int id, int windowingMode, @NonNull Intent intent, 97 ComponentName sourceComponent, int userId, long lastActiveTime) { 98 this.id = id; 99 this.windowingMode = windowingMode; 100 this.baseIntent = intent; 101 this.sourceComponent = sourceComponent; 102 this.userId = userId; 103 this.lastActiveTime = lastActiveTime; 104 this.displayId = DEFAULT_DISPLAY; 105 updateHashCode(); 106 } 107 TaskKey(int id, int windowingMode, @NonNull Intent intent, ComponentName sourceComponent, int userId, long lastActiveTime, int displayId)108 public TaskKey(int id, int windowingMode, @NonNull Intent intent, 109 ComponentName sourceComponent, int userId, long lastActiveTime, int displayId) { 110 this.id = id; 111 this.windowingMode = windowingMode; 112 this.baseIntent = intent; 113 this.sourceComponent = sourceComponent; 114 this.userId = userId; 115 this.lastActiveTime = lastActiveTime; 116 this.displayId = displayId; 117 updateHashCode(); 118 } 119 setWindowingMode(int windowingMode)120 public void setWindowingMode(int windowingMode) { 121 this.windowingMode = windowingMode; 122 updateHashCode(); 123 } 124 getComponent()125 public ComponentName getComponent() { 126 return this.baseIntent.getComponent(); 127 } 128 getPackageName()129 public String getPackageName() { 130 if (this.baseIntent.getComponent() != null) { 131 return this.baseIntent.getComponent().getPackageName(); 132 } 133 return this.baseIntent.getPackage(); 134 } 135 getId()136 public int getId() { 137 return id; 138 } 139 140 @Override equals(Object o)141 public boolean equals(Object o) { 142 if (!(o instanceof TaskKey)) { 143 return false; 144 } 145 TaskKey otherKey = (TaskKey) o; 146 return id == otherKey.id 147 && windowingMode == otherKey.windowingMode 148 && userId == otherKey.userId; 149 } 150 151 @Override hashCode()152 public int hashCode() { 153 return mHashCode; 154 } 155 156 @Override toString()157 public String toString() { 158 return "id=" + id + " windowingMode=" + windowingMode + " user=" + userId 159 + " lastActiveTime=" + lastActiveTime; 160 } 161 updateHashCode()162 private void updateHashCode() { 163 mHashCode = Objects.hash(id, windowingMode, userId); 164 } 165 166 public static final Parcelable.Creator<TaskKey> CREATOR = 167 new Parcelable.Creator<TaskKey>() { 168 @Override 169 public TaskKey createFromParcel(Parcel source) { 170 return TaskKey.readFromParcel(source); 171 } 172 173 @Override 174 public TaskKey[] newArray(int size) { 175 return new TaskKey[size]; 176 } 177 }; 178 179 @Override writeToParcel(Parcel parcel, int flags)180 public final void writeToParcel(Parcel parcel, int flags) { 181 parcel.writeInt(id); 182 parcel.writeInt(windowingMode); 183 parcel.writeTypedObject(baseIntent, flags); 184 parcel.writeInt(userId); 185 parcel.writeLong(lastActiveTime); 186 parcel.writeInt(displayId); 187 parcel.writeTypedObject(sourceComponent, flags); 188 } 189 readFromParcel(Parcel parcel)190 private static TaskKey readFromParcel(Parcel parcel) { 191 int id = parcel.readInt(); 192 int windowingMode = parcel.readInt(); 193 Intent baseIntent = parcel.readTypedObject(Intent.CREATOR); 194 int userId = parcel.readInt(); 195 long lastActiveTime = parcel.readLong(); 196 int displayId = parcel.readInt(); 197 ComponentName sourceComponent = parcel.readTypedObject(ComponentName.CREATOR); 198 199 return new TaskKey(id, windowingMode, baseIntent, sourceComponent, userId, 200 lastActiveTime, displayId); 201 } 202 203 @Override describeContents()204 public int describeContents() { 205 return 0; 206 } 207 } 208 209 @ViewDebug.ExportedProperty(deepExport=true, prefix="key_") 210 public TaskKey key; 211 212 /** 213 * The icon is the task description icon (if provided), which falls back to the activity icon, 214 * which can then fall back to the application icon. 215 */ 216 @Nullable public Drawable icon; 217 @Nullable public ThumbnailData thumbnail; 218 @ViewDebug.ExportedProperty(category="recents") 219 @Deprecated 220 public String title; 221 @ViewDebug.ExportedProperty(category="recents") 222 public String titleDescription; 223 @ViewDebug.ExportedProperty(category="recents") 224 public int colorPrimary; 225 @ViewDebug.ExportedProperty(category="recents") 226 public int colorBackground; 227 228 /** 229 * The task description for this task, only used to reload task icons. 230 */ 231 public TaskDescription taskDescription; 232 233 @ViewDebug.ExportedProperty(category="recents") 234 public boolean isDockable; 235 236 @ViewDebug.ExportedProperty(category="recents") 237 public ComponentName topActivity; 238 239 @ViewDebug.ExportedProperty(category="recents") 240 public boolean isLocked; 241 242 public Point positionInParent; 243 244 public Rect appBounds; 245 246 // Last snapshot data, only used for recent tasks 247 public ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData = 248 new ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData(); 249 Task()250 public Task() { 251 // Do nothing 252 } 253 254 /** 255 * Creates a task object from the provided task info 256 */ from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked)257 public static Task from(TaskKey taskKey, TaskInfo taskInfo, boolean isLocked) { 258 ActivityManager.TaskDescription td = taskInfo.taskDescription; 259 // Also consider undefined activity type to include tasks in overview right after rebooting 260 // the device. 261 final boolean isDockable = taskInfo.supportsMultiWindow 262 && ArrayUtils.contains( 263 CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, taskInfo.getWindowingMode()) 264 && (taskInfo.getActivityType() == ACTIVITY_TYPE_UNDEFINED 265 || ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())); 266 return new Task(taskKey, 267 td != null ? td.getPrimaryColor() : 0, 268 td != null ? td.getBackgroundColor() : 0, isDockable , isLocked, td, 269 taskInfo.topActivity); 270 } 271 Task(TaskKey key)272 public Task(TaskKey key) { 273 this.key = key; 274 this.taskDescription = new TaskDescription(); 275 } 276 Task(Task other)277 public Task(Task other) { 278 this(other.key, other.colorPrimary, other.colorBackground, other.isDockable, 279 other.isLocked, other.taskDescription, other.topActivity); 280 lastSnapshotData.set(other.lastSnapshotData); 281 positionInParent = other.positionInParent; 282 appBounds = other.appBounds; 283 } 284 285 /** 286 * Use {@link Task#Task(Task)}. 287 */ 288 @Deprecated Task(TaskKey key, int colorPrimary, int colorBackground, boolean isDockable, boolean isLocked, TaskDescription taskDescription, ComponentName topActivity)289 public Task(TaskKey key, int colorPrimary, int colorBackground, 290 boolean isDockable, boolean isLocked, TaskDescription taskDescription, 291 ComponentName topActivity) { 292 this.key = key; 293 this.colorPrimary = colorPrimary; 294 this.colorBackground = colorBackground; 295 this.taskDescription = taskDescription; 296 this.isDockable = isDockable; 297 this.isLocked = isLocked; 298 this.topActivity = topActivity; 299 } 300 301 /** 302 * Returns the top activity component. 303 */ getTopComponent()304 public ComponentName getTopComponent() { 305 return topActivity != null 306 ? topActivity 307 : key.baseIntent.getComponent(); 308 } 309 setLastSnapshotData(ActivityManager.RecentTaskInfo rawTask)310 public void setLastSnapshotData(ActivityManager.RecentTaskInfo rawTask) { 311 lastSnapshotData.set(rawTask.lastSnapshotData); 312 } 313 getKey()314 public TaskKey getKey() { 315 return key; 316 } 317 318 /** 319 * Returns the visible width to height ratio. Returns 0f if snapshot data is not available. 320 */ getVisibleThumbnailRatio(boolean clipInsets)321 public float getVisibleThumbnailRatio(boolean clipInsets) { 322 if (lastSnapshotData.taskSize == null || lastSnapshotData.contentInsets == null) { 323 return 0f; 324 } 325 326 float availableWidth = lastSnapshotData.taskSize.x; 327 float availableHeight = lastSnapshotData.taskSize.y; 328 if (clipInsets) { 329 availableWidth -= 330 (lastSnapshotData.contentInsets.left + lastSnapshotData.contentInsets.right); 331 availableHeight -= 332 (lastSnapshotData.contentInsets.top + lastSnapshotData.contentInsets.bottom); 333 } 334 return availableWidth / availableHeight; 335 } 336 337 @Override equals(Object o)338 public boolean equals(Object o) { 339 if (o == this) { 340 return true; 341 } 342 343 if (!(o instanceof Task)) { 344 return false; 345 } 346 347 // Check that the id matches 348 Task t = (Task) o; 349 return key.equals(t.key); 350 } 351 352 @Override toString()353 public String toString() { 354 return "[" + key.toString() + "] " + title; 355 } 356 dump(String prefix, PrintWriter writer)357 public void dump(String prefix, PrintWriter writer) { 358 writer.print(prefix); writer.print(key); 359 if (!isDockable) { 360 writer.print(" dockable=N"); 361 } 362 if (isLocked) { 363 writer.print(" locked=Y"); 364 } 365 writer.print(" "); writer.print(title); 366 writer.println(); 367 } 368 } 369