• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.shared.system;
18 
19 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
20 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
21 import static android.app.ActivityTaskManager.getService;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.Activity;
26 import android.app.ActivityClient;
27 import android.app.ActivityManager;
28 import android.app.ActivityManager.RunningTaskInfo;
29 import android.app.ActivityOptions;
30 import android.app.ActivityTaskManager;
31 import android.app.AppGlobals;
32 import android.app.WindowConfiguration;
33 import android.content.ContentResolver;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.pm.PackageManager;
37 import android.content.pm.UserInfo;
38 import android.graphics.Rect;
39 import android.os.Bundle;
40 import android.os.Handler;
41 import android.os.IBinder;
42 import android.os.RemoteException;
43 import android.os.ServiceManager;
44 import android.os.SystemClock;
45 import android.provider.Settings;
46 import android.util.Log;
47 import android.view.Display;
48 import android.view.IRecentsAnimationController;
49 import android.view.IRecentsAnimationRunner;
50 import android.view.RemoteAnimationTarget;
51 import android.window.TaskSnapshot;
52 
53 import com.android.internal.app.IVoiceInteractionManagerService;
54 import com.android.systemui.shared.recents.model.Task;
55 import com.android.systemui.shared.recents.model.ThumbnailData;
56 
57 import java.util.List;
58 import java.util.function.Consumer;
59 
60 public class ActivityManagerWrapper {
61 
62     private static final String TAG = "ActivityManagerWrapper";
63     private static final int NUM_RECENT_ACTIVITIES_REQUEST = 3;
64     private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
65 
66     // Should match the values in PhoneWindowManager
67     public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
68     public static final String CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY = "homekey";
69 
70     // Should match the value in AssistManager
71     private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
72 
73     private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
ActivityManagerWrapper()74     private ActivityManagerWrapper() { }
75 
getInstance()76     public static ActivityManagerWrapper getInstance() {
77         return sInstance;
78     }
79 
80     /**
81      * @return the current user's id.
82      */
getCurrentUserId()83     public int getCurrentUserId() {
84         UserInfo ui;
85         try {
86             ui = ActivityManager.getService().getCurrentUser();
87             return ui != null ? ui.id : 0;
88         } catch (RemoteException e) {
89             throw e.rethrowFromSystemServer();
90         }
91     }
92 
93     /**
94      * @return the top running task (can be {@code null}).
95      */
getRunningTask()96     public ActivityManager.RunningTaskInfo getRunningTask() {
97         return getRunningTask(false /* filterVisibleRecents */);
98     }
99 
100     /**
101      * @return the top running task filtering only for tasks that can be visible in the recent tasks
102      * list (can be {@code null}).
103      */
getRunningTask(boolean filterOnlyVisibleRecents)104     public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
105         // Note: The set of running tasks from the system is ordered by recency
106         List<ActivityManager.RunningTaskInfo> tasks =
107                 mAtm.getTasks(1, filterOnlyVisibleRecents);
108         if (tasks.isEmpty()) {
109             return null;
110         }
111         return tasks.get(0);
112     }
113 
114     /**
115      * @see #getRunningTasks(boolean , int)
116      */
getRunningTasks(boolean filterOnlyVisibleRecents)117     public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
118         return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
119     }
120 
121     /**
122      * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
123      * we'll get back 2 activities for each split app and one for launcher. Launcher might be more
124      * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
125      * out on one of the split apps
126      *
127      * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
128      *         filtering only for tasks that can be visible in the recent tasks list.
129      */
getRunningTasks(boolean filterOnlyVisibleRecents, int displayId)130     public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
131             int displayId) {
132         // Note: The set of running tasks from the system is ordered by recency
133         List<ActivityManager.RunningTaskInfo> tasks =
134                 mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
135                         filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
136         return tasks.toArray(new RunningTaskInfo[tasks.size()]);
137     }
138 
139     /**
140      * @return a {@link ThumbnailData} with {@link TaskSnapshot} for the given {@param taskId}.
141      *         The snapshot will be triggered if no cached {@link TaskSnapshot} exists.
142      */
getTaskThumbnail(int taskId, boolean isLowResolution)143     public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
144         TaskSnapshot snapshot = null;
145         try {
146             snapshot = getService().getTaskSnapshot(taskId, isLowResolution,
147                     true /* takeSnapshotIfNeeded */);
148         } catch (RemoteException e) {
149             Log.w(TAG, "Failed to retrieve task snapshot", e);
150         }
151         if (snapshot != null) {
152             return new ThumbnailData(snapshot);
153         } else {
154             return new ThumbnailData();
155         }
156     }
157 
158     /**
159      * Removes the outdated snapshot of home task.
160      *
161      * @param homeActivity The home task activity, or null if you have the
162      *                     {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS} permission and
163      *                     want us to find the home task for you.
164      */
invalidateHomeTaskSnapshot(@ullable final Activity homeActivity)165     public void invalidateHomeTaskSnapshot(@Nullable final Activity homeActivity) {
166         try {
167             ActivityClient.getInstance().invalidateHomeTaskSnapshot(
168                     homeActivity == null ? null : homeActivity.getActivityToken());
169         } catch (Throwable e) {
170             Log.w(TAG, "Failed to invalidate home snapshot", e);
171         }
172     }
173 
174     /**
175      * Starts the recents activity. The caller should manage the thread on which this is called.
176      */
startRecentsActivity(Intent intent, long eventTime, final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback, Handler resultCallbackHandler)177     public void startRecentsActivity(Intent intent, long eventTime,
178             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
179             Handler resultCallbackHandler) {
180         boolean result = startRecentsActivity(intent, eventTime, animationHandler);
181         if (resultCallback != null) {
182             resultCallbackHandler.post(new Runnable() {
183                 @Override
184                 public void run() {
185                     resultCallback.accept(result);
186                 }
187             });
188         }
189     }
190 
191     /**
192      * Starts the recents activity. The caller should manage the thread on which this is called.
193      */
startRecentsActivity( Intent intent, long eventTime, RecentsAnimationListener animationHandler)194     public boolean startRecentsActivity(
195             Intent intent, long eventTime, RecentsAnimationListener animationHandler) {
196         try {
197             IRecentsAnimationRunner runner = null;
198             if (animationHandler != null) {
199                 runner = new IRecentsAnimationRunner.Stub() {
200                     @Override
201                     public void onAnimationStart(IRecentsAnimationController controller,
202                             RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
203                             Rect homeContentInsets, Rect minimizedHomeBounds) {
204                         final RecentsAnimationControllerCompat controllerCompat =
205                                 new RecentsAnimationControllerCompat(controller);
206                         animationHandler.onAnimationStart(controllerCompat, apps,
207                                 wallpapers, homeContentInsets, minimizedHomeBounds);
208                     }
209 
210                     @Override
211                     public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots) {
212                         animationHandler.onAnimationCanceled(
213                                 ThumbnailData.wrap(taskIds, taskSnapshots));
214                     }
215 
216                     @Override
217                     public void onTasksAppeared(RemoteAnimationTarget[] apps) {
218                         animationHandler.onTasksAppeared(apps);
219                     }
220                 };
221             }
222             getService().startRecentsActivity(intent, eventTime, runner);
223             return true;
224         } catch (Exception e) {
225             return false;
226         }
227     }
228 
229     /**
230      * Cancels the remote recents animation started from {@link #startRecentsActivity}.
231      */
cancelRecentsAnimation(boolean restoreHomeRootTaskPosition)232     public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
233         try {
234             getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
235         } catch (RemoteException e) {
236             Log.e(TAG, "Failed to cancel recents animation", e);
237         }
238     }
239 
240     /**
241      * Starts a task from Recents synchronously.
242      */
startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options)243     public boolean startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options) {
244         return startActivityFromRecents(taskKey.id, options);
245     }
246 
247     /**
248      * Starts a task from Recents synchronously.
249      */
startActivityFromRecents(int taskId, ActivityOptions options)250     public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
251         try {
252             Bundle optsBundle = options == null ? null : options.toBundle();
253             return ActivityManager.isStartResultSuccessful(
254                     getService().startActivityFromRecents(
255                             taskId, optsBundle));
256         } catch (Exception e) {
257             return false;
258         }
259     }
260 
261     /**
262      * Requests that the system close any open system windows (including other SystemUI).
263      */
closeSystemWindows(final String reason)264     public void closeSystemWindows(final String reason) {
265         try {
266             ActivityManager.getService().closeSystemDialogs(reason);
267         } catch (RemoteException e) {
268             Log.w(TAG, "Failed to close system windows", e);
269         }
270     }
271 
272     /**
273      * Removes a task by id.
274      */
removeTask(final int taskId)275     public void removeTask(final int taskId) {
276         try {
277             getService().removeTask(taskId);
278         } catch (RemoteException e) {
279             Log.w(TAG, "Failed to remove task=" + taskId, e);
280         }
281     }
282 
283     /**
284      * Removes all the recent tasks.
285      */
removeAllRecentTasks()286     public void removeAllRecentTasks() {
287         try {
288             getService().removeAllVisibleRecentTasks();
289         } catch (RemoteException e) {
290             Log.w(TAG, "Failed to remove all tasks", e);
291         }
292     }
293 
294     /**
295      * @return whether screen pinning is enabled.
296      */
isScreenPinningEnabled()297     public boolean isScreenPinningEnabled() {
298         final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
299         return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
300     }
301 
302     /**
303      * @return whether there is currently a locked task (ie. in screen pinning).
304      */
isLockToAppActive()305     public boolean isLockToAppActive() {
306         try {
307             return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
308         } catch (RemoteException e) {
309             return false;
310         }
311     }
312 
313     /**
314      * @return whether lock task mode is active in kiosk-mode (not screen pinning).
315      */
isLockTaskKioskModeActive()316     public boolean isLockTaskKioskModeActive() {
317         try {
318             return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
319         } catch (RemoteException e) {
320             return false;
321         }
322     }
323 
324     /**
325      * Shows a voice session identified by {@code token}
326      * @return true if the session was shown, false otherwise
327      */
showVoiceSession(IBinder token, Bundle args, int flags)328     public boolean showVoiceSession(IBinder token, Bundle args, int flags) {
329         IVoiceInteractionManagerService service = IVoiceInteractionManagerService.Stub.asInterface(
330                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
331         if (service == null) {
332             return false;
333         }
334         args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
335 
336         try {
337             return service.showSessionFromSession(token, args, flags);
338         } catch (RemoteException e) {
339             return false;
340         }
341     }
342 
343     /**
344      * Returns true if the system supports freeform multi-window.
345      */
supportsFreeformMultiWindow(Context context)346     public boolean supportsFreeformMultiWindow(Context context) {
347         final boolean freeformDevOption = Settings.Global.getInt(context.getContentResolver(),
348                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
349         return ActivityTaskManager.supportsMultiWindow(context)
350                 && (context.getPackageManager().hasSystemFeature(
351                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
352                 || freeformDevOption);
353     }
354 
355     /**
356      * Returns true if the running task represents the home task
357      */
isHomeTask(RunningTaskInfo info)358     public static boolean isHomeTask(RunningTaskInfo info) {
359         return info.configuration.windowConfiguration.getActivityType()
360                 == WindowConfiguration.ACTIVITY_TYPE_HOME;
361     }
362 }
363