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.shared.recents.model;
     18 
     19 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
     20 
     21 import android.app.ActivityManager;
     22 import android.app.KeyguardManager;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.pm.ActivityInfo;
     26 import android.content.pm.ApplicationInfo;
     27 import android.content.res.Resources;
     28 import android.graphics.drawable.Drawable;
     29 import android.util.SparseBooleanArray;
     30 
     31 import com.android.systemui.shared.recents.model.Task.TaskKey;
     32 import com.android.systemui.shared.system.ActivityManagerWrapper;
     33 
     34 import java.util.ArrayList;
     35 import java.util.Collections;
     36 import java.util.List;
     37 
     38 
     39 /**
     40  * This class stores the loading state as it goes through multiple stages of loading:
     41  *   1) preloadRawTasks() will load the raw set of recents tasks from the system
     42  *   2) preloadPlan() will construct a new task stack with all metadata and only icons and
     43  *      thumbnails that are currently in the cache
     44  *   3) executePlan() will actually load and fill in the icons and thumbnails according to the load
     45  *      options specified, such that we can transition into the Recents activity seamlessly
     46  */
     47 public class RecentsTaskLoadPlan {
     48 
     49     /** The set of conditions to preload tasks. */
     50     public static class PreloadOptions {
     51         public boolean loadTitles = true;
     52     }
     53 
     54     /** The set of conditions to load tasks. */
     55     public static class Options {
     56         public int runningTaskId = -1;
     57         public boolean loadIcons = true;
     58         public boolean loadThumbnails = false;
     59         public boolean onlyLoadForCache = false;
     60         public boolean onlyLoadPausedActivities = false;
     61         public int numVisibleTasks = 0;
     62         public int numVisibleTaskThumbnails = 0;
     63     }
     64 
     65     private final Context mContext;
     66     private final KeyguardManager mKeyguardManager;
     67 
     68     private List<ActivityManager.RecentTaskInfo> mRawTasks;
     69     private TaskStack mStack;
     70 
     71     private final SparseBooleanArray mTmpLockedUsers = new SparseBooleanArray();
     72 
     73     public RecentsTaskLoadPlan(Context context) {
     74         mContext = context;
     75         mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
     76     }
     77 
     78     /**
     79      * Preloads the list of recent tasks from the system. After this call, the TaskStack will
     80      * have a list of all the recent tasks with their metadata, not including icons or
     81      * thumbnails which were not cached and have to be loaded.
     82      *
     83      * The tasks will be ordered by:
     84      * - least-recent to most-recent stack tasks
     85      *
     86      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
     87      * this call (callers should synchronize on the loader before making this call).
     88      */
     89     public void preloadPlan(PreloadOptions opts, RecentsTaskLoader loader, int runningTaskId,
     90             int currentUserId) {
     91         Resources res = mContext.getResources();
     92         ArrayList<Task> allTasks = new ArrayList<>();
     93         if (mRawTasks == null) {
     94             mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
     95                     ActivityManager.getMaxRecentTasksStatic(), currentUserId);
     96 
     97             // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
     98             Collections.reverse(mRawTasks);
     99         }
    100 
    101         int taskCount = mRawTasks.size();
    102         for (int i = 0; i < taskCount; i++) {
    103             ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
    104 
    105             // Compose the task key
    106             final ComponentName sourceComponent = t.origActivity != null
    107                     // Activity alias if there is one
    108                     ? t.origActivity
    109                     // The real activity if there is no alias (or the target if there is one)
    110                     : t.realActivity;
    111             final int windowingMode = t.configuration.windowConfiguration.getWindowingMode();
    112             TaskKey taskKey = new TaskKey(t.persistentId, windowingMode, t.baseIntent,
    113                     sourceComponent, t.userId, t.lastActiveTime);
    114 
    115             boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM;
    116             boolean isStackTask = !isFreeformTask;
    117             boolean isLaunchTarget = taskKey.id == runningTaskId;
    118 
    119             ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
    120             if (info == null) {
    121                 continue;
    122             }
    123 
    124             // Load the title, icon, and color
    125             String title = opts.loadTitles
    126                     ? loader.getAndUpdateActivityTitle(taskKey, t.taskDescription)
    127                     : "";
    128             String titleDescription = opts.loadTitles
    129                     ? loader.getAndUpdateContentDescription(taskKey, t.taskDescription)
    130                     : "";
    131             Drawable icon = isStackTask
    132                     ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, false)
    133                     : null;
    134             ThumbnailData thumbnail = loader.getAndUpdateThumbnail(taskKey,
    135                     false /* loadIfNotCached */, false /* storeInCache */);
    136             int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
    137             int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
    138             boolean isSystemApp = (info != null) &&
    139                     ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
    140 
    141             // TODO: Refactor to not do this every preload
    142             if (mTmpLockedUsers.indexOfKey(t.userId) < 0) {
    143                 mTmpLockedUsers.put(t.userId, mKeyguardManager.isDeviceLocked(t.userId));
    144             }
    145             boolean isLocked = mTmpLockedUsers.get(t.userId);
    146 
    147             // Add the task to the stack
    148             Task task = new Task(taskKey, icon,
    149                     thumbnail, title, titleDescription, activityColor, backgroundColor,
    150                     isLaunchTarget, isStackTask, isSystemApp, t.supportsSplitScreenMultiWindow,
    151                     t.taskDescription, t.resizeMode, t.topActivity, isLocked);
    152 
    153             allTasks.add(task);
    154         }
    155 
    156         // Initialize the stacks
    157         mStack = new TaskStack();
    158         mStack.setTasks(allTasks, false /* notifyStackChanges */);
    159     }
    160 
    161     /**
    162      * Called to apply the actual loading based on the specified conditions.
    163      *
    164      * Note: Do not lock, since this can be calling back to the loader, which separately also drives
    165      * this call (callers should synchronize on the loader before making this call).
    166      */
    167     public void executePlan(Options opts, RecentsTaskLoader loader) {
    168         Resources res = mContext.getResources();
    169 
    170         // Iterate through each of the tasks and load them according to the load conditions.
    171         ArrayList<Task> tasks = mStack.getTasks();
    172         int taskCount = tasks.size();
    173         for (int i = 0; i < taskCount; i++) {
    174             Task task = tasks.get(i);
    175             TaskKey taskKey = task.key;
    176 
    177             boolean isRunningTask = (task.key.id == opts.runningTaskId);
    178             boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
    179             boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
    180 
    181             // If requested, skip the running task
    182             if (opts.onlyLoadPausedActivities && isRunningTask) {
    183                 continue;
    184             }
    185 
    186             if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
    187                 if (task.icon == null) {
    188                     task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
    189                             true);
    190                 }
    191             }
    192             if (opts.loadThumbnails && isVisibleThumbnail) {
    193                 task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
    194                         true /* loadIfNotCached */, true /* storeInCache */);
    195             }
    196         }
    197     }
    198 
    199     /**
    200      * Returns the TaskStack from the preloaded list of recent tasks.
    201      */
    202     public TaskStack getTaskStack() {
    203         return mStack;
    204     }
    205 
    206     /** Returns whether there are any tasks in any stacks. */
    207     public boolean hasTasks() {
    208         if (mStack != null) {
    209             return mStack.getTaskCount() > 0;
    210         }
    211         return false;
    212     }
    213 }
    214