• 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.ActivityManager.LOCK_TASK_MODE_PINNED;
22 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
23 import static android.app.ActivityTaskManager.getService;
24 
25 import android.annotation.NonNull;
26 import android.app.Activity;
27 import android.app.ActivityClient;
28 import android.app.ActivityManager;
29 import android.app.ActivityManager.RecentTaskInfo;
30 import android.app.ActivityManager.RunningTaskInfo;
31 import android.window.TaskSnapshot;
32 import android.app.ActivityOptions;
33 import android.app.ActivityTaskManager;
34 import android.app.AppGlobals;
35 import android.app.WindowConfiguration;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.PackageManager;
40 import android.content.pm.UserInfo;
41 import android.graphics.Rect;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.os.IBinder;
45 import android.os.RemoteException;
46 import android.os.ServiceManager;
47 import android.os.SystemClock;
48 import android.provider.Settings;
49 import android.util.Log;
50 import android.view.IRecentsAnimationController;
51 import android.view.IRecentsAnimationRunner;
52 import android.view.RemoteAnimationTarget;
53 
54 import com.android.internal.app.IVoiceInteractionManagerService;
55 import com.android.systemui.shared.recents.model.Task;
56 import com.android.systemui.shared.recents.model.ThumbnailData;
57 
58 import java.util.List;
59 import java.util.function.Consumer;
60 
61 public class ActivityManagerWrapper {
62 
63     private static final String TAG = "ActivityManagerWrapper";
64 
65     private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
66 
67     // Should match the values in PhoneWindowManager
68     public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
69     public static final String CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY = "homekey";
70 
71     // Should match the value in AssistManager
72     private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
73 
74     private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
ActivityManagerWrapper()75     private ActivityManagerWrapper() { }
76 
getInstance()77     public static ActivityManagerWrapper getInstance() {
78         return sInstance;
79     }
80 
81     /**
82      * @return the current user's id.
83      */
getCurrentUserId()84     public int getCurrentUserId() {
85         UserInfo ui;
86         try {
87             ui = ActivityManager.getService().getCurrentUser();
88             return ui != null ? ui.id : 0;
89         } catch (RemoteException e) {
90             throw e.rethrowFromSystemServer();
91         }
92     }
93 
94     /**
95      * @return the top running task (can be {@code null}).
96      */
getRunningTask()97     public ActivityManager.RunningTaskInfo getRunningTask() {
98         return getRunningTask(false /* filterVisibleRecents */);
99     }
100 
101     /**
102      * @return the top running task filtering only for tasks that can be visible in the recent tasks
103      * list (can be {@code null}).
104      */
getRunningTask(boolean filterOnlyVisibleRecents)105     public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
106         // Note: The set of running tasks from the system is ordered by recency
107         List<ActivityManager.RunningTaskInfo> tasks =
108                 mAtm.getTasks(1, filterOnlyVisibleRecents);
109         if (tasks.isEmpty()) {
110             return null;
111         }
112         return tasks.get(0);
113     }
114 
115     /**
116      * @return a list of the recents tasks.
117      */
getRecentTasks(int numTasks, int userId)118     public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
119         return mAtm.getRecentTasks(numTasks, RECENT_IGNORE_UNAVAILABLE, userId);
120     }
121 
122     /**
123      * @return the task snapshot for the given {@param taskId}.
124      */
getTaskThumbnail(int taskId, boolean isLowResolution)125     public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
126         TaskSnapshot snapshot = null;
127         try {
128             snapshot = getService().getTaskSnapshot(taskId, isLowResolution);
129         } catch (RemoteException e) {
130             Log.w(TAG, "Failed to retrieve task snapshot", e);
131         }
132         if (snapshot != null) {
133             return new ThumbnailData(snapshot);
134         } else {
135             return new ThumbnailData();
136         }
137     }
138 
139     /**
140      * Removes the outdated snapshot of home task.
141      */
invalidateHomeTaskSnapshot(final Activity homeActivity)142     public void invalidateHomeTaskSnapshot(final Activity homeActivity) {
143         try {
144             ActivityClient.getInstance().invalidateHomeTaskSnapshot(
145                     homeActivity.getActivityToken());
146         } catch (Throwable e) {
147             Log.w(TAG, "Failed to invalidate home snapshot", e);
148         }
149     }
150 
151     /**
152      * Starts the recents activity. The caller should manage the thread on which this is called.
153      */
startRecentsActivity(Intent intent, long eventTime, final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback, Handler resultCallbackHandler)154     public void startRecentsActivity(Intent intent, long eventTime,
155             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
156             Handler resultCallbackHandler) {
157         boolean result = startRecentsActivity(intent, eventTime, animationHandler);
158         if (resultCallback != null) {
159             resultCallbackHandler.post(new Runnable() {
160                 @Override
161                 public void run() {
162                     resultCallback.accept(result);
163                 }
164             });
165         }
166     }
167 
168     /**
169      * Starts the recents activity. The caller should manage the thread on which this is called.
170      */
startRecentsActivity( Intent intent, long eventTime, RecentsAnimationListener animationHandler)171     public boolean startRecentsActivity(
172             Intent intent, long eventTime, RecentsAnimationListener animationHandler) {
173         try {
174             IRecentsAnimationRunner runner = null;
175             if (animationHandler != null) {
176                 runner = new IRecentsAnimationRunner.Stub() {
177                     @Override
178                     public void onAnimationStart(IRecentsAnimationController controller,
179                             RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
180                             Rect homeContentInsets, Rect minimizedHomeBounds) {
181                         final RecentsAnimationControllerCompat controllerCompat =
182                                 new RecentsAnimationControllerCompat(controller);
183                         final RemoteAnimationTargetCompat[] appsCompat =
184                                 RemoteAnimationTargetCompat.wrap(apps);
185                         final RemoteAnimationTargetCompat[] wallpapersCompat =
186                                 RemoteAnimationTargetCompat.wrap(wallpapers);
187                         animationHandler.onAnimationStart(controllerCompat, appsCompat,
188                                 wallpapersCompat, homeContentInsets, minimizedHomeBounds);
189                     }
190 
191                     @Override
192                     public void onAnimationCanceled(TaskSnapshot taskSnapshot) {
193                         animationHandler.onAnimationCanceled(
194                                 taskSnapshot != null ? new ThumbnailData(taskSnapshot) : null);
195                     }
196 
197                     @Override
198                     public void onTaskAppeared(RemoteAnimationTarget app) {
199                         animationHandler.onTaskAppeared(new RemoteAnimationTargetCompat(app));
200                     }
201                 };
202             }
203             getService().startRecentsActivity(intent, eventTime, runner);
204             return true;
205         } catch (Exception e) {
206             return false;
207         }
208     }
209 
210     /**
211      * Cancels the remote recents animation started from {@link #startRecentsActivity}.
212      */
cancelRecentsAnimation(boolean restoreHomeRootTaskPosition)213     public void cancelRecentsAnimation(boolean restoreHomeRootTaskPosition) {
214         try {
215             getService().cancelRecentsAnimation(restoreHomeRootTaskPosition);
216         } catch (RemoteException e) {
217             Log.e(TAG, "Failed to cancel recents animation", e);
218         }
219     }
220 
221     /**
222      * Starts a task from Recents.
223      *
224      * @param resultCallback The result success callback
225      * @param resultCallbackHandler The handler to receive the result callback
226      */
startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options, Consumer<Boolean> resultCallback, Handler resultCallbackHandler)227     public void startActivityFromRecentsAsync(Task.TaskKey taskKey, ActivityOptions options,
228             Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
229         final boolean result = startActivityFromRecents(taskKey, options);
230         if (resultCallback != null) {
231             resultCallbackHandler.post(new Runnable() {
232                 @Override
233                 public void run() {
234                     resultCallback.accept(result);
235                 }
236             });
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         ActivityOptionsCompat.addTaskInfo(options, taskKey);
245         return startActivityFromRecents(taskKey.id, options);
246     }
247 
248     /**
249      * Starts a task from Recents synchronously.
250      */
startActivityFromRecents(int taskId, ActivityOptions options)251     public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
252         try {
253             Bundle optsBundle = options == null ? null : options.toBundle();
254             getService().startActivityFromRecents(taskId, optsBundle);
255             return true;
256         } catch (Exception e) {
257             return false;
258         }
259     }
260 
261     /**
262      * @deprecated use {@link TaskStackChangeListeners#registerTaskStackListener}
263      */
registerTaskStackListener(TaskStackChangeListener listener)264     public void registerTaskStackListener(TaskStackChangeListener listener) {
265         TaskStackChangeListeners.getInstance().registerTaskStackListener(listener);
266     }
267 
268     /**
269      * @deprecated use {@link TaskStackChangeListeners#unregisterTaskStackListener}
270      */
unregisterTaskStackListener(TaskStackChangeListener listener)271     public void unregisterTaskStackListener(TaskStackChangeListener listener) {
272         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(listener);
273     }
274 
275     /**
276      * Requests that the system close any open system windows (including other SystemUI).
277      */
closeSystemWindows(final String reason)278     public void closeSystemWindows(final String reason) {
279         try {
280             ActivityManager.getService().closeSystemDialogs(reason);
281         } catch (RemoteException e) {
282             Log.w(TAG, "Failed to close system windows", e);
283         }
284     }
285 
286     /**
287      * Removes a task by id.
288      */
removeTask(final int taskId)289     public void removeTask(final int taskId) {
290         try {
291             getService().removeTask(taskId);
292         } catch (RemoteException e) {
293             Log.w(TAG, "Failed to remove task=" + taskId, e);
294         }
295     }
296 
297     /**
298      * Removes all the recent tasks.
299      */
removeAllRecentTasks()300     public void removeAllRecentTasks() {
301         try {
302             getService().removeAllVisibleRecentTasks();
303         } catch (RemoteException e) {
304             Log.w(TAG, "Failed to remove all tasks", e);
305         }
306     }
307 
308     /**
309      * @return whether screen pinning is active.
310      */
isScreenPinningActive()311     public boolean isScreenPinningActive() {
312         try {
313             return getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED;
314         } catch (RemoteException e) {
315             return false;
316         }
317     }
318 
319     /**
320      * @return whether screen pinning is enabled.
321      */
isScreenPinningEnabled()322     public boolean isScreenPinningEnabled() {
323         final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
324         return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
325     }
326 
327     /**
328      * @return whether there is currently a locked task (ie. in screen pinning).
329      */
isLockToAppActive()330     public boolean isLockToAppActive() {
331         try {
332             return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
333         } catch (RemoteException e) {
334             return false;
335         }
336     }
337 
338     /**
339      * @return whether lock task mode is active in kiosk-mode (not screen pinning).
340      */
isLockTaskKioskModeActive()341     public boolean isLockTaskKioskModeActive() {
342         try {
343             return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
344         } catch (RemoteException e) {
345             return false;
346         }
347     }
348 
349     /**
350      * Shows a voice session identified by {@code token}
351      * @return true if the session was shown, false otherwise
352      */
showVoiceSession(IBinder token, Bundle args, int flags)353     public boolean showVoiceSession(IBinder token, Bundle args, int flags) {
354         IVoiceInteractionManagerService service = IVoiceInteractionManagerService.Stub.asInterface(
355                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
356         if (service == null) {
357             return false;
358         }
359         args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
360 
361         try {
362             return service.showSessionFromSession(token, args, flags);
363         } catch (RemoteException e) {
364             return false;
365         }
366     }
367 
368     /**
369      * Returns true if the system supports freeform multi-window.
370      */
supportsFreeformMultiWindow(Context context)371     public boolean supportsFreeformMultiWindow(Context context) {
372         final boolean freeformDevOption = Settings.Global.getInt(context.getContentResolver(),
373                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
374         return ActivityTaskManager.supportsMultiWindow(context)
375                 && (context.getPackageManager().hasSystemFeature(
376                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
377                 || freeformDevOption);
378     }
379 
380     /**
381      * Returns true if the running task represents the home task
382      */
isHomeTask(RunningTaskInfo info)383     public static boolean isHomeTask(RunningTaskInfo info) {
384         return info.configuration.windowConfiguration.getActivityType()
385                 == WindowConfiguration.ACTIVITY_TYPE_HOME;
386     }
387 }
388