• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.recents.model;
18 
19 import android.app.ActivityManager;
20 import android.app.ActivityManager.TaskThumbnail;
21 import android.content.ComponentName;
22 import android.content.Intent;
23 import android.content.pm.ActivityInfo;
24 import android.graphics.Bitmap;
25 import android.graphics.Color;
26 import android.graphics.Rect;
27 import android.graphics.drawable.Drawable;
28 import android.view.ViewDebug;
29 
30 import com.android.systemui.recents.Recents;
31 import com.android.systemui.recents.misc.SystemServicesProxy;
32 import com.android.systemui.recents.misc.Utilities;
33 
34 import java.io.PrintWriter;
35 import java.util.ArrayList;
36 import java.util.Objects;
37 
38 
39 /**
40  * A task represents the top most task in the system's task stack.
41  */
42 public class Task {
43 
44     public static final String TAG = "Task";
45 
46     /* Task callbacks */
47     public interface TaskCallbacks {
48         /* Notifies when a task has been bound */
onTaskDataLoaded(Task task, ThumbnailData thumbnailData)49         public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData);
50         /* Notifies when a task has been unbound */
onTaskDataUnloaded()51         public void onTaskDataUnloaded();
52         /* Notifies when a task's stack id has changed. */
onTaskStackIdChanged()53         public void onTaskStackIdChanged();
54     }
55 
56     /* The Task Key represents the unique primary key for the task */
57     public static class TaskKey {
58         @ViewDebug.ExportedProperty(category="recents")
59         public final int id;
60         @ViewDebug.ExportedProperty(category="recents")
61         public int stackId;
62         @ViewDebug.ExportedProperty(category="recents")
63         public final Intent baseIntent;
64         @ViewDebug.ExportedProperty(category="recents")
65         public final int userId;
66         @ViewDebug.ExportedProperty(category="recents")
67         public long firstActiveTime;
68         @ViewDebug.ExportedProperty(category="recents")
69         public long lastActiveTime;
70 
71         private int mHashCode;
72 
TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime, long lastActiveTime)73         public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime,
74                 long lastActiveTime) {
75             this.id = id;
76             this.stackId = stackId;
77             this.baseIntent = intent;
78             this.userId = userId;
79             this.firstActiveTime = firstActiveTime;
80             this.lastActiveTime = lastActiveTime;
81             updateHashCode();
82         }
83 
setStackId(int stackId)84         public void setStackId(int stackId) {
85             this.stackId = stackId;
86             updateHashCode();
87         }
88 
getComponent()89         public ComponentName getComponent() {
90             return this.baseIntent.getComponent();
91         }
92 
93         @Override
equals(Object o)94         public boolean equals(Object o) {
95             if (!(o instanceof TaskKey)) {
96                 return false;
97             }
98             TaskKey otherKey = (TaskKey) o;
99             return id == otherKey.id && stackId == otherKey.stackId && userId == otherKey.userId;
100         }
101 
102         @Override
hashCode()103         public int hashCode() {
104             return mHashCode;
105         }
106 
107         @Override
toString()108         public String toString() {
109             return "id=" + id + " stackId=" + stackId + " user=" + userId + " lastActiveTime=" +
110                     lastActiveTime;
111         }
112 
updateHashCode()113         private void updateHashCode() {
114             mHashCode = Objects.hash(id, stackId, userId);
115         }
116     }
117 
118     @ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
119     public TaskKey key;
120 
121     /**
122      * The temporary sort index in the stack, used when ordering the stack.
123      */
124     public int temporarySortIndexInStack;
125 
126     /**
127      * The group will be computed separately from the initialization of the task
128      */
129     @ViewDebug.ExportedProperty(deepExport=true, prefix="group_")
130     public TaskGrouping group;
131     /**
132      * The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
133      * with any task.
134      */
135     @ViewDebug.ExportedProperty(category="recents")
136     public int affiliationTaskId;
137     @ViewDebug.ExportedProperty(category="recents")
138     public int affiliationColor;
139 
140     /**
141      * The icon is the task description icon (if provided), which falls back to the activity icon,
142      * which can then fall back to the application icon.
143      */
144     public Drawable icon;
145     public ThumbnailData thumbnail;
146     @ViewDebug.ExportedProperty(category="recents")
147     public String title;
148     @ViewDebug.ExportedProperty(category="recents")
149     public String titleDescription;
150     @ViewDebug.ExportedProperty(category="recents")
151     public String dismissDescription;
152     @ViewDebug.ExportedProperty(category="recents")
153     public String appInfoDescription;
154     @ViewDebug.ExportedProperty(category="recents")
155     public int colorPrimary;
156     @ViewDebug.ExportedProperty(category="recents")
157     public int colorBackground;
158     @ViewDebug.ExportedProperty(category="recents")
159     public boolean useLightOnPrimaryColor;
160 
161     /**
162      * The bounds of the task, used only if it is a freeform task.
163      */
164     @ViewDebug.ExportedProperty(category="recents")
165     public Rect bounds;
166 
167     /**
168      * The task description for this task, only used to reload task icons.
169      */
170     public ActivityManager.TaskDescription taskDescription;
171 
172     /**
173      * The state isLaunchTarget will be set for the correct task upon launching Recents.
174      */
175     @ViewDebug.ExportedProperty(category="recents")
176     public boolean isLaunchTarget;
177     @ViewDebug.ExportedProperty(category="recents")
178     public boolean isStackTask;
179     @ViewDebug.ExportedProperty(category="recents")
180     public boolean isSystemApp;
181     @ViewDebug.ExportedProperty(category="recents")
182     public boolean isDockable;
183 
184     /**
185      * Resize mode. See {@link ActivityInfo#resizeMode}.
186      */
187     @ViewDebug.ExportedProperty(category="recents")
188     public int resizeMode;
189 
190     @ViewDebug.ExportedProperty(category="recents")
191     public ComponentName topActivity;
192 
193     @ViewDebug.ExportedProperty(category="recents")
194     public boolean isLocked;
195 
196     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
197 
Task()198     public Task() {
199         // Do nothing
200     }
201 
Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon, ThumbnailData thumbnail, String title, String titleDescription, String dismissDescription, String appInfoDescription, int colorPrimary, int colorBackground, boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp, boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription, int resizeMode, ComponentName topActivity, boolean isLocked)202     public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
203             ThumbnailData thumbnail, String title, String titleDescription,
204             String dismissDescription, String appInfoDescription, int colorPrimary,
205             int colorBackground, boolean isLaunchTarget, boolean isStackTask, boolean isSystemApp,
206             boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription,
207             int resizeMode, ComponentName topActivity, boolean isLocked) {
208         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
209         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
210         this.key = key;
211         this.affiliationTaskId = affiliationTaskId;
212         this.affiliationColor = affiliationColor;
213         this.icon = icon;
214         this.thumbnail = thumbnail;
215         this.title = title;
216         this.titleDescription = titleDescription;
217         this.dismissDescription = dismissDescription;
218         this.appInfoDescription = appInfoDescription;
219         this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
220         this.colorBackground = colorBackground;
221         this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
222                 Color.WHITE) > 3f;
223         this.bounds = bounds;
224         this.taskDescription = taskDescription;
225         this.isLaunchTarget = isLaunchTarget;
226         this.isStackTask = isStackTask;
227         this.isSystemApp = isSystemApp;
228         this.isDockable = isDockable;
229         this.resizeMode = resizeMode;
230         this.topActivity = topActivity;
231         this.isLocked = isLocked;
232     }
233 
234     /**
235      * Copies the metadata from another task, but retains the current callbacks.
236      */
copyFrom(Task o)237     public void copyFrom(Task o) {
238         this.key = o.key;
239         this.group = o.group;
240         this.affiliationTaskId = o.affiliationTaskId;
241         this.affiliationColor = o.affiliationColor;
242         this.icon = o.icon;
243         this.thumbnail = o.thumbnail;
244         this.title = o.title;
245         this.titleDescription = o.titleDescription;
246         this.dismissDescription = o.dismissDescription;
247         this.appInfoDescription = o.appInfoDescription;
248         this.colorPrimary = o.colorPrimary;
249         this.colorBackground = o.colorBackground;
250         this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
251         this.bounds = o.bounds;
252         this.taskDescription = o.taskDescription;
253         this.isLaunchTarget = o.isLaunchTarget;
254         this.isStackTask = o.isStackTask;
255         this.isSystemApp = o.isSystemApp;
256         this.isDockable = o.isDockable;
257         this.resizeMode = o.resizeMode;
258         this.isLocked = o.isLocked;
259         this.topActivity = o.topActivity;
260     }
261 
262     /**
263      * Add a callback.
264      */
addCallback(TaskCallbacks cb)265     public void addCallback(TaskCallbacks cb) {
266         if (!mCallbacks.contains(cb)) {
267             mCallbacks.add(cb);
268         }
269     }
270 
271     /**
272      * Remove a callback.
273      */
removeCallback(TaskCallbacks cb)274     public void removeCallback(TaskCallbacks cb) {
275         mCallbacks.remove(cb);
276     }
277 
278     /** Set the grouping */
setGroup(TaskGrouping group)279     public void setGroup(TaskGrouping group) {
280         this.group = group;
281     }
282 
283     /**
284      * Updates the stack id of this task.
285      */
setStackId(int stackId)286     public void setStackId(int stackId) {
287         key.setStackId(stackId);
288         int callbackCount = mCallbacks.size();
289         for (int i = 0; i < callbackCount; i++) {
290             mCallbacks.get(i).onTaskStackIdChanged();
291         }
292     }
293 
294     /**
295      * Returns whether this task is on the freeform task stack.
296      */
isFreeformTask()297     public boolean isFreeformTask() {
298         SystemServicesProxy ssp = Recents.getSystemServices();
299         return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId);
300     }
301 
302     /** Notifies the callback listeners that this task has been loaded */
notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon)303     public void notifyTaskDataLoaded(ThumbnailData thumbnailData, Drawable applicationIcon) {
304         this.icon = applicationIcon;
305         this.thumbnail = thumbnailData;
306         int callbackCount = mCallbacks.size();
307         for (int i = 0; i < callbackCount; i++) {
308             mCallbacks.get(i).onTaskDataLoaded(this, thumbnailData);
309         }
310     }
311 
312     /** Notifies the callback listeners that this task has been unloaded */
notifyTaskDataUnloaded(Drawable defaultApplicationIcon)313     public void notifyTaskDataUnloaded(Drawable defaultApplicationIcon) {
314         icon = defaultApplicationIcon;
315         thumbnail = null;
316         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
317             mCallbacks.get(i).onTaskDataUnloaded();
318         }
319     }
320 
321     /**
322      * Returns whether this task is affiliated with another task.
323      */
isAffiliatedTask()324     public boolean isAffiliatedTask() {
325         return key.id != affiliationTaskId;
326     }
327 
328     /**
329      * Returns the top activity component.
330      */
getTopComponent()331     public ComponentName getTopComponent() {
332         return topActivity != null
333                 ? topActivity
334                 : key.baseIntent.getComponent();
335     }
336 
337     @Override
equals(Object o)338     public boolean equals(Object o) {
339         // Check that the id matches
340         Task t = (Task) o;
341         return key.equals(t.key);
342     }
343 
344     @Override
toString()345     public String toString() {
346         return "[" + key.toString() + "] " + title;
347     }
348 
dump(String prefix, PrintWriter writer)349     public void dump(String prefix, PrintWriter writer) {
350         writer.print(prefix); writer.print(key);
351         if (isAffiliatedTask()) {
352             writer.print(" "); writer.print("affTaskId=" + affiliationTaskId);
353         }
354         if (!isDockable) {
355             writer.print(" dockable=N");
356         }
357         if (isLaunchTarget) {
358             writer.print(" launchTarget=Y");
359         }
360         if (isFreeformTask()) {
361             writer.print(" freeform=Y");
362         }
363         if (isLocked) {
364             writer.print(" locked=Y");
365         }
366         writer.print(" "); writer.print(title);
367         writer.println();
368     }
369 }
370