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