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