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