blob: 72040fe4f9f45b41327f1337ad63bf23118551fa [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
19import android.app.ActivityManager;
Winson Chung1f24c7e2014-07-11 17:06:48 -070020import android.app.ActivityManagerNative;
Winson Chunga10370f2014-04-02 12:25:04 -070021import android.app.ActivityOptions;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070022import android.app.AppGlobals;
Winson Chungd16c5652015-01-26 16:11:07 -080023import android.app.IActivityContainer;
Winson Chung1f24c7e2014-07-11 17:06:48 -070024import android.app.IActivityManager;
Winson Chung740c3ac2014-11-12 16:14:38 -080025import android.app.ITaskStackListener;
Winson Chungecd9b302014-04-16 17:07:18 -070026import android.app.SearchManager;
Winson Chungf7bca432014-04-30 17:11:13 -070027import android.appwidget.AppWidgetHost;
28import android.appwidget.AppWidgetManager;
29import android.appwidget.AppWidgetProviderInfo;
Winson Chunga10370f2014-04-02 12:25:04 -070030import android.content.ComponentName;
Jason Monk56e09b42014-07-18 10:29:14 -040031import android.content.ContentResolver;
Winson Chunga10370f2014-04-02 12:25:04 -070032import android.content.Context;
33import android.content.Intent;
34import android.content.pm.ActivityInfo;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070035import android.content.pm.IPackageManager;
Winson Chunga10370f2014-04-02 12:25:04 -070036import android.content.pm.PackageManager;
Winson Chungbf8871d2014-08-28 20:57:16 -070037import android.content.pm.ResolveInfo;
Winson Chung85cfec82014-07-14 14:16:04 -070038import android.content.res.Resources;
Winson Chunga10370f2014-04-02 12:25:04 -070039import android.graphics.Bitmap;
Winson Chungffa2ec62014-07-03 15:54:42 -070040import android.graphics.BitmapFactory;
Winson Chungb5ddfc32014-06-13 17:23:12 -070041import android.graphics.Canvas;
42import android.graphics.Color;
43import android.graphics.Paint;
Winson Chungdcfa7972014-07-22 12:27:13 -070044import android.graphics.Point;
Winson Chungb5ddfc32014-06-13 17:23:12 -070045import android.graphics.PorterDuff;
46import android.graphics.PorterDuffXfermode;
Winson Chungffa2ec62014-07-03 15:54:42 -070047import android.graphics.Rect;
Winson Chunga10370f2014-04-02 12:25:04 -070048import android.graphics.drawable.ColorDrawable;
49import android.graphics.drawable.Drawable;
Winson Chungecd9b302014-04-16 17:07:18 -070050import android.os.Bundle;
Winson Chungffa2ec62014-07-03 15:54:42 -070051import android.os.ParcelFileDescriptor;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070052import android.os.RemoteException;
Winson Chungd16c5652015-01-26 16:11:07 -080053import android.os.SystemProperties;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070054import android.os.UserHandle;
Jason Monk56e09b42014-07-18 10:29:14 -040055import android.provider.Settings;
Winson Chungb5ddfc32014-06-13 17:23:12 -070056import android.util.Log;
Winson Chungf7bca432014-04-30 17:11:13 -070057import android.util.Pair;
Winson Chungd16c5652015-01-26 16:11:07 -080058import android.util.SparseArray;
Winson Chungd42a6cf2014-06-03 16:24:04 -070059import android.view.Display;
60import android.view.DisplayInfo;
Winson Chungd42a6cf2014-06-03 16:24:04 -070061import android.view.SurfaceControl;
62import android.view.WindowManager;
Winson Chungee445952014-09-09 16:12:59 +020063import android.view.accessibility.AccessibilityManager;
Winson Chung4e96eb72014-09-17 15:16:09 +020064import com.android.systemui.R;
Winson Chungffa2ec62014-07-03 15:54:42 -070065import com.android.systemui.recents.Constants;
Winson Chung2cf8b222015-01-20 11:44:05 -080066import com.android.systemui.recents.Recents;
Winson Chunga10370f2014-04-02 12:25:04 -070067
Winson Chungffa2ec62014-07-03 15:54:42 -070068import java.io.IOException;
Winson Chunga10370f2014-04-02 12:25:04 -070069import java.util.ArrayList;
Winson Chungd16c5652015-01-26 16:11:07 -080070import java.util.Collections;
71import java.util.Comparator;
Winson Chung918c0722014-05-08 15:04:23 -070072import java.util.Iterator;
Winson Chunga10370f2014-04-02 12:25:04 -070073import java.util.List;
Winson Chung5e3e5d82014-04-02 15:44:55 -070074import java.util.Random;
Winson Chung2cf8b222015-01-20 11:44:05 -080075import java.util.concurrent.atomic.AtomicBoolean;
Winson Chunga10370f2014-04-02 12:25:04 -070076
77/**
78 * Acts as a shim around the real system services that we need to access data from, and provides
79 * a point of injection when testing UI.
80 */
81public class SystemServicesProxy {
Winson Chungb5ddfc32014-06-13 17:23:12 -070082 final static String TAG = "SystemServicesProxy";
83
Dianne Hackbornaec68bb2014-08-20 15:25:13 -070084 final static BitmapFactory.Options sBitmapOptions;
85
Winson Chungee445952014-09-09 16:12:59 +020086 AccessibilityManager mAccm;
Winson Chunga10370f2014-04-02 12:25:04 -070087 ActivityManager mAm;
Winson Chung1f24c7e2014-07-11 17:06:48 -070088 IActivityManager mIam;
Winson Chungf7bca432014-04-30 17:11:13 -070089 AppWidgetManager mAwm;
Winson Chunga10370f2014-04-02 12:25:04 -070090 PackageManager mPm;
Amith Yamasani4f0a49e2014-04-10 13:48:15 -070091 IPackageManager mIpm;
Winson Chungecd9b302014-04-16 17:07:18 -070092 SearchManager mSm;
Winson Chungd42a6cf2014-06-03 16:24:04 -070093 WindowManager mWm;
94 Display mDisplay;
Winson Chung918c0722014-05-08 15:04:23 -070095 String mRecentsPackage;
Winson Chungda5b84c2014-05-05 12:06:28 -070096 ComponentName mAssistComponent;
Winson Chunga10370f2014-04-02 12:25:04 -070097
98 Bitmap mDummyIcon;
Winson Chung85cfec82014-07-14 14:16:04 -070099 int mDummyThumbnailWidth;
100 int mDummyThumbnailHeight;
Winson Chungb5ddfc32014-06-13 17:23:12 -0700101 Paint mBgProtectionPaint;
102 Canvas mBgProtectionCanvas;
Winson Chunga10370f2014-04-02 12:25:04 -0700103
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700104 static {
105 sBitmapOptions = new BitmapFactory.Options();
106 sBitmapOptions.inMutable = true;
107 }
108
Winson Chunga10370f2014-04-02 12:25:04 -0700109 /** Private constructor */
110 public SystemServicesProxy(Context context) {
Winson Chungee445952014-09-09 16:12:59 +0200111 mAccm = AccessibilityManager.getInstance(context);
Winson Chunga10370f2014-04-02 12:25:04 -0700112 mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
Winson Chung1f24c7e2014-07-11 17:06:48 -0700113 mIam = ActivityManagerNative.getDefault();
Winson Chungf7bca432014-04-30 17:11:13 -0700114 mAwm = AppWidgetManager.getInstance(context);
Winson Chunga10370f2014-04-02 12:25:04 -0700115 mPm = context.getPackageManager();
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700116 mIpm = AppGlobals.getPackageManager();
Winson Chungecd9b302014-04-16 17:07:18 -0700117 mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700118 mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
119 mDisplay = mWm.getDefaultDisplay();
Winson Chung918c0722014-05-08 15:04:23 -0700120 mRecentsPackage = context.getPackageName();
Winson Chunga10370f2014-04-02 12:25:04 -0700121
Winson Chung85cfec82014-07-14 14:16:04 -0700122 // Get the dummy thumbnail width/heights
123 Resources res = context.getResources();
124 int wId = com.android.internal.R.dimen.thumbnail_width;
125 int hId = com.android.internal.R.dimen.thumbnail_height;
126 mDummyThumbnailWidth = res.getDimensionPixelSize(wId);
127 mDummyThumbnailHeight = res.getDimensionPixelSize(hId);
128
Winson Chungb5ddfc32014-06-13 17:23:12 -0700129 // Create the protection paints
130 mBgProtectionPaint = new Paint();
131 mBgProtectionPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
132 mBgProtectionPaint.setColor(0xFFffffff);
133 mBgProtectionCanvas = new Canvas();
134
Winson Chungda5b84c2014-05-05 12:06:28 -0700135 // Resolve the assist intent
136 Intent assist = mSm.getAssistIntent(context, false);
137 if (assist != null) {
138 mAssistComponent = assist.getComponent();
139 }
140
Winson Chunga10370f2014-04-02 12:25:04 -0700141 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
142 // Create a dummy icon
Winson Chung2f2ca082014-04-03 18:05:29 -0700143 mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
Winson Chung67369052014-04-07 17:35:48 -0700144 mDummyIcon.eraseColor(0xFF999999);
Winson Chunga10370f2014-04-02 12:25:04 -0700145 }
146 }
147
148 /** Returns a list of the recents tasks */
Winson Chung9cb5c4e2014-09-29 13:16:05 -0700149 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
150 boolean isTopTaskHome) {
Winson Chunga10370f2014-04-02 12:25:04 -0700151 if (mAm == null) return null;
152
153 // If we are mocking, then create some recent tasks
154 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
155 ArrayList<ActivityManager.RecentTaskInfo> tasks =
156 new ArrayList<ActivityManager.RecentTaskInfo>();
Winson Chung918c0722014-05-08 15:04:23 -0700157 int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
Winson Chunga10370f2014-04-02 12:25:04 -0700158 for (int i = 0; i < count; i++) {
159 // Create a dummy component name
160 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
161 ComponentName cn = new ComponentName("com.android.test" + packageIndex,
162 "com.android.test" + i + ".Activity");
Winson Chunga449dc02014-05-16 11:15:04 -0700163 String description = "" + i + " - " +
164 Long.toString(Math.abs(new Random().nextLong()), 36);
Winson Chunga10370f2014-04-02 12:25:04 -0700165 // Create the recent task info
166 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
167 rti.id = rti.persistentId = i;
168 rti.baseIntent = new Intent();
169 rti.baseIntent.setComponent(cn);
Winson Chunga449dc02014-05-16 11:15:04 -0700170 rti.description = description;
Winson Chungffa2ec62014-07-03 15:54:42 -0700171 rti.firstActiveTime = rti.lastActiveTime = i;
Winson Chung5e3e5d82014-04-02 15:44:55 -0700172 if (i % 2 == 0) {
Winson Chunga449dc02014-05-16 11:15:04 -0700173 rti.taskDescription = new ActivityManager.TaskDescription(description,
Winson Chung10f81392014-05-20 16:21:31 -0700174 Bitmap.createBitmap(mDummyIcon),
175 0xFF000000 | (0xFFFFFF & new Random().nextInt()));
Winson Chunga449dc02014-05-16 11:15:04 -0700176 } else {
177 rti.taskDescription = new ActivityManager.TaskDescription();
Winson Chung5e3e5d82014-04-02 15:44:55 -0700178 }
Winson Chunga10370f2014-04-02 12:25:04 -0700179 tasks.add(rti);
180 }
181 return tasks;
182 }
183
Winson Chung918c0722014-05-08 15:04:23 -0700184 // Remove home/recents/excluded tasks
185 int minNumTasksToQuery = 10;
186 int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
187 List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
Winson Chunga4ccb862014-08-22 15:26:27 -0700188 ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
Winson Chunga10370f2014-04-02 12:25:04 -0700189 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
Winson Chung918c0722014-05-08 15:04:23 -0700190 ActivityManager.RECENT_INCLUDE_PROFILES |
191 ActivityManager.RECENT_WITH_EXCLUDED, userId);
Winson Chung4298b432014-09-12 15:25:46 +0200192
193 // Break early if we can't get a valid set of tasks
194 if (tasks == null) {
195 return new ArrayList<ActivityManager.RecentTaskInfo>();
196 }
197
Winson Chung918c0722014-05-08 15:04:23 -0700198 boolean isFirstValidTask = true;
199 Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
200 while (iter.hasNext()) {
201 ActivityManager.RecentTaskInfo t = iter.next();
202
203 // NOTE: The order of these checks happens in the expected order of the traversal of the
204 // tasks
205
Winson Chung918c0722014-05-08 15:04:23 -0700206 // Check the first non-recents task, include this task even if it is marked as excluded
Winson Chung9cb5c4e2014-09-29 13:16:05 -0700207 // from recents if we are currently in the app. In other words, only remove excluded
208 // tasks if it is not the first active task.
Winson Chung918c0722014-05-08 15:04:23 -0700209 boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
210 == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
Winson Chung9cb5c4e2014-09-29 13:16:05 -0700211 if (isExcluded && (isTopTaskHome || !isFirstValidTask)) {
Winson Chung918c0722014-05-08 15:04:23 -0700212 iter.remove();
213 continue;
214 }
215 isFirstValidTask = false;
Winson Chung918c0722014-05-08 15:04:23 -0700216 }
217
218 return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
Winson Chunga10370f2014-04-02 12:25:04 -0700219 }
220
221 /** Returns a list of the running tasks */
Winson Chung2cf8b222015-01-20 11:44:05 -0800222 private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
Winson Chunga10370f2014-04-02 12:25:04 -0700223 if (mAm == null) return null;
224 return mAm.getRunningTasks(numTasks);
225 }
226
Winson Chung2cf8b222015-01-20 11:44:05 -0800227 /** Returns the top task. */
228 public ActivityManager.RunningTaskInfo getTopMostTask() {
229 List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1);
230 if (!tasks.isEmpty()) {
231 return tasks.get(0);
232 }
233 return null;
234 }
235
Winson Chungd16c5652015-01-26 16:11:07 -0800236 /** Returns a list of all the launcher apps sorted by name. */
237 public List<ResolveInfo> getLauncherApps() {
238 if (mPm == null) return new ArrayList<ResolveInfo>();
239
240 final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
241 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
242 List<ResolveInfo> activities = mPm.queryIntentActivities(mainIntent, 0 /* flags */);
243 Collections.sort(activities, new Comparator<ResolveInfo>() {
244 @Override
245 public int compare(ResolveInfo o1, ResolveInfo o2) {
246 return getActivityLabel(o1.activityInfo).compareTo(
247 getActivityLabel(o2.activityInfo));
248 }
249 });
250 return activities;
251 }
252
Winson Chung2cf8b222015-01-20 11:44:05 -0800253 /** Returns whether the recents is currently running */
254 public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
255 AtomicBoolean isHomeTopMost) {
256 if (topTask != null) {
257 ComponentName topActivity = topTask.topActivity;
258
259 // Check if the front most activity is recents
260 if (topActivity.getPackageName().equals(Recents.sRecentsPackage) &&
261 topActivity.getClassName().equals(Recents.sRecentsActivity)) {
262 if (isHomeTopMost != null) {
263 isHomeTopMost.set(false);
264 }
265 return true;
266 }
267
268 if (isHomeTopMost != null) {
269 isHomeTopMost.set(isInHomeStack(topTask.id));
270 }
271 }
272 return false;
273 }
274
Winson Chungd16c5652015-01-26 16:11:07 -0800275 /** Create a new stack. */
276 public void createNewStack(int displayId, Rect bounds, Intent activity) {
277 try {
278 IActivityContainer container = mIam.createStackOnDisplay(displayId);
279 if (container != null) {
280 // Resize the stack
281 resizeStack(container.getStackId(), bounds);
282 // Start the new activity on that stack
283 container.startActivity(activity);
284 }
285 } catch (RemoteException e) {
286 e.printStackTrace();
287 }
288 }
289
290 /** Resizes a stack. */
291 public void resizeStack(int stackId, Rect bounds) {
292 if (mIam == null) return;
293
294 try {
295 mIam.resizeStack(stackId, bounds);
296 } catch (RemoteException e) {
297 e.printStackTrace();
298 }
299 }
300
301 /** Returns the stack info for all stacks. */
302 public SparseArray<ActivityManager.StackInfo> getAllStackInfos() {
303 if (mIam == null) return new SparseArray<ActivityManager.StackInfo>();
304
305 try {
306 SparseArray<ActivityManager.StackInfo> stacks =
307 new SparseArray<ActivityManager.StackInfo>();
308 List<ActivityManager.StackInfo> infos = mIam.getAllStackInfos();
309 int stackCount = infos.size();
310 for (int i = 0; i < stackCount; i++) {
311 ActivityManager.StackInfo info = infos.get(i);
312 stacks.put(info.stackId, info);
313 }
314 return stacks;
315 } catch (RemoteException e) {
316 e.printStackTrace();
317 return new SparseArray<ActivityManager.StackInfo>();
318 }
319 }
320
321 /** Returns the focused stack id. */
322 public int getFocusedStack() {
323 if (mIam == null) return -1;
324
325 try {
326 return mIam.getFocusedStackId();
327 } catch (RemoteException e) {
328 e.printStackTrace();
329 return -1;
330 }
331 }
332
Winson Chunga10370f2014-04-02 12:25:04 -0700333 /** Returns whether the specified task is in the home stack */
334 public boolean isInHomeStack(int taskId) {
335 if (mAm == null) return false;
336
337 // If we are mocking, then just return false
338 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
339 return false;
340 }
341
342 return mAm.isInHomeStack(taskId);
343 }
344
345 /** Returns the top task thumbnail for the given task id */
346 public Bitmap getTaskThumbnail(int taskId) {
347 if (mAm == null) return null;
348
349 // If we are mocking, then just return a dummy thumbnail
350 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
Winson Chung85cfec82014-07-14 14:16:04 -0700351 Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight,
352 Bitmap.Config.ARGB_8888);
Winson Chung67369052014-04-07 17:35:48 -0700353 thumbnail.eraseColor(0xff333333);
Winson Chunga10370f2014-04-02 12:25:04 -0700354 return thumbnail;
355 }
356
Winson Chungffa2ec62014-07-03 15:54:42 -0700357 Bitmap thumbnail = SystemServicesProxy.getThumbnail(mAm, taskId);
Winson Chungb5ddfc32014-06-13 17:23:12 -0700358 if (thumbnail != null) {
Winson Chunga91c2932014-11-07 15:02:38 -0800359 thumbnail.setHasAlpha(false);
Winson Chungb5ddfc32014-06-13 17:23:12 -0700360 // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
361 // left pixel, then assume the whole thumbnail is transparent. Generally, proper
362 // screenshots are always composed onto a bitmap that has no alpha.
363 if (Color.alpha(thumbnail.getPixel(0, 0)) == 0) {
364 mBgProtectionCanvas.setBitmap(thumbnail);
365 mBgProtectionCanvas.drawRect(0, 0, thumbnail.getWidth(), thumbnail.getHeight(),
366 mBgProtectionPaint);
367 mBgProtectionCanvas.setBitmap(null);
368 Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
369 }
370 }
371 return thumbnail;
Winson Chunga10370f2014-04-02 12:25:04 -0700372 }
373
Winson Chungffa2ec62014-07-03 15:54:42 -0700374 /**
375 * Returns a task thumbnail from the activity manager
376 */
377 public static Bitmap getThumbnail(ActivityManager activityManager, int taskId) {
378 ActivityManager.TaskThumbnail taskThumbnail = activityManager.getTaskThumbnail(taskId);
Winson Chung85cfec82014-07-14 14:16:04 -0700379 if (taskThumbnail == null) return null;
380
Winson Chungffa2ec62014-07-03 15:54:42 -0700381 Bitmap thumbnail = taskThumbnail.mainThumbnail;
382 ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
383 if (thumbnail == null && descriptor != null) {
Dianne Hackbornaec68bb2014-08-20 15:25:13 -0700384 thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
385 null, sBitmapOptions);
Winson Chungffa2ec62014-07-03 15:54:42 -0700386 }
387 if (descriptor != null) {
388 try {
389 descriptor.close();
390 } catch (IOException e) {
391 }
392 }
393 return thumbnail;
394 }
395
Winson Chungd16c5652015-01-26 16:11:07 -0800396 /** Moves a task to the front with the specified activity options. */
Winson Chunga10370f2014-04-02 12:25:04 -0700397 public void moveTaskToFront(int taskId, ActivityOptions opts) {
398 if (mAm == null) return;
399 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
400
401 if (opts != null) {
402 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
403 opts.toBundle());
404 } else {
405 mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME);
406 }
407 }
408
Winson Chungd16c5652015-01-26 16:11:07 -0800409 /** Moves a task to another stack. */
410 public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
411 if (mIam == null) return;
412 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
413
414 try {
415 mIam.moveTaskToStack(taskId, stackId, toTop);
416 } catch (RemoteException e) {
417 e.printStackTrace();
418 }
419 }
420
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700421 /** Removes the task */
422 public void removeTask(int taskId) {
Winson Chunga10370f2014-04-02 12:25:04 -0700423 if (mAm == null) return;
424 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
425
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700426 // Remove the task.
427 mAm.removeTask(taskId);
Winson Chunga10370f2014-04-02 12:25:04 -0700428 }
429
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700430 /**
431 * Returns the activity info for a given component name.
Wale Ogunwaled54b5782014-10-23 15:55:23 -0700432 *
Winson Chungf7bca432014-04-30 17:11:13 -0700433 * @param cn The component name of the activity.
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700434 * @param userId The userId of the user that this is for.
435 */
436 public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
437 if (mIpm == null) return null;
Winson Chung814086d2014-05-07 15:01:14 -0700438 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
Winson Chunga10370f2014-04-02 12:25:04 -0700439
440 try {
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700441 return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
442 } catch (RemoteException e) {
Winson Chunga10370f2014-04-02 12:25:04 -0700443 e.printStackTrace();
444 return null;
445 }
446 }
447
Winson Chungf7bca432014-04-30 17:11:13 -0700448 /**
449 * Returns the activity info for a given component name.
450 *
451 * @param cn The component name of the activity.
452 */
453 public ActivityInfo getActivityInfo(ComponentName cn) {
454 if (mPm == null) return null;
Winson Chung814086d2014-05-07 15:01:14 -0700455 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
Winson Chungf7bca432014-04-30 17:11:13 -0700456
457 try {
458 return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
459 } catch (PackageManager.NameNotFoundException e) {
460 e.printStackTrace();
461 return null;
462 }
463 }
464
Winson Chunga10370f2014-04-02 12:25:04 -0700465 /** Returns the activity label */
466 public String getActivityLabel(ActivityInfo info) {
467 if (mPm == null) return null;
468
469 // If we are mocking, then return a mock label
470 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
471 return "Recent Task";
472 }
473
474 return info.loadLabel(mPm).toString();
475 }
476
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700477 /**
478 * Returns the activity icon for the ActivityInfo for a user, badging if
479 * necessary.
480 */
481 public Drawable getActivityIcon(ActivityInfo info, int userId) {
Svetoslavc7d62f02014-09-04 15:39:54 -0700482 if (mPm == null) return null;
Winson Chunga10370f2014-04-02 12:25:04 -0700483
484 // If we are mocking, then return a mock label
485 if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
Winson Chung2f2ca082014-04-03 18:05:29 -0700486 return new ColorDrawable(0xFF666666);
Winson Chunga10370f2014-04-02 12:25:04 -0700487 }
488
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700489 Drawable icon = info.loadIcon(mPm);
Robin Lee6507f2e2014-06-26 14:13:17 +0100490 return getBadgedIcon(icon, userId);
491 }
492
493 /**
494 * Returns the given icon for a user, badging if necessary.
495 */
496 public Drawable getBadgedIcon(Drawable icon, int userId) {
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700497 if (userId != UserHandle.myUserId()) {
Amith Yamasanifdf169c2014-09-07 15:45:57 -0700498 icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
Amith Yamasani4f0a49e2014-04-10 13:48:15 -0700499 }
500 return icon;
Winson Chunga10370f2014-04-02 12:25:04 -0700501 }
Winson Chungecd9b302014-04-16 17:07:18 -0700502
Winson Chungbf8871d2014-08-28 20:57:16 -0700503 /** Returns the package name of the home activity. */
504 public String getHomeActivityPackageName() {
505 if (mPm == null) return null;
506 if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
507
508 ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
509 ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
510 if (defaultHomeActivity != null) {
511 return defaultHomeActivity.getPackageName();
512 } else if (homeActivities.size() == 1) {
513 ResolveInfo info = homeActivities.get(0);
514 if (info.activityInfo != null) {
515 return info.activityInfo.packageName;
516 }
517 }
518 return null;
519 }
520
521 /**
Winson Chung2002cf52014-12-08 17:26:44 -0800522 * Returns whether the foreground user is the owner.
523 */
524 public boolean isForegroundUserOwner() {
525 if (mAm == null) return false;
526
527 return mAm.getCurrentUser() == UserHandle.USER_OWNER;
528 }
529
530 /**
Winson Chungbf8871d2014-08-28 20:57:16 -0700531 * Resolves and returns the first Recents widget from the same package as the global
532 * assist activity.
533 */
534 public AppWidgetProviderInfo resolveSearchAppWidget() {
535 if (mAwm == null) return null;
536 if (mAssistComponent == null) return null;
537
538 // Find the first Recents widget from the same package as the global assist activity
539 List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
Winson Chungee0b1212014-09-04 16:42:53 +0200540 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
Winson Chungbf8871d2014-08-28 20:57:16 -0700541 for (AppWidgetProviderInfo info : widgets) {
542 if (info.provider.getPackageName().equals(mAssistComponent.getPackageName())) {
543 return info;
544 }
545 }
546 return null;
547 }
548
Winson Chungecd9b302014-04-16 17:07:18 -0700549 /**
Winson Chungf7bca432014-04-30 17:11:13 -0700550 * Resolves and binds the search app widget that is to appear in the recents.
Winson Chungecd9b302014-04-16 17:07:18 -0700551 */
Winson Chungf7bca432014-04-30 17:11:13 -0700552 public Pair<Integer, AppWidgetProviderInfo> bindSearchAppWidget(AppWidgetHost host) {
553 if (mAwm == null) return null;
Winson Chungda5b84c2014-05-05 12:06:28 -0700554 if (mAssistComponent == null) return null;
Winson Chungecd9b302014-04-16 17:07:18 -0700555
Winson Chungda5b84c2014-05-05 12:06:28 -0700556 // Find the first Recents widget from the same package as the global assist activity
Winson Chungbf8871d2014-08-28 20:57:16 -0700557 AppWidgetProviderInfo searchWidgetInfo = resolveSearchAppWidget();
Winson Chungf7bca432014-04-30 17:11:13 -0700558
559 // Return early if there is no search widget
560 if (searchWidgetInfo == null) return null;
561
562 // Allocate a new widget id and try and bind the app widget (if that fails, then just skip)
563 int searchWidgetId = host.allocateAppWidgetId();
564 Bundle opts = new Bundle();
565 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
Winson Chungee0b1212014-09-04 16:42:53 +0200566 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
Winson Chungf7bca432014-04-30 17:11:13 -0700567 if (!mAwm.bindAppWidgetIdIfAllowed(searchWidgetId, searchWidgetInfo.provider, opts)) {
Winson Chung044d5292014-11-06 11:05:19 -0800568 host.deleteAppWidgetId(searchWidgetId);
Winson Chungf7bca432014-04-30 17:11:13 -0700569 return null;
570 }
571 return new Pair<Integer, AppWidgetProviderInfo>(searchWidgetId, searchWidgetInfo);
572 }
573
574 /**
575 * Returns the app widget info for the specified app widget id.
576 */
577 public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) {
578 if (mAwm == null) return null;
579
580 return mAwm.getAppWidgetInfo(appWidgetId);
581 }
582
583 /**
584 * Destroys the specified app widget.
585 */
586 public void unbindSearchAppWidget(AppWidgetHost host, int appWidgetId) {
587 if (mAwm == null) return;
588
589 // Delete the app widget
590 host.deleteAppWidgetId(appWidgetId);
Winson Chungecd9b302014-04-16 17:07:18 -0700591 }
Winson Chungd42a6cf2014-06-03 16:24:04 -0700592
593 /**
Winson Chungee445952014-09-09 16:12:59 +0200594 * Returns whether touch exploration is currently enabled.
595 */
596 public boolean isTouchExplorationEnabled() {
597 if (mAccm == null) return false;
598
599 return mAccm.isEnabled() && mAccm.isTouchExplorationEnabled();
600 }
601
602 /**
Jason Monk56e09b42014-07-18 10:29:14 -0400603 * Returns a global setting.
604 */
605 public int getGlobalSetting(Context context, String setting) {
606 ContentResolver cr = context.getContentResolver();
607 return Settings.Global.getInt(cr, setting, 0);
608 }
609
610 /**
611 * Returns a system setting.
612 */
613 public int getSystemSetting(Context context, String setting) {
614 ContentResolver cr = context.getContentResolver();
615 return Settings.System.getInt(cr, setting, 0);
616 }
617
618 /**
Winson Chungd16c5652015-01-26 16:11:07 -0800619 * Returns a system property.
620 */
621 public String getSystemProperty(String key) {
622 return SystemProperties.get(key);
623 }
624
625 /**
Winson Chungffa2ec62014-07-03 15:54:42 -0700626 * Returns the window rect.
627 */
628 public Rect getWindowRect() {
629 Rect windowRect = new Rect();
630 if (mWm == null) return windowRect;
631
Winson Chungdcfa7972014-07-22 12:27:13 -0700632 Point p = new Point();
633 mWm.getDefaultDisplay().getRealSize(p);
634 windowRect.set(0, 0, p.x, p.y);
Winson Chungffa2ec62014-07-03 15:54:42 -0700635 return windowRect;
636 }
637
638 /**
Winson Chungd42a6cf2014-06-03 16:24:04 -0700639 * Takes a screenshot of the current surface.
640 */
641 public Bitmap takeScreenshot() {
642 DisplayInfo di = new DisplayInfo();
643 mDisplay.getDisplayInfo(di);
644 return SurfaceControl.screenshot(di.getNaturalWidth(), di.getNaturalHeight());
645 }
Winson Chungffa2ec62014-07-03 15:54:42 -0700646
647 /**
648 * Takes a screenshot of the current app.
649 */
650 public Bitmap takeAppScreenshot() {
651 return takeScreenshot();
652 }
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700653
Winson Chung4e96eb72014-09-17 15:16:09 +0200654 /** Starts an activity from recents. */
655 public boolean startActivityFromRecents(Context context, int taskId, String taskName,
656 ActivityOptions options) {
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700657 if (mIam != null) {
658 try {
659 mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
Winson Chung4e96eb72014-09-17 15:16:09 +0200660 return true;
661 } catch (Exception e) {
662 Console.logError(context,
663 context.getString(R.string.recents_launch_error_message, taskName));
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700664 }
665 }
Winson Chung4e96eb72014-09-17 15:16:09 +0200666 return false;
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700667 }
Winson Chung044d5292014-11-06 11:05:19 -0800668
669 /** Starts an in-place animation on the front most application windows. */
670 public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) {
671 if (mIam == null) return;
672
673 try {
674 mIam.startInPlaceAnimationOnFrontMostApplication(opts);
675 } catch (Exception e) {
676 e.printStackTrace();
677 }
678 }
Winson Chung740c3ac2014-11-12 16:14:38 -0800679
680 /** Registers a task stack listener with the system. */
681 public void registerTaskStackListener(ITaskStackListener listener) {
682 if (mIam == null) return;
683
684 try {
685 mIam.registerTaskStackListener(listener);
686 } catch (Exception e) {
687 e.printStackTrace();
688 }
689 }
Winson Chunga10370f2014-04-02 12:25:04 -0700690}