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