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