• 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.os.Bundle;
39 import android.os.IBinder;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import android.os.SystemClock;
43 import android.provider.Settings;
44 import android.util.Log;
45 import android.view.Display;
46 import android.window.TaskSnapshot;
47 
48 import com.android.internal.app.IVoiceInteractionManagerService;
49 import com.android.systemui.shared.recents.model.Task;
50 import com.android.systemui.shared.recents.model.ThumbnailData;
51 
52 import java.util.List;
53 
54 public class ActivityManagerWrapper {
55 
56     private static final String TAG = "ActivityManagerWrapper";
57     private static final int NUM_RECENT_ACTIVITIES_REQUEST = 3;
58     private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
59 
60     // Should match the values in PhoneWindowManager
61     public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
62     public static final String CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY = "homekey";
63 
64     // Should match the value in AssistManager
65     private static final String INVOCATION_TIME_MS_KEY = "invocation_time_ms";
66 
67     private final ActivityTaskManager mAtm = ActivityTaskManager.getInstance();
ActivityManagerWrapper()68     private ActivityManagerWrapper() { }
69 
getInstance()70     public static ActivityManagerWrapper getInstance() {
71         return sInstance;
72     }
73 
74     /**
75      * @return the current user's id.
76      */
getCurrentUserId()77     public int getCurrentUserId() {
78         UserInfo ui;
79         try {
80             ui = ActivityManager.getService().getCurrentUser();
81             return ui != null ? ui.id : 0;
82         } catch (RemoteException e) {
83             throw e.rethrowFromSystemServer();
84         }
85     }
86 
87     /**
88      * @return the top running task (can be {@code null}).
89      */
getRunningTask()90     public ActivityManager.RunningTaskInfo getRunningTask() {
91         return getRunningTask(false /* filterVisibleRecents */);
92     }
93 
94     /**
95      * @return the top running task filtering only for tasks that can be visible in the recent tasks
96      * list (can be {@code null}).
97      */
getRunningTask(boolean filterOnlyVisibleRecents)98     public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
99         // Note: The set of running tasks from the system is ordered by recency
100         List<ActivityManager.RunningTaskInfo> tasks =
101                 mAtm.getTasks(1, filterOnlyVisibleRecents);
102         if (tasks.isEmpty()) {
103             return null;
104         }
105         return tasks.get(0);
106     }
107 
108     /**
109      * @see #getRunningTasks(boolean , int)
110      */
getRunningTasks(boolean filterOnlyVisibleRecents)111     public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents) {
112         return getRunningTasks(filterOnlyVisibleRecents, Display.INVALID_DISPLAY);
113     }
114 
115     /**
116      * We ask for {@link #NUM_RECENT_ACTIVITIES_REQUEST} activities because when in split screen,
117      * we'll get back 2 activities for each split app and one for launcher. Launcher might be more
118      * "recently" used than one of the split apps so if we only request 2 tasks, then we might miss
119      * out on one of the split apps
120      *
121      * @return an array of up to {@link #NUM_RECENT_ACTIVITIES_REQUEST} running tasks
122      *         filtering only for tasks that can be visible in the recent tasks list.
123      */
getRunningTasks(boolean filterOnlyVisibleRecents, int displayId)124     public ActivityManager.RunningTaskInfo[] getRunningTasks(boolean filterOnlyVisibleRecents,
125             int displayId) {
126         // Note: The set of running tasks from the system is ordered by recency
127         List<ActivityManager.RunningTaskInfo> tasks =
128                 mAtm.getTasks(NUM_RECENT_ACTIVITIES_REQUEST,
129                         filterOnlyVisibleRecents, /* keepInExtras= */ false, displayId);
130         return tasks.toArray(new RunningTaskInfo[tasks.size()]);
131     }
132 
133     /**
134      * @return the task snapshot for the given {@param taskId}.
135      */
getTaskThumbnail(int taskId, boolean isLowResolution)136     public @NonNull ThumbnailData getTaskThumbnail(int taskId, boolean isLowResolution) {
137         TaskSnapshot snapshot = null;
138         try {
139             snapshot = getService().getTaskSnapshot(taskId, isLowResolution);
140         } catch (RemoteException e) {
141             Log.w(TAG, "Failed to retrieve task snapshot", e);
142         }
143         if (snapshot != null) {
144             return ThumbnailData.fromSnapshot(snapshot);
145         } else {
146             return new ThumbnailData();
147         }
148     }
149 
150 
151     /**
152      * Requests for a new snapshot to be taken for the given task, stores it in the cache, and
153      * returns a {@link ThumbnailData} with the result.
154      */
155     @NonNull
takeTaskThumbnail(int taskId)156     public ThumbnailData takeTaskThumbnail(int taskId) {
157         TaskSnapshot snapshot = null;
158         try {
159             snapshot = getService().takeTaskSnapshot(taskId, /* updateCache= */ true);
160         } catch (RemoteException e) {
161             Log.w(TAG, "Failed to take task snapshot", e);
162         }
163         if (snapshot != null) {
164             return ThumbnailData.fromSnapshot(snapshot);
165         } else {
166             return new ThumbnailData();
167         }
168     }
169 
170     /**
171      * Removes the outdated snapshot of home task.
172      *
173      * @param homeActivity The home task activity, or null if you have the
174      *                     {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS} permission and
175      *                     want us to find the home task for you.
176      */
invalidateHomeTaskSnapshot(@ullable final Activity homeActivity)177     public void invalidateHomeTaskSnapshot(@Nullable final Activity homeActivity) {
178         try {
179             ActivityClient.getInstance().invalidateHomeTaskSnapshot(
180                     homeActivity == null ? null : homeActivity.getActivityToken());
181         } catch (Throwable e) {
182             Log.w(TAG, "Failed to invalidate home snapshot", e);
183         }
184     }
185 
186     /**
187      * Preloads the recents activity. The caller should manage the thread on which this is called.
188      */
preloadRecentsActivity(Intent intent)189     public void preloadRecentsActivity(Intent intent) {
190         try {
191             getService().preloadRecentsActivity(intent);
192         } catch (Exception e) {
193             Log.w(TAG, "Failed to preload recents activity", e);
194         }
195     }
196 
197     /**
198      * Starts a task from Recents synchronously.
199      */
startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options)200     public boolean startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options) {
201         return startActivityFromRecents(taskKey.id, options);
202     }
203 
204     /**
205      * Starts a task from Recents synchronously.
206      */
startActivityFromRecents(int taskId, ActivityOptions options)207     public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
208         try {
209             Bundle optsBundle = options == null ? null : options.toBundle();
210             return ActivityManager.isStartResultSuccessful(
211                     getService().startActivityFromRecents(
212                             taskId, optsBundle));
213         } catch (Exception e) {
214             return false;
215         }
216     }
217 
218     /**
219      * Requests that the system close any open system windows (including other SystemUI).
220      */
closeSystemWindows(final String reason)221     public void closeSystemWindows(final String reason) {
222         try {
223             ActivityManager.getService().closeSystemDialogs(reason);
224         } catch (RemoteException e) {
225             Log.w(TAG, "Failed to close system windows", e);
226         }
227     }
228 
229     /**
230      * Sets whether or not the specified task is perceptible.
231      */
setTaskIsPerceptible(int taskId, boolean isPerceptible)232     public boolean setTaskIsPerceptible(int taskId, boolean isPerceptible) {
233         try {
234             return getService().setTaskIsPerceptible(taskId, isPerceptible);
235         } catch (RemoteException e) {
236             throw e.rethrowFromSystemServer();
237         }
238     }
239 
240     /**
241      * Removes a task by id.
242      */
removeTask(final int taskId)243     public void removeTask(final int taskId) {
244         try {
245             getService().removeTask(taskId);
246         } catch (RemoteException e) {
247             Log.w(TAG, "Failed to remove task=" + taskId, e);
248         }
249     }
250 
251     /**
252      * Removes all the recent tasks.
253      */
removeAllRecentTasks()254     public void removeAllRecentTasks() {
255         try {
256             getService().removeAllVisibleRecentTasks();
257         } catch (RemoteException e) {
258             Log.w(TAG, "Failed to remove all tasks", e);
259         }
260     }
261 
262     /**
263      * @return whether screen pinning is enabled.
264      */
isScreenPinningEnabled()265     public boolean isScreenPinningEnabled() {
266         final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver();
267         return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0;
268     }
269 
270     /**
271      * @return whether there is currently a locked task (ie. in screen pinning).
272      */
isLockToAppActive()273     public boolean isLockToAppActive() {
274         try {
275             return getService().getLockTaskModeState() != LOCK_TASK_MODE_NONE;
276         } catch (RemoteException e) {
277             return false;
278         }
279     }
280 
281     /**
282      * @return whether lock task mode is active in kiosk-mode (not screen pinning).
283      */
isLockTaskKioskModeActive()284     public boolean isLockTaskKioskModeActive() {
285         try {
286             return getService().getLockTaskModeState() == LOCK_TASK_MODE_LOCKED;
287         } catch (RemoteException e) {
288             return false;
289         }
290     }
291 
292     /**
293      * Shows a voice session identified by {@code token}
294      * @return true if the session was shown, false otherwise
295      */
showVoiceSession(IBinder token, @NonNull Bundle args, int flags, @Nullable String attributionTag)296     public boolean showVoiceSession(IBinder token, @NonNull Bundle args, int flags,
297             @Nullable String attributionTag) {
298         IVoiceInteractionManagerService service = IVoiceInteractionManagerService.Stub.asInterface(
299                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
300         if (service == null) {
301             return false;
302         }
303         args.putLong(INVOCATION_TIME_MS_KEY, SystemClock.elapsedRealtime());
304 
305         try {
306             return service.showSessionFromSession(token, args, flags, attributionTag);
307         } catch (RemoteException e) {
308             return false;
309         }
310     }
311 
312     /**
313      * Returns true if the system supports freeform multi-window.
314      */
supportsFreeformMultiWindow(Context context)315     public boolean supportsFreeformMultiWindow(Context context) {
316         final boolean freeformDevOption = Settings.Global.getInt(context.getContentResolver(),
317                 Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
318         return ActivityTaskManager.supportsMultiWindow(context)
319                 && (context.getPackageManager().hasSystemFeature(
320                 PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
321                 || freeformDevOption);
322     }
323 
324     /**
325      * Returns true if the running task represents the home task
326      */
isHomeTask(RunningTaskInfo info)327     public static boolean isHomeTask(RunningTaskInfo info) {
328         return info.configuration.windowConfiguration.getActivityType()
329                 == WindowConfiguration.ACTIVITY_TYPE_HOME;
330     }
331 
isRunningInTestHarness()332     public boolean isRunningInTestHarness() {
333         return ActivityManager.isRunningInTestHarness()
334                 || ActivityManager.isRunningInUserTestHarness();
335     }
336 }
337