blob: 3b759c02c8ca38c6f2f0691f69ee71ec4a0cf382 [file] [log] [blame]
Winson Chunga10370f2014-04-02 12:25:04 -07001/*
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
Winson Chungffa2ec62014-07-03 15:54:42 -070017package com.android.systemui.recents.misc;
Winson Chunga10370f2014-04-02 12:25:04 -070018
Winson59924fe2016-03-17 14:13:18 -070019import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
20import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
21import static android.app.ActivityManager.StackId.HOME_STACK_ID;
22import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
23import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
24
Winson Chunga10370f2014-04-02 12:25:04 -070025import android.app.ActivityManager;
Winson Chung1f24c7e2014-07-11 17:06:48 -070026import android.app.ActivityManagerNative;
Winson Chunga10370f2014-04-02 12:25:04 -070027import android.app.ActivityOptions;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070028import android.app.AppGlobals;
Winson Chung1f24c7e2014-07-11 17:06:48 -070029import android.app.IActivityManager;
Winson Chung740c3ac2014-11-12 16:14:38 -080030import android.app.ITaskStackListener;
Winson Chunga10370f2014-04-02 12:25:04 -070031import android.content.ComponentName;
Jason Monk56e09b42014-07-18 10:29:14 -040032import android.content.ContentResolver;
Winson Chunga10370f2014-04-02 12:25:04 -070033import android.content.Context;
34import android.content.Intent;
35import android.content.pm.ActivityInfo;
Winsonc5ef63f2016-01-21 14:39:23 -080036import android.content.pm.ApplicationInfo;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070037import android.content.pm.IPackageManager;
Winson Chunga10370f2014-04-02 12:25:04 -070038import android.content.pm.PackageManager;
Winson Chungbf8871d2014-08-28 20:57:16 -070039import android.content.pm.ResolveInfo;
Winson59924fe2016-03-17 14:13:18 -070040import android.content.res.Configuration;
Winson Chung85cfec82014-07-14 14:16:04 -070041import android.content.res.Resources;
Winson Chunga10370f2014-04-02 12:25:04 -070042import android.graphics.Bitmap;
Winson Chungffa2ec62014-07-03 15:54:42 -070043import android.graphics.BitmapFactory;
Winson Chungb5ddfc32014-06-13 17:23:12 -070044import android.graphics.Canvas;
45import android.graphics.Color;
46import android.graphics.Paint;
Winson Chungdcfa7972014-07-22 12:27:13 -070047import android.graphics.Point;
Winson Chungb5ddfc32014-06-13 17:23:12 -070048import android.graphics.PorterDuff;
49import android.graphics.PorterDuffXfermode;
Winson Chungffa2ec62014-07-03 15:54:42 -070050import android.graphics.Rect;
Winson Chung296278a2015-12-17 12:09:02 -050051import android.graphics.drawable.BitmapDrawable;
Winson Chunga10370f2014-04-02 12:25:04 -070052import android.graphics.drawable.ColorDrawable;
53import android.graphics.drawable.Drawable;
Jaewan Kim938a50b2016-03-14 17:35:43 +090054import android.os.Handler;
Jorim Jaggic69bd222016-03-15 14:38:37 +010055import android.os.IRemoteCallback;
Jaewan Kim938a50b2016-03-14 17:35:43 +090056import android.os.Looper;
57import android.os.Message;
Winson Chungffa2ec62014-07-03 15:54:42 -070058import android.os.ParcelFileDescriptor;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070059import android.os.RemoteException;
Winson Chungd16c5652015-01-26 16:11:07 -080060import android.os.SystemProperties;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070061import android.os.UserHandle;
Winson190fe3bf2015-10-20 14:57:24 -070062import android.os.UserManager;
Jason Monk56e09b42014-07-18 10:29:14 -040063import android.provider.Settings;
Rubin Xuefb844d2015-12-08 20:57:24 +000064import android.util.ArraySet;
Winson Chungb5ddfc32014-06-13 17:23:12 -070065import android.util.Log;
Winson Chunge1e20e12015-06-02 14:11:49 -070066import android.util.MutableBoolean;
Winson Chungd42a6cf2014-06-03 16:24:04 -070067import android.view.Display;
Jorim Jaggic69bd222016-03-15 14:38:37 +010068import android.view.IAppTransitionAnimationSpecsFuture;
Jorim Jaggia6c934e2015-12-21 13:22:31 +010069import android.view.IDockedStackListener;
Winson Chungd42a6cf2014-06-03 16:24:04 -070070import android.view.WindowManager;
Clara Bayarri75e09792015-07-29 16:20:40 +010071import android.view.WindowManager.KeyboardShortcutsReceiver;
Winsonc28098f2015-10-30 14:50:19 -070072import android.view.WindowManagerGlobal;
Winson Chungee445952014-09-09 16:12:59 +020073import android.view.accessibility.AccessibilityManager;
Winsonc0d70582016-01-29 10:24:39 -080074
Jorim Jaggi165ce062015-07-06 16:18:11 -070075import com.android.internal.app.AssistUtils;
Winsonab84fc52015-10-23 11:52:07 -070076import com.android.internal.os.BackgroundThread;
Winson Chung4e96eb72014-09-17 15:16:09 +020077import com.android.systemui.R;
Winsonc742f972015-11-12 11:32:21 -080078import com.android.systemui.recents.RecentsDebugFlags;
Winson190fe3bf2015-10-20 14:57:24 -070079import com.android.systemui.recents.RecentsImpl;
Sid Soundararajan4bdb6872016-03-18 13:42:10 -070080import com.android.systemui.recents.tv.RecentsTvImpl;
Winson21700932016-03-24 17:26:23 -070081import com.android.systemui.recents.model.ThumbnailData;
Winson Chunga10370f2014-04-02 12:25:04 -070082
Winson Chungffa2ec62014-07-03 15:54:42 -070083import java.io.IOException;
Winson Chunga10370f2014-04-02 12:25:04 -070084import java.util.ArrayList;
Winson Chung918c0722014-05-08 15:04:23 -070085import java.util.Iterator;
Winson Chunga10370f2014-04-02 12:25:04 -070086import java.util.List;
Winson Chung5e3e5d82014-04-02 15:44:55 -070087import java.util.Random;
Winson Chunga10370f2014-04-02 12:25:04 -070088
89/**
90 * Acts as a shim around the real system services that we need to access data from, and provides
91 * a point of injection when testing UI.
92 */
93public class SystemServicesProxy {
Winson Chungb5ddfc32014-06-13 17:23:12 -070094 final static String TAG = "SystemServicesProxy";
95
Dianne Hackbornaec68bb2014-08-20 15:25:13 -070096 final static BitmapFactory.Options sBitmapOptions;
Winson Chungc35e6702015-07-30 18:08:26 -070097 static {
Winson Chungc35e6702015-07-30 18:08:26 -070098 sBitmapOptions = new BitmapFactory.Options();
99 sBitmapOptions.inMutable = true;
100 }
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700101
Jaewan Kim7ed76572016-03-17 18:15:07 +0900102 final static List<String> sRecentsBlacklist;
103 static {
104 sRecentsBlacklist = new ArrayList<>();
105 sRecentsBlacklist.add("com.android.systemui.tv.pip.PipOnboardingActivity");
106 sRecentsBlacklist.add("com.android.systemui.tv.pip.PipMenuActivity");
107 }
108
Jaewan Kim938a50b2016-03-14 17:35:43 +0900109 private static SystemServicesProxy sSystemServicesProxy;
110
Winson Chungee445952014-09-09 16:12:59 +0200111 AccessibilityManager mAccm;
Winson Chunga10370f2014-04-02 12:25:04 -0700112 ActivityManager mAm;
Winson Chung1f24c7e2014-07-11 17:06:48 -0700113 IActivityManager mIam;
Winson Chunga10370f2014-04-02 12:25:04 -0700114 PackageManager mPm;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700115 IPackageManager mIpm;
Jorim Jaggi165ce062015-07-06 16:18:11 -0700116 AssistUtils mAssistUtils;
Winson Chungd42a6cf2014-06-03 16:24:04 -0700117 WindowManager mWm;
Winson190fe3bf2015-10-20 14:57:24 -0700118 UserManager mUm;
Winson Chungd42a6cf2014-06-03 16:24:04 -0700119 Display mDisplay;
Winson Chung918c0722014-05-08 15:04:23 -0700120 String mRecentsPackage;
Winson Chungda5b84c2014-05-05 12:06:28 -0700121 ComponentName mAssistComponent;
Winson8be16342016-02-09 11:53:27 -0800122
123 boolean mIsSafeMode;
Winsoneca4ab62015-11-04 10:50:28 -0800124 boolean mHasFreeformWorkspaceSupport;
Winson Chunga10370f2014-04-02 12:25:04 -0700125
126 Bitmap mDummyIcon;
Winson Chung85cfec82014-07-14 14:16:04 -0700127 int mDummyThumbnailWidth;
128 int mDummyThumbnailHeight;
Winson Chungb5ddfc32014-06-13 17:23:12 -0700129 Paint mBgProtectionPaint;
130 Canvas mBgProtectionCanvas;
Winson Chunga10370f2014-04-02 12:25:04 -0700131
Jaewan Kim938a50b2016-03-14 17:35:43 +0900132 private final Handler mHandler = new H();
133
134 /**
135 * An abstract class to track task stack changes.
136 * Classes should implement this instead of {@link android.app.ITaskStackListener}
137 * to reduce IPC calls from system services. These callbacks will be called on the main thread.
138 */
139 public abstract static class TaskStackListener {
140 public void onTaskStackChanged() { }
141 public void onActivityPinned() { }
142 public void onPinnedActivityRestartAttempt() { }
143 public void onPinnedStackAnimationEnded() { }
Jorim Jaggi2adba072016-03-03 13:43:39 +0100144 public void onActivityForcedResizable(String packageName, int taskId) { }
Jaewan Kim938a50b2016-03-14 17:35:43 +0900145 }
146
147 /**
148 * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from
149 * ActivityManagerNative.
150 * This simply passes callbacks to listeners through {@link H}.
151 * */
152 private ITaskStackListener.Stub mTaskStackListener = new ITaskStackListener.Stub() {
153 @Override
154 public void onTaskStackChanged() throws RemoteException {
155 mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
156 mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
157 }
158
159 @Override
160 public void onActivityPinned() throws RemoteException {
161 mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
162 mHandler.sendEmptyMessage(H.ON_ACTIVITY_PINNED);
163 }
164
165 @Override
166 public void onPinnedActivityRestartAttempt() throws RemoteException{
167 mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
168 mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
169 }
170
171 @Override
172 public void onPinnedStackAnimationEnded() throws RemoteException {
173 mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
174 mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
175 }
Jorim Jaggi2adba072016-03-03 13:43:39 +0100176
177 @Override
178 public void onActivityForcedResizable(String packageName, int taskId)
179 throws RemoteException {
180 mHandler.obtainMessage(H.ON_ACTIVITY_FORCED_RESIZABLE, taskId, 0, packageName)
181 .sendToTarget();
182 }
Jaewan Kim938a50b2016-03-14 17:35:43 +0900183 };
184
185 /**
Jorim Jaggi2adba072016-03-03 13:43:39 +0100186 * List of {@link TaskStackListener} registered from {@link #registerTaskStackListener}.
Jaewan Kim938a50b2016-03-14 17:35:43 +0900187 */
188 private List<TaskStackListener> mTaskStackListeners = new ArrayList<>();
189
Winson Chunga10370f2014-04-02 12:25:04 -0700190 /** Private constructor */
Jaewan Kim938a50b2016-03-14 17:35:43 +0900191 private SystemServicesProxy(Context context) {
Winson Chungee445952014-09-09 16:12:59 +0200192 mAccm = AccessibilityManager.getInstance(context);
Winson Chunga10370f2014-04-02 12:25:04 -0700193 mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
Winson Chung1f24c7e2014-07-11 17:06:48 -0700194 mIam = ActivityManagerNative.getDefault();
Winson Chunga10370f2014-04-02 12:25:04 -0700195 mPm = context.getPackageManager();
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700196 mIpm = AppGlobals.getPackageManager();
Jorim Jaggi165ce062015-07-06 16:18:11 -0700197 mAssistUtils = new AssistUtils(context);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700198 mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Winson190fe3bf2015-10-20 14:57:24 -0700199 mUm = UserManager.get(context);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700200 mDisplay = mWm.getDefaultDisplay();
Winson Chung918c0722014-05-08 15:04:23 -0700201 mRecentsPackage = context.getPackageName();
Winson Chung48f2cda2015-12-11 13:20:12 -0500202 mHasFreeformWorkspaceSupport =
Jorim Jaggi6f2efd32015-12-23 12:04:39 +0100203 mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
204 Settings.Global.getInt(context.getContentResolver(),
205 DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
Winson8be16342016-02-09 11:53:27 -0800206 mIsSafeMode = mPm.isSafeMode();
Winson Chunga10370f2014-04-02 12:25:04 -0700207
Winson Chung85cfec82014-07-14 14:16:04 -0700208 // Get the dummy thumbnail width/heights
209 Resources res = context.getResources();
210 int wId = com.android.internal.R.dimen.thumbnail_width;
211 int hId = com.android.internal.R.dimen.thumbnail_height;
212 mDummyThumbnailWidth = res.getDimensionPixelSize(wId);
213 mDummyThumbnailHeight = res.getDimensionPixelSize(hId);
214
Winson Chungb5ddfc32014-06-13 17:23:12 -0700215 // Create the protection paints
216 mBgProtectionPaint = new Paint();
217 mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
218 mBgProtectionPaint.setColor(0xFFffffff);
219 mBgProtectionCanvas = new Canvas();
220
Winson Chungda5b84c2014-05-05 12:06:28 -0700221 // Resolve the assist intent
Jorim Jaggi165ce062015-07-06 16:18:11 -0700222 mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
Winson Chungda5b84c2014-05-05 12:06:28 -0700223
Winson6e6bd8772016-01-25 10:41:40 -0800224 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winson Chunga10370f2014-04-02 12:25:04 -0700225 // Create a dummy icon
Winson Chung2f2ca082014-04-03 18:05:29 -0700226 mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Winson Chung67369052014-04-07 17:35:48 -0700227 mDummyIcon.eraseColor(0xFF999999);
Winson Chunga10370f2014-04-02 12:25:04 -0700228 }
229 }
230
Jaewan Kim938a50b2016-03-14 17:35:43 +0900231 /**
232 * Returns the single instance of the {@link SystemServicesProxy}.
233 * This should only be called on the main thread.
234 */
235 public static SystemServicesProxy getInstance(Context context) {
236 if (!Looper.getMainLooper().isCurrentThread()) {
237 throw new RuntimeException("Must be called on the UI thread");
238 }
239 if (sSystemServicesProxy == null) {
240 sSystemServicesProxy = new SystemServicesProxy(context);
241 }
242 return sSystemServicesProxy;
243 }
244
Winson Chunga10370f2014-04-02 12:25:04 -0700245 /** Returns a list of the recents tasks */
Winson Chung9cb5c4e2014-09-29 13:16:05 -0700246 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
Rubin Xuefb844d2015-12-08 20:57:24 +0000247 boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) {
Winson Chunga10370f2014-04-02 12:25:04 -0700248 if (mAm == null) return null;
249
250 // If we are mocking, then create some recent tasks
Winson6e6bd8772016-01-25 10:41:40 -0800251 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winson Chunga10370f2014-04-02 12:25:04 -0700252 ArrayList<ActivityManager.RecentTaskInfo> tasks =
253 new ArrayList<ActivityManager.RecentTaskInfo>();
Winson6e6bd8772016-01-25 10:41:40 -0800254 int count = Math.min(numLatestTasks, RecentsDebugFlags.Static.MockTaskCount);
Winson Chunga10370f2014-04-02 12:25:04 -0700255 for (int i = 0; i < count; i++) {
256 // Create a dummy component name
Winson6e6bd8772016-01-25 10:41:40 -0800257 int packageIndex = i % RecentsDebugFlags.Static.MockTasksPackageCount;
Winson Chunga10370f2014-04-02 12:25:04 -0700258 ComponentName cn = new ComponentName("com.android.test" + packageIndex,
259 "com.android.test" + i + ".Activity");
Winson Chunga449dc02014-05-16 11:15:04 -0700260 String description = "" + i + " - " +
261 Long.toString(Math.abs(new Random().nextLong()), 36);
Winson Chunga10370f2014-04-02 12:25:04 -0700262 // Create the recent task info
263 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
Winson6e6bd8772016-01-25 10:41:40 -0800264 rti.id = rti.persistentId = rti.affiliatedTaskId = i;
Winson Chunga10370f2014-04-02 12:25:04 -0700265 rti.baseIntent = new Intent();
266 rti.baseIntent.setComponent(cn);
Winson Chunga449dc02014-05-16 11:15:04 -0700267 rti.description = description;
Winson Chungffa2ec62014-07-03 15:54:42 -0700268 rti.firstActiveTime = rti.lastActiveTime = i;
Winson Chung5e3e5d82014-04-02 15:44:55 -0700269 if (i % 2 == 0) {
Winson Chunga449dc02014-05-16 11:15:04 -0700270 rti.taskDescription = new ActivityManager.TaskDescription(description,
Winson Chung1af8eda2016-02-05 17:55:56 +0000271 Bitmap.createBitmap(mDummyIcon), null,
272 0xFF000000 | (0xFFFFFF & new Random().nextInt()),
Winson Chung10f81392014-05-20 16:21:31 -0700273 0xFF000000 | (0xFFFFFF & new Random().nextInt()));
Winson Chunga449dc02014-05-16 11:15:04 -0700274 } else {
275 rti.taskDescription = new ActivityManager.TaskDescription();
Winson Chung5e3e5d82014-04-02 15:44:55 -0700276 }
Winson Chunga10370f2014-04-02 12:25:04 -0700277 tasks.add(rti);
278 }
279 return tasks;
280 }
281
Winson Chung918c0722014-05-08 15:04:23 -0700282 // Remove home/recents/excluded tasks
283 int minNumTasksToQuery = 10;
284 int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
285 List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
Winson Chunga4ccb862014-08-22 15:26:27 -0700286 ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
Winson Chung0583d3d2015-12-18 10:03:12 -0500287 ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS |
288 ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
Winson Chunga10370f2014-04-02 12:25:04 -0700289 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
Winson Chung918c0722014-05-08 15:04:23 -0700290 ActivityManager.RECENT_INCLUDE_PROFILES |
291 ActivityManager.RECENT_WITH_EXCLUDED, userId);
Winson Chung4298b432014-09-12 15:25:46 +0200292
293 // Break early if we can't get a valid set of tasks
294 if (tasks == null) {
Winson Chunge1e20e12015-06-02 14:11:49 -0700295 return new ArrayList<>();
Winson Chung4298b432014-09-12 15:25:46 +0200296 }
297
Winson Chung918c0722014-05-08 15:04:23 -0700298 boolean isFirstValidTask = true;
299 Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
300 while (iter.hasNext()) {
301 ActivityManager.RecentTaskInfo t = iter.next();
302
303 // NOTE: The order of these checks happens in the expected order of the traversal of the
304 // tasks
305
Winson Chung918c0722014-05-08 15:04:23 -0700306 // Check the first non-recents task, include this task even if it is marked as excluded
Winson Chung9cb5c4e2014-09-29 13:16:05 -0700307 // from recents if we are currently in the app. In other words, only remove excluded
Jaewan Kim7ed76572016-03-17 18:15:07 +0900308 // tasks if it is not the first active task, and not in the blacklist.
Winson Chung918c0722014-05-08 15:04:23 -0700309 boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
310 == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
Jaewan Kim7ed76572016-03-17 18:15:07 +0900311 boolean isBlackListed = sRecentsBlacklist.contains(t.realActivity.getClassName());
Rubin Xuefb844d2015-12-08 20:57:24 +0000312 // Filter out recent tasks from managed profiles which are in quiet mode.
313 isExcluded |= quietProfileIds.contains(t.userId);
Jaewan Kim7ed76572016-03-17 18:15:07 +0900314 if (isBlackListed || (isExcluded && (isTopTaskHome || !isFirstValidTask))) {
Winson Chung918c0722014-05-08 15:04:23 -0700315 iter.remove();
316 continue;
317 }
318 isFirstValidTask = false;
Winson Chung918c0722014-05-08 15:04:23 -0700319 }
320
321 return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
Winson Chunga10370f2014-04-02 12:25:04 -0700322 }
323
324 /** Returns a list of the running tasks */
Winson Chung2cf8b222015-01-20 11:44:05 -0800325 private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
Winson Chunga10370f2014-04-02 12:25:04 -0700326 if (mAm == null) return null;
327 return mAm.getRunningTasks(numTasks);
328 }
329
Winson Chung2cf8b222015-01-20 11:44:05 -0800330 /** Returns the top task. */
331 public ActivityManager.RunningTaskInfo getTopMostTask() {
332 List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1);
Winson Chung65c29402015-05-27 12:45:20 -0700333 if (tasks != null && !tasks.isEmpty()) {
Winson Chung2cf8b222015-01-20 11:44:05 -0800334 return tasks.get(0);
335 }
336 return null;
337 }
338
Winsona5e6b362015-11-02 17:17:20 -0800339 /**
340 * Returns whether this device has freeform workspaces.
341 */
342 public boolean hasFreeformWorkspaceSupport() {
Winsoneca4ab62015-11-04 10:50:28 -0800343 return mHasFreeformWorkspaceSupport;
Winsona5e6b362015-11-02 17:17:20 -0800344 }
345
Winson8be16342016-02-09 11:53:27 -0800346 /**
347 * Returns whether this device is in the safe mode.
348 */
349 public boolean isInSafeMode() {
350 return mIsSafeMode;
351 }
352
Winson Chung2cf8b222015-01-20 11:44:05 -0800353 /** Returns whether the recents is currently running */
354 public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
Winson Chunge1e20e12015-06-02 14:11:49 -0700355 MutableBoolean isHomeTopMost) {
Winson Chung2cf8b222015-01-20 11:44:05 -0800356 if (topTask != null) {
357 ComponentName topActivity = topTask.topActivity;
358
359 // Check if the front most activity is recents
Sid Soundararajanb58c46a2016-01-26 15:39:27 -0800360 if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
361 (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
Sid Soundararajan4bdb6872016-03-18 13:42:10 -0700362 topActivity.getClassName().equals(RecentsTvImpl.RECENTS_TV_ACTIVITY)))) {
Winson Chung2cf8b222015-01-20 11:44:05 -0800363 if (isHomeTopMost != null) {
Winson Chunge1e20e12015-06-02 14:11:49 -0700364 isHomeTopMost.value = false;
Winson Chung2cf8b222015-01-20 11:44:05 -0800365 }
366 return true;
367 }
368
Winson5510f6c2015-10-27 12:11:26 -0700369 // Note, this is only valid because we currently only allow the recents and home
370 // activities in the home stack
Winson Chung2cf8b222015-01-20 11:44:05 -0800371 if (isHomeTopMost != null) {
Winson5510f6c2015-10-27 12:11:26 -0700372 isHomeTopMost.value = SystemServicesProxy.isHomeStack(topTask.stackId);
Winson Chung2cf8b222015-01-20 11:44:05 -0800373 }
374 }
375 return false;
376 }
377
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700378 /** Get the bounds of a task. */
379 public Rect getTaskBounds(int taskId) {
380 if (mIam == null) return null;
381
382 try {
383 return mIam.getTaskBounds(taskId);
384 } catch (RemoteException e) {
385 e.printStackTrace();
386 }
387 return null;
Winson Chungd16c5652015-01-26 16:11:07 -0800388 }
389
Winsonb1bbaed2015-09-23 15:45:11 -0700390 /**
391 * Resizes the given task to the new bounds.
392 */
393 public void resizeTask(int taskId, Rect bounds) {
394 if (mIam == null) return;
395
396 try {
397 mIam.resizeTask(taskId, bounds, ActivityManager.RESIZE_MODE_FORCED);
398 } catch (RemoteException e) {
399 e.printStackTrace();
400 }
401 }
402
Jorim Jaggi75b25972015-10-21 14:51:10 +0200403 /** Docks a task to the side of the screen and starts it. */
Jorim Jaggic69bd222016-03-15 14:38:37 +0100404 public void startTaskInDockedMode(int taskId, int createMode) {
Winsonb1bbaed2015-09-23 15:45:11 -0700405 if (mIam == null) return;
406
407 try {
Winson3e874742016-01-07 10:08:17 -0800408 // TODO: Determine what animation we want for the incoming task
Jorim Jaggic69bd222016-03-15 14:38:37 +0100409 final ActivityOptions options = ActivityOptions.makeBasic();
Filip Gruszczynski90186c62015-10-26 14:07:00 -0700410 options.setDockCreateMode(createMode);
Wale Ogunwale854809c2015-12-27 16:18:19 -0800411 options.setLaunchStackId(DOCKED_STACK_ID);
412 mIam.startActivityFromRecents(taskId, options.toBundle());
Jorim Jaggi75b25972015-10-21 14:51:10 +0200413 } catch (RemoteException e) {
414 e.printStackTrace();
415 }
416 }
417
Jorim Jaggi030979c2015-11-20 15:14:43 -0800418 /** Docks an already resumed task to the side of the screen. */
Chong Zhange4fbd322016-03-01 14:44:03 -0800419 public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
420 if (mIam == null) {
421 return false;
422 }
Jorim Jaggi030979c2015-11-20 15:14:43 -0800423
424 try {
Chong Zhange4fbd322016-03-01 14:44:03 -0800425 return mIam.moveTaskToDockedStack(
426 taskId, createMode, true /* onTop */, false /* animate */, initialBounds);
Jorim Jaggi030979c2015-11-20 15:14:43 -0800427 } catch (RemoteException e) {
428 e.printStackTrace();
429 }
Chong Zhange4fbd322016-03-01 14:44:03 -0800430 return false;
Jorim Jaggi030979c2015-11-20 15:14:43 -0800431 }
432
Winson Chungd16c5652015-01-26 16:11:07 -0800433 /** Returns the focused stack id. */
434 public int getFocusedStack() {
435 if (mIam == null) return -1;
436
437 try {
438 return mIam.getFocusedStackId();
439 } catch (RemoteException e) {
440 e.printStackTrace();
441 return -1;
442 }
443 }
444
Winson5510f6c2015-10-27 12:11:26 -0700445 /**
446 * Returns whether the given stack id is the home stack id.
447 */
448 public static boolean isHomeStack(int stackId) {
Wale Ogunwale3797c222015-10-27 14:21:58 -0700449 return stackId == HOME_STACK_ID;
Winson5510f6c2015-10-27 12:11:26 -0700450 }
Winson Chunga10370f2014-04-02 12:25:04 -0700451
Winson5510f6c2015-10-27 12:11:26 -0700452 /**
Sid Soundararajanb58c46a2016-01-26 15:39:27 -0800453 * Returns whether the given stack id is the pinned stack id.
454 */
455 public static boolean isPinnedStack(int stackId){
456 return stackId == PINNED_STACK_ID;
457 }
458
459 /**
Winson8f0e3a62015-11-23 09:15:08 -0800460 * Returns whether the given stack id is the docked stack id.
461 */
462 public static boolean isDockedStack(int stackId) {
463 return stackId == DOCKED_STACK_ID;
464 }
465
466 /**
Winson5510f6c2015-10-27 12:11:26 -0700467 * Returns whether the given stack id is the freeform workspace stack id.
468 */
469 public static boolean isFreeformStack(int stackId) {
Wale Ogunwale3797c222015-10-27 14:21:58 -0700470 return stackId == FREEFORM_WORKSPACE_STACK_ID;
Winson Chunga10370f2014-04-02 12:25:04 -0700471 }
472
Winsonbe7607a2015-10-01 17:24:51 -0700473 /**
Winsonf3918002016-01-12 15:59:29 -0800474 * @return whether there are any docked tasks for the current user.
Winsonbe7607a2015-10-01 17:24:51 -0700475 */
476 public boolean hasDockedTask() {
477 if (mIam == null) return false;
478
479 ActivityManager.StackInfo stackInfo = null;
480 try {
Wale Ogunwale7e8184b2015-10-05 14:37:03 -0700481 stackInfo = mIam.getStackInfo(DOCKED_STACK_ID);
Winsonbe7607a2015-10-01 17:24:51 -0700482 } catch (RemoteException e) {
483 e.printStackTrace();
484 }
Winsondcf48262016-01-25 17:16:58 -0800485
486 if (stackInfo != null) {
487 int userId = getCurrentUser();
488 boolean hasUserTask = false;
489 for (int i = stackInfo.taskUserIds.length - 1; i >= 0 && !hasUserTask; i--) {
490 hasUserTask = (stackInfo.taskUserIds[i] == userId);
491 }
492 return hasUserTask;
493 }
494 return false;
Winsonbe7607a2015-10-01 17:24:51 -0700495 }
496
Winsonc28098f2015-10-30 14:50:19 -0700497 /**
498 * Cancels the current window transtion to/from Recents for the given task id.
499 */
500 public void cancelWindowTransition(int taskId) {
501 if (mWm == null) return;
502
503 try {
504 WindowManagerGlobal.getWindowManagerService().cancelTaskWindowTransition(taskId);
505 } catch (RemoteException e) {
506 e.printStackTrace();
507 }
508 }
509
Winson13d30662015-11-06 15:30:29 -0800510 /**
511 * Cancels the current thumbnail transtion to/from Recents for the given task id.
512 */
513 public void cancelThumbnailTransition(int taskId) {
514 if (mWm == null) return;
515
516 try {
517 WindowManagerGlobal.getWindowManagerService().cancelTaskThumbnailTransition(taskId);
518 } catch (RemoteException e) {
519 e.printStackTrace();
520 }
521 }
522
Winson Chunga10370f2014-04-02 12:25:04 -0700523 /** Returns the top task thumbnail for the given task id */
Winson21700932016-03-24 17:26:23 -0700524 public ThumbnailData getTaskThumbnail(int taskId) {
Winson Chunga10370f2014-04-02 12:25:04 -0700525 if (mAm == null) return null;
Winson21700932016-03-24 17:26:23 -0700526 ThumbnailData thumbnailData = new ThumbnailData();
Winson Chunga10370f2014-04-02 12:25:04 -0700527
528 // If we are mocking, then just return a dummy thumbnail
Winson6e6bd8772016-01-25 10:41:40 -0800529 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winson21700932016-03-24 17:26:23 -0700530 thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
531 mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
532 thumbnailData.thumbnail.eraseColor(0xff333333);
533 return thumbnailData;
Winson Chunga10370f2014-04-02 12:25:04 -0700534 }
535
Winson21700932016-03-24 17:26:23 -0700536 getThumbnail(taskId, thumbnailData);
537 if (thumbnailData.thumbnail != null) {
538 thumbnailData.thumbnail.setHasAlpha(false);
Winson Chungb5ddfc32014-06-13 17:23:12 -0700539 // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
540 // left pixel, then assume the whole thumbnail is transparent. Generally, proper
541 // screenshots are always composed onto a bitmap that has no alpha.
Winson21700932016-03-24 17:26:23 -0700542 if (Color.alpha(thumbnailData.thumbnail.getPixel(0, 0)) == 0) {
543 mBgProtectionCanvas.setBitmap(thumbnailData.thumbnail);
544 mBgProtectionCanvas.drawRect(0, 0, thumbnailData.thumbnail.getWidth(),
545 thumbnailData.thumbnail.getHeight(), mBgProtectionPaint);
Winson Chungb5ddfc32014-06-13 17:23:12 -0700546 mBgProtectionCanvas.setBitmap(null);
547 Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
548 }
549 }
Winson21700932016-03-24 17:26:23 -0700550 return thumbnailData;
Winson Chunga10370f2014-04-02 12:25:04 -0700551 }
552
Winson Chungffa2ec62014-07-03 15:54:42 -0700553 /**
554 * Returns a task thumbnail from the activity manager
555 */
Winson21700932016-03-24 17:26:23 -0700556 public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {
Winson479f7442015-11-25 15:16:27 -0800557 if (mAm == null) {
Winson21700932016-03-24 17:26:23 -0700558 return;
Winson479f7442015-11-25 15:16:27 -0800559 }
560
561 ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
Winson21700932016-03-24 17:26:23 -0700562 if (taskThumbnail == null) {
563 return;
564 }
Winson Chung85cfec82014-07-14 14:16:04 -0700565
Winson Chungffa2ec62014-07-03 15:54:42 -0700566 Bitmap thumbnail = taskThumbnail.mainThumbnail;
567 ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
568 if (thumbnail == null && descriptor != null) {
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700569 thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
570 null, sBitmapOptions);
Winson Chungffa2ec62014-07-03 15:54:42 -0700571 }
572 if (descriptor != null) {
573 try {
574 descriptor.close();
575 } catch (IOException e) {
576 }
577 }
Winson21700932016-03-24 17:26:23 -0700578 thumbnailDataOut.thumbnail = thumbnail;
579 thumbnailDataOut.thumbnailInfo = taskThumbnail.thumbnailInfo;
Winson Chungffa2ec62014-07-03 15:54:42 -0700580 }
581
Winsoneca4ab62015-11-04 10:50:28 -0800582 /**
583 * Moves a task into another stack.
584 */
585 public void moveTaskToStack(int taskId, int stackId) {
586 if (mIam == null) return;
587
588 try {
589 mIam.positionTaskInStack(taskId, stackId, 0);
Winson7db704a2016-01-07 13:13:52 -0800590 } catch (RemoteException | IllegalArgumentException e) {
Winsoneca4ab62015-11-04 10:50:28 -0800591 e.printStackTrace();
592 }
593 }
594
Winson Chungd16c5652015-01-26 16:11:07 -0800595 /** Moves a task to the front with the specified activity options. */
Winson Chunga10370f2014-04-02 12:25:04 -0700596 public void moveTaskToFront(int taskId, ActivityOptions opts) {
597 if (mAm == null) return;
Winson6e6bd8772016-01-25 10:41:40 -0800598 if (RecentsDebugFlags.Static.EnableMockTasks) return;
Winson Chunga10370f2014-04-02 12:25:04 -0700599
600 if (opts != null) {
601 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
602 opts.toBundle());
603 } else {
604 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME);
605 }
606 }
607
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700608 /** Removes the task */
Winson Chungc35e6702015-07-30 18:08:26 -0700609 public void removeTask(final int taskId) {
Winson Chunga10370f2014-04-02 12:25:04 -0700610 if (mAm == null) return;
Winson6e6bd8772016-01-25 10:41:40 -0800611 if (RecentsDebugFlags.Static.EnableMockTasks) return;
Winson Chunga10370f2014-04-02 12:25:04 -0700612
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700613 // Remove the task.
Winsonab84fc52015-10-23 11:52:07 -0700614 BackgroundThread.getHandler().post(new Runnable() {
Winson Chungc35e6702015-07-30 18:08:26 -0700615 @Override
616 public void run() {
617 mAm.removeTask(taskId);
618 }
619 });
Winson Chunga10370f2014-04-02 12:25:04 -0700620 }
621
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700622 /**
Winsond8b1d632016-01-04 17:51:18 -0800623 * Sends a message to close other system windows.
624 */
625 public void sendCloseSystemWindows(String reason) {
626 if (ActivityManagerNative.isSystemReady()) {
627 try {
Winsone6309aa2016-01-08 11:19:21 -0800628 mIam.closeSystemDialogs(reason);
Winsond8b1d632016-01-04 17:51:18 -0800629 } catch (RemoteException e) {
630 }
631 }
632 }
633
634 /**
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700635 * Returns the activity info for a given component name.
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700636 *
Winson Chungf7bca432014-04-30 17:11:13 -0700637 * @param cn The component name of the activity.
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700638 * @param userId The userId of the user that this is for.
639 */
640 public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
641 if (mIpm == null) return null;
Winson6e6bd8772016-01-25 10:41:40 -0800642 if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
Winson Chunga10370f2014-04-02 12:25:04 -0700643
644 try {
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700645 return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
646 } catch (RemoteException e) {
Winson Chunga10370f2014-04-02 12:25:04 -0700647 e.printStackTrace();
648 return null;
649 }
650 }
651
Winson Chungf7bca432014-04-30 17:11:13 -0700652 /**
653 * Returns the activity info for a given component name.
654 *
655 * @param cn The component name of the activity.
656 */
657 public ActivityInfo getActivityInfo(ComponentName cn) {
658 if (mPm == null) return null;
Winson6e6bd8772016-01-25 10:41:40 -0800659 if (RecentsDebugFlags.Static.EnableMockTasks) return new ActivityInfo();
Winson Chungf7bca432014-04-30 17:11:13 -0700660
661 try {
662 return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
663 } catch (PackageManager.NameNotFoundException e) {
664 e.printStackTrace();
665 return null;
666 }
667 }
668
Winsonc5ef63f2016-01-21 14:39:23 -0800669 /**
670 * Returns the activity label, badging if necessary.
671 */
672 public String getBadgedActivityLabel(ActivityInfo info, int userId) {
Winson Chunga10370f2014-04-02 12:25:04 -0700673 if (mPm == null) return null;
674
675 // If we are mocking, then return a mock label
Winson6e6bd8772016-01-25 10:41:40 -0800676 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winsonc5ef63f2016-01-21 14:39:23 -0800677 return "Recent Task: " + userId;
Winson Chunga10370f2014-04-02 12:25:04 -0700678 }
679
Winsonc5ef63f2016-01-21 14:39:23 -0800680 return getBadgedLabel(info.loadLabel(mPm).toString(), userId);
Winson Chunga10370f2014-04-02 12:25:04 -0700681 }
682
Winsonc5ef63f2016-01-21 14:39:23 -0800683 /**
684 * Returns the application label, badging if necessary.
685 */
686 public String getBadgedApplicationLabel(ApplicationInfo appInfo, int userId) {
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100687 if (mPm == null) return null;
688
689 // If we are mocking, then return a mock label
Winson6e6bd8772016-01-25 10:41:40 -0800690 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winsonc5ef63f2016-01-21 14:39:23 -0800691 return "Recent Task App: " + userId;
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100692 }
693
Winsonc5ef63f2016-01-21 14:39:23 -0800694 return getBadgedLabel(appInfo.loadLabel(mPm).toString(), userId);
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100695 }
696
Winsonc5ef63f2016-01-21 14:39:23 -0800697 /**
698 * Returns the content description for a given task, badging it if necessary. The content
699 * description joins the app and activity labels.
700 */
701 public String getBadgedContentDescription(ActivityInfo info, int userId, Resources res) {
Winson6e6bd8772016-01-25 10:41:40 -0800702 // If we are mocking, then return a mock label
703 if (RecentsDebugFlags.Static.EnableMockTasks) {
704 return "Recent Task Content Description: " + userId;
705 }
706
Winsonc5ef63f2016-01-21 14:39:23 -0800707 String activityLabel = info.loadLabel(mPm).toString();
708 String applicationLabel = info.applicationInfo.loadLabel(mPm).toString();
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100709 String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
710 return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
711 : res.getString(R.string.accessibility_recents_task_header,
712 badgedApplicationLabel, activityLabel);
713 }
714
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700715 /**
716 * Returns the activity icon for the ActivityInfo for a user, badging if
717 * necessary.
718 */
Winson Chung296278a2015-12-17 12:09:02 -0500719 public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
Svetoslavc7d62f02014-09-04 15:39:54 -0700720 if (mPm == null) return null;
Winson Chunga10370f2014-04-02 12:25:04 -0700721
722 // If we are mocking, then return a mock label
Winson6e6bd8772016-01-25 10:41:40 -0800723 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winson Chung2f2ca082014-04-03 18:05:29 -0700724 return new ColorDrawable(0xFF666666);
Winson Chunga10370f2014-04-02 12:25:04 -0700725 }
726
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700727 Drawable icon = info.loadIcon(mPm);
Robin Lee6507f2e2014-06-26 14:13:17 +0100728 return getBadgedIcon(icon, userId);
729 }
730
731 /**
Winsonc5ef63f2016-01-21 14:39:23 -0800732 * Returns the application icon for the ApplicationInfo for a user, badging if
733 * necessary.
734 */
735 public Drawable getBadgedApplicationIcon(ApplicationInfo appInfo, int userId) {
736 if (mPm == null) return null;
737
738 // If we are mocking, then return a mock label
Winson6e6bd8772016-01-25 10:41:40 -0800739 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winsonc5ef63f2016-01-21 14:39:23 -0800740 return new ColorDrawable(0xFF666666);
741 }
742
743 Drawable icon = appInfo.loadIcon(mPm);
744 return getBadgedIcon(icon, userId);
745 }
746
747 /**
Winson Chung296278a2015-12-17 12:09:02 -0500748 * Returns the task description icon, loading and badging it if it necessary.
749 */
750 public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription,
751 int userId, Resources res) {
752
753 // If we are mocking, then return a mock label
Winson6e6bd8772016-01-25 10:41:40 -0800754 if (RecentsDebugFlags.Static.EnableMockTasks) {
Winson Chung296278a2015-12-17 12:09:02 -0500755 return new ColorDrawable(0xFF666666);
756 }
757
758 Bitmap tdIcon = taskDescription.getInMemoryIcon();
759 if (tdIcon == null) {
760 tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
761 taskDescription.getIconFilename(), userId);
762 }
763 if (tdIcon != null) {
764 return getBadgedIcon(new BitmapDrawable(res, tdIcon), userId);
765 }
766 return null;
767 }
768
769 /**
Robin Lee6507f2e2014-06-26 14:13:17 +0100770 * Returns the given icon for a user, badging if necessary.
771 */
Winson Chung296278a2015-12-17 12:09:02 -0500772 private Drawable getBadgedIcon(Drawable icon, int userId) {
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700773 if (userId != UserHandle.myUserId()) {
Amith Yamasanifdf169c2014-09-07 15:45:57 -0700774 icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700775 }
776 return icon;
Winson Chunga10370f2014-04-02 12:25:04 -0700777 }
Winson Chungecd9b302014-04-16 17:07:18 -0700778
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100779 /**
Sid Soundararajan1008cc22016-02-01 11:11:14 -0800780 * Returns a banner used on TV for the specified Activity.
781 */
782 public Drawable getActivityBanner(ActivityInfo info) {
783 if (mPm == null) return null;
784
785 // If we are mocking, then return a mock banner
786 if (RecentsDebugFlags.Static.EnableMockTasks) {
787 return new ColorDrawable(0xFF666666);
788 }
789
790 Drawable banner = info.loadBanner(mPm);
791 return banner;
792 }
793
794 /**
795 * Returns a logo used on TV for the specified Activity.
796 */
797 public Drawable getActivityLogo(ActivityInfo info) {
798 if (mPm == null) return null;
799
800 // If we are mocking, then return a mock logo
801 if (RecentsDebugFlags.Static.EnableMockTasks) {
802 return new ColorDrawable(0xFF666666);
803 }
804
805 Drawable logo = info.loadLogo(mPm);
806 return logo;
807 }
808
809
810 /**
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100811 * Returns the given label for a user, badging if necessary.
812 */
Winson Chung296278a2015-12-17 12:09:02 -0500813 private String getBadgedLabel(String label, int userId) {
Benjamin Franzb7a42fd2015-04-23 15:33:32 +0100814 if (userId != UserHandle.myUserId()) {
815 label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
816 }
817 return label;
818 }
819
Winson Chungbf8871d2014-08-28 20:57:16 -0700820 /** Returns the package name of the home activity. */
821 public String getHomeActivityPackageName() {
822 if (mPm == null) return null;
Winson6e6bd8772016-01-25 10:41:40 -0800823 if (RecentsDebugFlags.Static.EnableMockTasks) return null;
Winson Chungbf8871d2014-08-28 20:57:16 -0700824
Winsond8b1d632016-01-04 17:51:18 -0800825 ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
Winson Chungbf8871d2014-08-28 20:57:16 -0700826 ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
827 if (defaultHomeActivity != null) {
828 return defaultHomeActivity.getPackageName();
829 } else if (homeActivities.size() == 1) {
830 ResolveInfo info = homeActivities.get(0);
831 if (info.activityInfo != null) {
832 return info.activityInfo.packageName;
833 }
834 }
835 return null;
836 }
837
838 /**
Winson190fe3bf2015-10-20 14:57:24 -0700839 * Returns whether the provided {@param userId} represents the system user.
Winson Chung2002cf52014-12-08 17:26:44 -0800840 */
Winson190fe3bf2015-10-20 14:57:24 -0700841 public boolean isSystemUser(int userId) {
842 return userId == UserHandle.USER_SYSTEM;
843 }
Winson Chung2002cf52014-12-08 17:26:44 -0800844
Winson190fe3bf2015-10-20 14:57:24 -0700845 /**
846 * Returns the current user id.
847 */
848 public int getCurrentUser() {
849 if (mAm == null) return 0;
850
851 return mAm.getCurrentUser();
852 }
853
854 /**
855 * Returns the processes user id.
856 */
857 public int getProcessUser() {
858 if (mUm == null) return 0;
859 return mUm.getUserHandle();
Winson Chung2002cf52014-12-08 17:26:44 -0800860 }
861
862 /**
Winson Chungee445952014-09-09 16:12:59 +0200863 * Returns whether touch exploration is currently enabled.
864 */
865 public boolean isTouchExplorationEnabled() {
866 if (mAccm == null) return false;
867
868 return mAccm.isEnabled() && mAccm.isTouchExplorationEnabled();
869 }
870
871 /**
Winsone6309aa2016-01-08 11:19:21 -0800872 * Returns whether the current task is in screen-pinning mode.
873 */
874 public boolean isScreenPinningActive() {
875 if (mIam == null) return false;
876
877 try {
878 return mIam.isInLockTaskMode();
879 } catch (RemoteException e) {
880 return false;
881 }
882 }
883
884 /**
Jason Monk56e09b42014-07-18 10:29:14 -0400885 * Returns a global setting.
886 */
887 public int getGlobalSetting(Context context, String setting) {
888 ContentResolver cr = context.getContentResolver();
889 return Settings.Global.getInt(cr, setting, 0);
890 }
891
892 /**
893 * Returns a system setting.
894 */
895 public int getSystemSetting(Context context, String setting) {
896 ContentResolver cr = context.getContentResolver();
897 return Settings.System.getInt(cr, setting, 0);
898 }
899
900 /**
Winson Chungd16c5652015-01-26 16:11:07 -0800901 * Returns a system property.
902 */
903 public String getSystemProperty(String key) {
904 return SystemProperties.get(key);
905 }
906
907 /**
Winson35f30502015-09-28 11:24:36 -0700908 * Returns the smallest width/height.
909 */
910 public int getDeviceSmallestWidth() {
Winson59924fe2016-03-17 14:13:18 -0700911 if (mDisplay == null) return 0;
Winson35f30502015-09-28 11:24:36 -0700912
913 Point smallestSizeRange = new Point();
914 Point largestSizeRange = new Point();
Winson59924fe2016-03-17 14:13:18 -0700915 mDisplay.getCurrentSizeRange(smallestSizeRange, largestSizeRange);
Winson35f30502015-09-28 11:24:36 -0700916 return smallestSizeRange.x;
917 }
918
919 /**
Winson59924fe2016-03-17 14:13:18 -0700920 * Returns the current display rect in the current display orientation.
Winsonb1bbaed2015-09-23 15:45:11 -0700921 */
922 public Rect getDisplayRect() {
923 Rect displayRect = new Rect();
Winson59924fe2016-03-17 14:13:18 -0700924 if (mDisplay == null) return displayRect;
Winsonb1bbaed2015-09-23 15:45:11 -0700925
926 Point p = new Point();
Winson59924fe2016-03-17 14:13:18 -0700927 mDisplay.getRealSize(p);
Winsonb1bbaed2015-09-23 15:45:11 -0700928 displayRect.set(0, 0, p.x, p.y);
929 return displayRect;
930 }
931
932 /**
Winson59924fe2016-03-17 14:13:18 -0700933 * Returns the current display orientation.
934 */
935 public int getDisplayOrientation() {
936 // Because of multi-window, the configuration orientation does not necessarily reflect the
937 // orientation of the display, instead we just use the display's real-size.
938 Rect displayRect = getDisplayRect();
939 return displayRect.width() > displayRect.height()
940 ? Configuration.ORIENTATION_LANDSCAPE
941 : Configuration.ORIENTATION_PORTRAIT;
942 }
943
944 /**
Winson35f30502015-09-28 11:24:36 -0700945 * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
Winson Chungffa2ec62014-07-03 15:54:42 -0700946 */
947 public Rect getWindowRect() {
948 Rect windowRect = new Rect();
Winson147ecaf2015-09-16 16:49:55 -0700949 if (mIam == null) return windowRect;
Winson Chungffa2ec62014-07-03 15:54:42 -0700950
Winson147ecaf2015-09-16 16:49:55 -0700951 try {
952 // Use the home stack bounds
Wale Ogunwale3797c222015-10-27 14:21:58 -0700953 ActivityManager.StackInfo stackInfo = mIam.getStackInfo(HOME_STACK_ID);
Winson147ecaf2015-09-16 16:49:55 -0700954 if (stackInfo != null) {
955 windowRect.set(stackInfo.bounds);
956 }
957 } catch (RemoteException e) {
958 e.printStackTrace();
959 } finally {
960 return windowRect;
961 }
Winson Chungffa2ec62014-07-03 15:54:42 -0700962 }
963
Winson Chung4e96eb72014-09-17 15:16:09 +0200964 /** Starts an activity from recents. */
965 public boolean startActivityFromRecents(Context context, int taskId, String taskName,
966 ActivityOptions options) {
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700967 if (mIam != null) {
968 try {
Wale Ogunwale854809c2015-12-27 16:18:19 -0800969 mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
Winson Chung4e96eb72014-09-17 15:16:09 +0200970 return true;
971 } catch (Exception e) {
Winson1b585612015-11-06 09:16:26 -0800972 Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700973 }
974 }
Winson Chung4e96eb72014-09-17 15:16:09 +0200975 return false;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700976 }
Winson Chung044d5292014-11-06 11:05:19 -0800977
978 /** Starts an in-place animation on the front most application windows. */
979 public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) {
980 if (mIam == null) return;
981
982 try {
983 mIam.startInPlaceAnimationOnFrontMostApplication(opts);
984 } catch (Exception e) {
985 e.printStackTrace();
986 }
987 }
Winson Chung740c3ac2014-11-12 16:14:38 -0800988
Jaewan Kim938a50b2016-03-14 17:35:43 +0900989 /**
990 * Registers a task stack listener with the system.
991 * This should be called on the main thread.
992 */
993 public void registerTaskStackListener(TaskStackListener listener) {
Winson Chung740c3ac2014-11-12 16:14:38 -0800994 if (mIam == null) return;
995
Jaewan Kim938a50b2016-03-14 17:35:43 +0900996 mTaskStackListeners.add(listener);
997 if (mTaskStackListeners.size() == 1) {
998 // Register mTaskStackListener to IActivityManager only once if needed.
999 try {
1000 mIam.registerTaskStackListener(mTaskStackListener);
1001 } catch (Exception e) {
1002 Log.w(TAG, "Failed to call registerTaskStackListener", e);
1003 }
Winson Chung740c3ac2014-11-12 16:14:38 -08001004 }
1005 }
Filip Gruszczynski14b4e572015-11-03 15:53:55 -08001006
1007 public void endProlongedAnimations() {
1008 if (mWm == null) {
1009 return;
1010 }
1011 try {
1012 WindowManagerGlobal.getWindowManagerService().endProlongedAnimations();
1013 } catch (Exception e) {
1014 e.printStackTrace();
1015 }
1016 }
Filip Gruszczynski64cdc142015-11-29 21:10:07 -08001017
Jorim Jaggia6c934e2015-12-21 13:22:31 +01001018 public void registerDockedStackListener(IDockedStackListener listener) {
Filip Gruszczynski64cdc142015-11-29 21:10:07 -08001019 if (mWm == null) return;
1020
1021 try {
Jorim Jaggia6c934e2015-12-21 13:22:31 +01001022 WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
Filip Gruszczynski64cdc142015-11-29 21:10:07 -08001023 } catch (Exception e) {
1024 e.printStackTrace();
1025 }
1026 }
Clara Bayarri75e09792015-07-29 16:20:40 +01001027
Winson3e874742016-01-07 10:08:17 -08001028 /**
1029 * Calculates the size of the dock divider in the current orientation.
1030 */
1031 public int getDockedDividerSize(Context context) {
1032 Resources res = context.getResources();
1033 int dividerWindowWidth = res.getDimensionPixelSize(
1034 com.android.internal.R.dimen.docked_stack_divider_thickness);
1035 int dividerInsets = res.getDimensionPixelSize(
1036 com.android.internal.R.dimen.docked_stack_divider_insets);
1037 return dividerWindowWidth - 2 * dividerInsets;
1038 }
1039
Clara Bayarrifcd7e802016-03-10 12:58:18 +00001040 public void requestKeyboardShortcuts(
1041 Context context, KeyboardShortcutsReceiver receiver, int deviceId) {
1042 mWm.requestAppKeyboardShortcuts(receiver, deviceId);
Clara Bayarri75e09792015-07-29 16:20:40 +01001043 }
Sid Soundararajanb58c46a2016-01-26 15:39:27 -08001044
Jorim Jaggic6c89a82016-01-28 17:48:21 -08001045 public void getStableInsets(Rect outStableInsets) {
1046 if (mWm == null) return;
1047
1048 try {
1049 WindowManagerGlobal.getWindowManagerService().getStableInsets(outStableInsets);
1050 } catch (Exception e) {
1051 e.printStackTrace();
1052 }
1053 }
Jaewan Kim938a50b2016-03-14 17:35:43 +09001054
Jorim Jaggic69bd222016-03-15 14:38:37 +01001055 public void overridePendingAppTransitionMultiThumbFuture(
1056 IAppTransitionAnimationSpecsFuture future, IRemoteCallback animStartedListener,
1057 boolean scaleUp) {
1058 try {
1059 WindowManagerGlobal.getWindowManagerService()
1060 .overridePendingAppTransitionMultiThumbFuture(future, animStartedListener,
1061 scaleUp);
1062 } catch (RemoteException e) {
1063 Log.w(TAG, "Failed to override transition: " + e);
1064 }
1065 }
1066
Winsona1ededd2016-03-25 12:23:12 -07001067 /**
1068 * Returns whether the device has a transposed nav bar (on the right of the screen) in the
1069 * current display orientation.
1070 */
1071 public boolean hasTransposedNavBar() {
1072 Rect insets = new Rect();
1073 getStableInsets(insets);
1074 return insets.right > 0;
1075 }
1076
Jaewan Kim938a50b2016-03-14 17:35:43 +09001077 private final class H extends Handler {
1078 private static final int ON_TASK_STACK_CHANGED = 1;
1079 private static final int ON_ACTIVITY_PINNED = 2;
1080 private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
1081 private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
Jorim Jaggi2adba072016-03-03 13:43:39 +01001082 private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
Jaewan Kim938a50b2016-03-14 17:35:43 +09001083
1084 @Override
1085 public void handleMessage(Message msg) {
1086 switch (msg.what) {
1087 case ON_TASK_STACK_CHANGED: {
1088 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
1089 mTaskStackListeners.get(i).onTaskStackChanged();
1090 }
1091 break;
1092 }
1093 case ON_ACTIVITY_PINNED: {
1094 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
1095 mTaskStackListeners.get(i).onActivityPinned();
1096 }
1097 break;
1098 }
1099 case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
1100 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
1101 mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
1102 }
1103 break;
1104 }
1105 case ON_PINNED_STACK_ANIMATION_ENDED: {
1106 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
1107 mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
1108 }
1109 break;
1110 }
Jorim Jaggi2adba072016-03-03 13:43:39 +01001111 case ON_ACTIVITY_FORCED_RESIZABLE: {
1112 for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
1113 mTaskStackListeners.get(i).onActivityForcedResizable(
1114 (String) msg.obj, msg.arg1);
1115 }
1116 break;
1117 }
Jaewan Kim938a50b2016-03-14 17:35:43 +09001118 }
1119 }
1120 }
Winson Chunga10370f2014-04-02 12:25:04 -07001121}