/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.window; import android.annotation.BinderThread; import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.app.ActivityManager; import android.app.CameraCompatTaskInfo.CameraCompatControlState; import android.os.IBinder; import android.os.RemoteException; import android.view.SurfaceControl; import com.android.internal.annotations.VisibleForTesting; import java.util.List; import java.util.concurrent.Executor; /** * Interface for ActivityTaskManager/WindowManager to delegate control of tasks. * @hide */ @TestApi public class TaskOrganizer extends WindowOrganizer { private final ITaskOrganizerController mTaskOrganizerController; // Callbacks WM Core are posted on this executor if it isn't null, otherwise direct calls are // made on the incoming binder call. private final Executor mExecutor; public TaskOrganizer() { this(null /*taskOrganizerController*/, null /*executor*/); } /** @hide */ @VisibleForTesting public TaskOrganizer(ITaskOrganizerController taskOrganizerController, Executor executor) { mExecutor = executor != null ? executor : Runnable::run; mTaskOrganizerController = taskOrganizerController != null ? taskOrganizerController : getController(); } /** * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode. * * @return a list of the tasks that should be managed by the organizer, not including tasks * created via {@link #createRootTask}. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @CallSuper @NonNull public List registerOrganizer() { try { return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Unregisters a previously registered task organizer. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @CallSuper public void unregisterOrganizer() { try { mTaskOrganizerController.unregisterTaskOrganizer(mInterface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Called when a Task is starting and the system would like to show a UI to indicate that an * application is starting. The client is responsible to add/remove the starting window if it * has create a starting window for the Task. * * @param info The information about the Task that's available * @hide */ @BinderThread public void addStartingWindow(@NonNull StartingWindowInfo info) {} /** * Called when the Task want to remove the starting window. * @param removalInfo The information used to remove the starting window. * @hide */ @BinderThread public void removeStartingWindow(@NonNull StartingWindowRemovalInfo removalInfo) {} /** * Called when the Task want to copy the splash screen. */ @BinderThread public void copySplashScreenView(int taskId) {} /** * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has * removed the splash screen view. * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int) * @see SplashScreenView#remove() */ @BinderThread public void onAppSplashScreenViewRemoved(int taskId) { } /** * Called when a task with the registered windowing mode can be controlled by this task * organizer. For non-root tasks, the leash may initially be hidden so it is up to the organizer * to show this task. */ @BinderThread public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo, @NonNull SurfaceControl leash) {} @BinderThread public void onTaskVanished(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} @BinderThread public void onTaskInfoChanged(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} @BinderThread public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {} /** @hide */ @BinderThread public void onImeDrawnOnTask(int taskId) {} /** * Creates a persistent root task in WM for a particular windowing-mode. * @param displayId The display to create the root task on. * @param windowingMode Windowing mode to put the root task in. * @param launchCookie Launch cookie to associate with the task so that is can be identified * when the {@link ITaskOrganizer#onTaskAppeared} callback is called. * @param removeWithTaskOrganizer True if this task should be removed when organizer destroyed. * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie, boolean removeWithTaskOrganizer) { try { mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie, removeWithTaskOrganizer); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Creates a persistent root task in WM for a particular windowing-mode. * @param displayId The display to create the root task on. * @param windowingMode Windowing mode to put the root task in. * @param launchCookie Launch cookie to associate with the task so that is can be identified * when the {@link ITaskOrganizer#onTaskAppeared} callback is called. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) { createRootTask(displayId, windowingMode, launchCookie, false /* removeWithTaskOrganizer */); } /** Deletes a persistent root task in WM */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull WindowContainerToken task) { try { return mTaskOrganizerController.deleteRootTask(task); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Gets direct child tasks (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable @SuppressLint("NullableCollection") public List getChildTasks( @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) { try { return mTaskOrganizerController.getChildTasks(parent, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Gets all root tasks on a display (ordered from top-to-bottom) */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable @SuppressLint("NullableCollection") public List getRootTasks( int displayId, @NonNull int[] activityTypes) { try { return mTaskOrganizerController.getRootTasks(displayId, activityTypes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Get the {@link WindowContainerToken} of the task which contains the current ime target */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @Nullable public WindowContainerToken getImeTarget(int display) { try { return mTaskOrganizerController.getImeTarget(display); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Requests that the given task organizer is notified when back is pressed on the root activity * of one of its controlled tasks. */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task, boolean interceptBackPressed) { try { mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(task, interceptBackPressed); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Restarts the top activity in the given task by killing its process if it is visible. * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void restartTaskTopActivityProcessIfVisible(@NonNull WindowContainerToken task) { try { mTaskOrganizerController.restartTaskTopActivityProcessIfVisible(task); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Updates a state of camera compat control for stretched issues in the viewfinder. * @hide */ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void updateCameraCompatControlState(@NonNull WindowContainerToken task, @CameraCompatControlState int state) { try { mTaskOrganizerController.updateCameraCompatControlState(task, state); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Gets the executor to run callbacks on. * @hide */ @NonNull public Executor getExecutor() { return mExecutor; } private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() { @Override public void addStartingWindow(StartingWindowInfo windowInfo) { mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo)); } @Override public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) { mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(removalInfo)); } @Override public void copySplashScreenView(int taskId) { mExecutor.execute(() -> TaskOrganizer.this.copySplashScreenView(taskId)); } @Override public void onAppSplashScreenViewRemoved(int taskId) { mExecutor.execute(() -> TaskOrganizer.this.onAppSplashScreenViewRemoved(taskId)); } @Override public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { mExecutor.execute(() -> TaskOrganizer.this.onTaskAppeared(taskInfo, leash)); } @Override public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { mExecutor.execute(() -> TaskOrganizer.this.onTaskVanished(taskInfo)); } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { mExecutor.execute(() -> TaskOrganizer.this.onTaskInfoChanged(info)); } @Override public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) { mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info)); } @Override public void onImeDrawnOnTask(int taskId) { mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId)); } }; @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) private ITaskOrganizerController getController() { try { return getWindowOrganizerController().getTaskOrganizerController(); } catch (RemoteException e) { return null; } } }