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