From 568f9f41c63f34a74c4e9e225ace29b124277a81 Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Sat, 21 Mar 2020 22:27:35 -0700 Subject: [PATCH] Introduce WindowOrganizer WM currently only allows the organization of tasks, however we will soon be allowing the organization of DisplayAreas. To help with the code structure, we are introducing WindowOrganizer interface which will contain common APIs for all types of windows organizers (e.g. applyTransaction) and also be the interfaece for getting the controller for other organizers. Test: they pass! Bug: 147406652 Bug: 152113464 Bug: 152117221 Change-Id: Id2797b288ce92430206c25345d60e7b0e3be98c8 --- .../java/android/app/ActivityTaskManager.java | 19 - .../android/app/IActivityTaskManager.aidl | 9 +- core/java/android/window/ITaskOrganizer.aidl | 37 +- .../window/ITaskOrganizerController.aidl | 14 - .../IWindowContainerTransactionCallback.aidl | 28 ++ .../window/IWindowOrganizerController.aidl | 46 +++ core/java/android/window/WindowOrganizer.java | 157 ++++++++ .../systemui/pip/PipTaskOrganizer.java | 9 +- .../systemui/pip/phone/PipManager.java | 5 +- .../android/systemui/pip/tv/PipManager.java | 5 +- .../systemui/stackdivider/Divider.java | 17 +- .../SplitScreenTaskOrganizer.java | 17 +- .../stackdivider/WindowManagerProxy.java | 38 +- .../server/wm/ActivityTaskManagerService.java | 19 +- .../android/server/wm/DisplayRotation.java | 3 +- .../server/wm/TaskOrganizerController.java | 284 +------------- .../server/wm/WindowOrganizerController.java | 347 ++++++++++++++++++ .../server/wm/ActivityStarterTests.java | 3 - .../android/server/wm/TaskOrganizerTests.java | 40 +- .../TaskOrganizerMultiWindowTest.java | 40 +- .../test/taskembed/TaskOrganizerPipTest.java | 12 +- 21 files changed, 689 insertions(+), 460 deletions(-) create mode 100644 core/java/android/window/IWindowContainerTransactionCallback.aidl create mode 100644 core/java/android/window/IWindowOrganizerController.aidl create mode 100644 core/java/android/window/WindowOrganizer.java create mode 100644 services/core/java/com/android/server/wm/WindowOrganizerController.java diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java index c9673f59183af..1b941defba42d 100644 --- a/core/java/android/app/ActivityTaskManager.java +++ b/core/java/android/app/ActivityTaskManager.java @@ -30,7 +30,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Singleton; -import android.window.ITaskOrganizerController; import java.util.List; @@ -159,24 +158,6 @@ public class ActivityTaskManager { } }; - /** @hide */ - @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) - public static ITaskOrganizerController getTaskOrganizerController() { - return ITaskOrganizerControllerSingleton.get(); - } - - private static final Singleton ITaskOrganizerControllerSingleton = - new Singleton() { - @Override - protected ITaskOrganizerController create() { - try { - return getService().getTaskOrganizerController(); - } catch (RemoteException e) { - return null; - } - } - }; - /** * Sets the windowing mode for a specific task. Only works on tasks of type * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index ab5c6788969ae..03717ecd40380 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -29,7 +29,6 @@ import android.app.IProcessObserver; import android.app.IRequestFinishCallback; import android.app.IServiceConnection; import android.app.IStopUserCallback; -import android.window.ITaskOrganizerController; import android.app.ITaskStackListener; import android.app.IUiAutomationConnection; import android.app.IUidObserver; @@ -69,9 +68,9 @@ import android.os.StrictMode; import android.os.WorkSource; import android.service.voice.IVoiceInteractionSession; import android.view.IRecentsAnimationRunner; -import android.window.ITaskOrganizer; import android.view.RemoteAnimationDefinition; import android.view.RemoteAnimationAdapter; +import android.window.IWindowOrganizerController; import com.android.internal.app.IVoiceInteractor; import com.android.internal.os.IResultReceiver; import com.android.internal.policy.IKeyguardDismissCallback; @@ -340,10 +339,8 @@ interface IActivityTaskManager { in Rect tempDockedTaskInsetBounds, in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds); - /** - * Returns an interface enabling the management of task organizers. - */ - ITaskOrganizerController getTaskOrganizerController(); + /** Returns an interface enabling the management of window organizers. */ + IWindowOrganizerController getWindowOrganizerController(); /** * Sets whether we are currently in an interactive split screen resize operation where we diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl index b2da23949005f..0a04462c42097 100644 --- a/core/java/android/window/ITaskOrganizer.aidl +++ b/core/java/android/window/ITaskOrganizer.aidl @@ -1,19 +1,18 @@ -/* //device/java/android/android/view/ITaskOrganizer.aidl -** -** Copyright 2019, 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. -*/ +/* + * Copyright (C) 2019 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; @@ -29,12 +28,6 @@ oneway interface ITaskOrganizer { void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo); void taskVanished(in ActivityManager.RunningTaskInfo taskInfo); - /** - * Called upon completion of - * ActivityTaskManagerService#applyTaskOrganizerTransaction - */ - void transactionReady(int id, in SurfaceControl.Transaction t); - /** * Will fire when core attributes of a Task's info change. Relevant properties include the * {@link WindowConfiguration.ActivityType} and whether it is resizable. diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl index e8af8e196bede..a8b6aae80dcee 100644 --- a/core/java/android/window/ITaskOrganizerController.aidl +++ b/core/java/android/window/ITaskOrganizerController.aidl @@ -36,20 +36,6 @@ interface ITaskOrganizerController { */ void unregisterTaskOrganizer(ITaskOrganizer organizer); - /** - * Apply multiple WindowContainer operations at once. - * @param organizer If non-null this transaction will use the synchronization - * scheme described in BLASTSyncEngine.java. The SurfaceControl transaction - * containing the effects of this WindowContainer transaction will be passed - * to the organizers Transaction ready callback. If null the transaction - * will apply with non particular synchronization constraints (other than - * it will all apply at once). - * @return If organizer was non-null returns an ID for the sync operation which will - * later be passed to transactionReady. This lets TaskOrganizer implementations - * differentiate overlapping sync operations. - */ - int applyContainerTransaction(in WindowContainerTransaction t, ITaskOrganizer organizer); - /** Creates a persistent root task in WM for a particular windowing-mode. */ ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode); diff --git a/core/java/android/window/IWindowContainerTransactionCallback.aidl b/core/java/android/window/IWindowContainerTransactionCallback.aidl new file mode 100644 index 0000000000000..0579932f0c5f4 --- /dev/null +++ b/core/java/android/window/IWindowContainerTransactionCallback.aidl @@ -0,0 +1,28 @@ +/* + * 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.view.SurfaceControl; + +/** + * See WindowOrganizer#applyTransaction. + * {@hide} + */ +oneway interface IWindowContainerTransactionCallback { + /** Called upon completion of WindowOrganizer#applyTransaction */ + void transactionReady(int id, in SurfaceControl.Transaction t); +} diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl new file mode 100644 index 0000000000000..4b47924dc5a68 --- /dev/null +++ b/core/java/android/window/IWindowOrganizerController.aidl @@ -0,0 +1,46 @@ +/** + * 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.window.ITaskOrganizerController; +import android.window.IWindowContainerTransactionCallback; +import android.window.WindowContainerTransaction; + +/** @hide */ +interface IWindowOrganizerController { + + /** + * Apply multiple WindowContainer operations at once. + * @param t The transaction to apply. + */ + void applyTransaction(in WindowContainerTransaction t); + + /** + * Apply multiple WindowContainer operations at once. + * @param t The transaction to apply. + * @param callback This transaction will use the synchronization scheme described in + * BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this + * WindowContainer transaction will be passed to this callback when ready. + * @return An ID for the sync operation which will later be passed to transactionReady callback. + * This lets the caller differentiate overlapping sync operations. + */ + int applySyncTransaction(in WindowContainerTransaction t, + in IWindowContainerTransactionCallback callback); + + /** @return An interface enabling the management of task organizers. */ + ITaskOrganizerController getTaskOrganizerController(); +} diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java new file mode 100644 index 0000000000000..b8969c1623099 --- /dev/null +++ b/core/java/android/window/WindowOrganizer.java @@ -0,0 +1,157 @@ +/* + * 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.RequiresPermission; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.os.RemoteException; +import android.util.Singleton; + +import java.util.List; + +/** + * Class for organizing specific types of windows like Tasks and DisplayAreas + * + * @hide + */ +public class WindowOrganizer { + + /** + * Apply multiple WindowContainer operations at once. + * @param t The transaction to apply. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static void applyTransaction(WindowContainerTransaction t) throws RemoteException { + getWindowOrganizerController().applyTransaction(t); + } + + /** + * Apply multiple WindowContainer operations at once. + * @param t The transaction to apply. + * @param callback This transaction will use the synchronization scheme described in + * BLASTSyncEngine.java. The SurfaceControl transaction containing the effects of this + * WindowContainer transaction will be passed to this callback when ready. + * @return An ID for the sync operation which will later be passed to transactionReady callback. + * This lets the caller differentiate overlapping sync operations. + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static int applySyncTransaction(WindowContainerTransaction t, + IWindowContainerTransactionCallback callback) throws RemoteException { + return getWindowOrganizerController().applySyncTransaction(t, callback); + } + + /** @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + private static IWindowOrganizerController getWindowOrganizerController() { + return IWindowOrganizerControllerSingleton.get(); + } + + private static final Singleton IWindowOrganizerControllerSingleton = + new Singleton() { + @Override + protected IWindowOrganizerController create() { + try { + return ActivityTaskManager.getService().getWindowOrganizerController(); + } catch (RemoteException e) { + return null; + } + } + }; + + public static class TaskOrganizer { + + /** + * Register a TaskOrganizer to manage tasks as they enter the given windowing mode. + * If there was already a TaskOrganizer for this windowing mode it will be evicted + * and receive taskVanished callbacks in the process. + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static void registerOrganizer(ITaskOrganizer organizer, int windowingMode) + throws RemoteException { + getController().registerTaskOrganizer(organizer, windowingMode); + } + + /** Unregisters a previously registered task organizer. */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static void unregisterOrganizer(ITaskOrganizer organizer) throws RemoteException { + getController().unregisterTaskOrganizer(organizer); + } + + /** Creates a persistent root task in WM for a particular windowing-mode. */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static ActivityManager.RunningTaskInfo createRootTask( + int displayId, int windowingMode) throws RemoteException { + return getController().createRootTask(displayId, windowingMode); + } + + /** Deletes a persistent root task in WM */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static boolean deleteRootTask(IWindowContainer task) throws RemoteException { + return getController().deleteRootTask(task); + } + + /** Gets direct child tasks (ordered from top-to-bottom) */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static List getChildTasks(IWindowContainer parent, + int[] activityTypes) throws RemoteException { + return getController().getChildTasks(parent, activityTypes); + } + + /** Gets all root tasks on a display (ordered from top-to-bottom) */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static List getRootTasks( + int displayId, int[] activityTypes) throws RemoteException { + return getController().getRootTasks(displayId, activityTypes); + } + + /** Get the root task which contains the current ime target */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static IWindowContainer getImeTarget(int display) throws RemoteException { + return getController().getImeTarget(display); + } + + /** + * Set's the root task to launch new tasks into on a display. {@code null} means no launch + * root and thus new tasks just end up directly on the display. + */ + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public static void setLaunchRoot(int displayId, IWindowContainer root) + throws RemoteException { + getController().setLaunchRoot(displayId, root); + } + + private static ITaskOrganizerController getController() { + return ITaskOrganizerControllerSingleton.get(); + } + + private static final Singleton ITaskOrganizerControllerSingleton = + new Singleton() { + @Override + protected ITaskOrganizerController create() { + try { + return getWindowOrganizerController().getTaskOrganizerController(); + } catch (RemoteException e) { + return null; + } + } + }; + + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 195050e41278d..7f14645424da4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -42,6 +42,7 @@ import android.window.ITaskOrganizer; import android.window.IWindowContainer; import android.view.SurfaceControl; import android.window.WindowContainerTransaction; +import android.window.WindowOrganizer; import com.android.internal.os.SomeArgs; import com.android.systemui.R; @@ -75,7 +76,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { private final Handler mMainHandler; private final Handler mUpdateHandler; - private final ITaskOrganizerController mTaskOrganizerController; private final PipBoundsHandler mPipBoundsHandler; private final PipAnimationController mPipAnimationController; private final List mPipTransitionCallbacks = new ArrayList<>(); @@ -181,7 +181,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper) { mMainHandler = new Handler(Looper.getMainLooper()); mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks); - mTaskOrganizerController = ActivityTaskManager.getTaskOrganizerController(); mPipBoundsHandler = boundsHandler; mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); @@ -257,10 +256,6 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { mInPip = false; } - @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { - } - @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { final PictureInPictureParams newParams = info.pictureInPictureParams; @@ -415,7 +410,7 @@ public class PipTaskOrganizer extends ITaskOrganizer.Stub { wct.setBounds(mToken, taskBounds); } wct.setBoundsChangeTransaction(mToken, tx); - mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */); + WindowOrganizer.applyTransaction(wct); } catch (RemoteException e) { Log.e(TAG, "Failed to apply container transaction", e); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index a0dff3f981739..e89ce2e3a56f4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -18,6 +18,7 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -35,6 +36,7 @@ import android.util.Pair; import android.view.DisplayInfo; import android.view.IPinnedStackController; import android.window.WindowContainerTransaction; +import android.window.WindowOrganizer; import com.android.systemui.Dependency; import com.android.systemui.UiOffloadThread; @@ -248,8 +250,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mPipBoundsHandler.onDisplayInfoChanged(displayInfo); try { - ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer( - mPipTaskOrganizer, WINDOWING_MODE_PINNED); + TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED); ActivityManager.StackInfo stackInfo = activityTaskManager.getStackInfo( WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED); if (stackInfo != null) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 050acd5a87285..2dcf1f89c3ec3 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -19,6 +19,7 @@ package com.android.systemui.pip.tv; import static android.app.ActivityTaskManager.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManager.StackInfo; @@ -44,6 +45,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.view.DisplayInfo; +import android.window.WindowOrganizer; import com.android.systemui.Dependency; import com.android.systemui.R; @@ -293,8 +295,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio try { WindowManagerWrapper.getInstance().addPinnedStackListener(mPinnedStackListener); - ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer( - mPipTaskOrganizer, WINDOWING_MODE_PINNED); + TaskOrganizer.registerOrganizer(mPipTaskOrganizer, WINDOWING_MODE_PINNED); } catch (RemoteException e) { Log.e(TAG, "Failed to register pinned stack listener", e); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 3d5281247f63f..01498f9333838 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -20,11 +20,11 @@ import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED; import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.WindowOrganizer.TaskOrganizer; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; -import android.app.ActivityTaskManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; @@ -38,6 +38,7 @@ import android.view.SurfaceControl; import android.view.SurfaceSession; import android.view.View; import android.window.WindowContainerTransaction; +import android.window.WindowOrganizer; import androidx.annotation.Nullable; @@ -177,8 +178,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, private boolean getSecondaryHasFocus(int displayId) { try { - IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController() - .getImeTarget(displayId); + IWindowContainer imeSplit = TaskOrganizer.getImeTarget(displayId); return imeSplit != null && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder()); } catch (RemoteException e) { @@ -267,8 +267,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED); } try { - ActivityTaskManager.getTaskOrganizerController() - .applyContainerTransaction(wct, null /* organizer */); + WindowOrganizer.applyTransaction(wct); } catch (RemoteException e) { } @@ -474,13 +473,12 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, mImeController.addPositionProcessor(mImePositionProcessor); mDisplayController.addDisplayChangingController(mRotationController); try { - mSplits.init(ActivityTaskManager.getTaskOrganizerController(), mSurfaceSession); + mSplits.init(mSurfaceSession); // Set starting tile bounds based on middle target final WindowContainerTransaction tct = new WindowContainerTransaction(); int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position; mSplitLayout.resizeSplits(midPos, tct); - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(tct, - null /* organizer */); + WindowOrganizer.applyTransaction(tct); } catch (Exception e) { Slog.e(TAG, "Failed to register docked stack listener", e); } @@ -499,8 +497,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks, final WindowContainerTransaction tct = new WindowContainerTransaction(); mSplitLayout.resizeSplits(midPos, tct); try { - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(tct, - null /* organizer */); + WindowOrganizer.applyTransaction(tct); } catch (RemoteException e) { } } else if (mRotateSplitLayout != null diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java index f82936a4492bf..8bbb548b0ecfc 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java @@ -22,9 +22,9 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager.RunningTaskInfo; -import android.window.ITaskOrganizerController; import android.app.WindowConfiguration; import android.os.RemoteException; import android.util.Log; @@ -49,13 +49,12 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { mDivider = divider; } - void init(ITaskOrganizerController organizerController, SurfaceSession session) - throws RemoteException { - organizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - organizerController.registerTaskOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); - mPrimary = organizerController.createRootTask(Display.DEFAULT_DISPLAY, + void init(SurfaceSession session) throws RemoteException { + TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); + TaskOrganizer.registerOrganizer(this, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); + mPrimary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - mSecondary = organizerController.createRootTask(Display.DEFAULT_DISPLAY, + mSecondary = TaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY, WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); mPrimarySurface = mPrimary.token.getLeash(); mSecondarySurface = mSecondary.token.getLeash(); @@ -90,10 +89,6 @@ class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub { public void taskVanished(RunningTaskInfo taskInfo) { } - @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { - } - @Override public void onTaskInfoChanged(RunningTaskInfo taskInfo) { if (taskInfo.displayId != DEFAULT_DISPLAY) { diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index 0e391ec7580a8..8724e490a558f 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.WindowOrganizer.TaskOrganizer; import android.annotation.NonNull; import android.app.ActivityManager; @@ -31,6 +32,7 @@ import android.view.Display; import android.window.IWindowContainer; import android.window.WindowContainerTransaction; import android.view.WindowManagerGlobal; +import android.window.WindowOrganizer; import com.android.internal.annotations.GuardedBy; @@ -111,8 +113,7 @@ public class WindowManagerProxy { WindowContainerTransaction t = new WindowContainerTransaction(); splitLayout.resizeSplits(position, t); try { - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(t, - null /* organizer */); + WindowOrganizer.applyTransaction(t); } catch (RemoteException e) { } } @@ -122,10 +123,8 @@ public class WindowManagerProxy { boolean resizable = false; try { List rootTasks = parent == null - ? ActivityTaskManager.getTaskOrganizerController().getRootTasks( - Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) - : ActivityTaskManager.getTaskOrganizerController().getChildTasks(parent, - HOME_AND_RECENTS); + ? TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS) + : TaskOrganizer.getChildTasks(parent, HOME_AND_RECENTS); for (int i = 0, n = rootTasks.size(); i < n; ++i) { final ActivityManager.RunningTaskInfo ti = rootTasks.get(i); out.add(ti.token); @@ -174,11 +173,9 @@ public class WindowManagerProxy { // Set launchtile first so that any stack created after // getAllStackInfos and before reparent (even if unlikely) are placed // correctly. - ActivityTaskManager.getTaskOrganizerController().setLaunchRoot( - DEFAULT_DISPLAY, tiles.mSecondary.token); + TaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token); List rootTasks = - ActivityTaskManager.getTaskOrganizerController().getRootTasks(DEFAULT_DISPLAY, - null /* activityTypes */); + TaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */); WindowContainerTransaction wct = new WindowContainerTransaction(); if (rootTasks.isEmpty()) { return false; @@ -192,8 +189,7 @@ public class WindowManagerProxy { true /* onTop */); } boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct); - ActivityTaskManager.getTaskOrganizerController() - .applyContainerTransaction(wct, null /* organizer */); + WindowOrganizer.applyTransaction(wct); return isHomeResizable; } catch (RemoteException e) { Log.w(TAG, "Error moving fullscreen tasks to secondary split: " + e); @@ -216,22 +212,18 @@ public class WindowManagerProxy { try { // Set launch root first so that any task created after getChildContainers and // before reparent (pretty unlikely) are put into fullscreen. - ActivityTaskManager.getTaskOrganizerController().setLaunchRoot(Display.DEFAULT_DISPLAY, - null); + TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null); // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished // plus specific APIs to clean this up. List primaryChildren = - ActivityTaskManager.getTaskOrganizerController().getChildTasks( - tiles.mPrimary.token, null /* activityTypes */); + TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */); List secondaryChildren = - ActivityTaskManager.getTaskOrganizerController().getChildTasks( - tiles.mSecondary.token, null /* activityTypes */); + TaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */); // In some cases (eg. non-resizable is launched), system-server will leave split-screen. // as a result, the above will not capture any tasks; yet, we need to clean-up the // home task bounds. List freeHomeAndRecents = - ActivityTaskManager.getTaskOrganizerController().getRootTasks( - Display.DEFAULT_DISPLAY, HOME_AND_RECENTS); + TaskOrganizer.getRootTasks(Display.DEFAULT_DISPLAY, HOME_AND_RECENTS); if (primaryChildren.isEmpty() && secondaryChildren.isEmpty() && freeHomeAndRecents.isEmpty()) { return; @@ -281,8 +273,7 @@ public class WindowManagerProxy { } // Reset focusable to true wct.setFocusable(tiles.mPrimary.token, true /* focusable */); - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, - null /* organizer */); + WindowOrganizer.applyTransaction(wct); } catch (RemoteException e) { Log.w(TAG, "Failed to remove stack: " + e); } @@ -290,8 +281,7 @@ public class WindowManagerProxy { static void applyContainerTransaction(WindowContainerTransaction wct) { try { - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, - null /* organizer */); + WindowOrganizer.applyTransaction(wct); } catch (RemoteException e) { Log.w(TAG, "Error setting focusability: " + e); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 184439587a022..f7278e70cedec 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -230,6 +230,7 @@ import android.util.proto.ProtoOutputStream; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationAdapter; import android.view.RemoteAnimationDefinition; +import android.window.IWindowOrganizerController; import android.window.WindowContainerTransaction; import android.view.WindowManager; @@ -663,10 +664,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { private FontScaleSettingObserver mFontScaleSettingObserver; - /** - * Stores the registration and state of TaskOrganizers in use. - */ - TaskOrganizerController mTaskOrganizerController = new TaskOrganizerController(this); + WindowOrganizerController mWindowOrganizerController; + TaskOrganizerController mTaskOrganizerController; private int mDeviceOwnerUid = Process.INVALID_UID; @@ -724,6 +723,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mLifecycleManager = new ClientLifecycleManager(); mInternal = new LocalService(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", GL_ES_VERSION_UNDEFINED); + mWindowOrganizerController = new WindowOrganizerController(this); + mTaskOrganizerController = mWindowOrganizerController.mTaskOrganizerController; } public void onSystemReady() { @@ -2772,7 +2773,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } WindowContainerTransaction wct = new WindowContainerTransaction(); wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop); - mTaskOrganizerController.applyContainerTransaction(wct, null); + mWindowOrganizerController.applyTransaction(wct); } /** @@ -4311,7 +4312,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } wct.setBounds(secondary.mRemoteToken, otherRect); - mTaskOrganizerController.applyContainerTransaction(wct, null /* organizer */); + mWindowOrganizerController.applyTransaction(wct); } } finally { Binder.restoreCallingIdentity(ident); @@ -4332,10 +4333,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } @Override - public ITaskOrganizerController getTaskOrganizerController() { + public IWindowOrganizerController getWindowOrganizerController() { mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, - "getTaskOrganizerController()"); - return mTaskOrganizerController; + "getWindowOrganizerController()"); + return mWindowOrganizerController; } /** diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 776a9863dc6ad..60b817c13236e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -531,8 +531,7 @@ public class DisplayRotation { try { mDisplayContent.sendNewConfiguration(); if (t != null) { - mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, - null /* organizer */); + mService.mAtmService.mWindowOrganizerController.applyTransaction(t); } } finally { mService.mAtmService.continueWindowLayout(); diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 9bf4d63550711..fc58ee785cf81 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -22,59 +22,34 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; -import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; -import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; -import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; -import static com.android.server.wm.WindowContainer.POSITION_TOP; +import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFIGS; +import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; -import android.app.WindowConfiguration; import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; -import android.util.ArraySet; import android.util.Slog; -import android.view.SurfaceControl; import android.window.ITaskOrganizerController; import android.window.ITaskOrganizer; import android.window.IWindowContainer; -import android.window.WindowContainerTransaction; import com.android.internal.util.ArrayUtils; -import com.android.internal.util.function.pooled.PooledConsumer; -import com.android.internal.util.function.pooled.PooledLambda; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.WeakHashMap; /** * Stores the TaskOrganizers associated with a given windowing mode and * their associated state. */ -class TaskOrganizerController extends ITaskOrganizerController.Stub - implements BLASTSyncEngine.TransactionReadyListener { +class TaskOrganizerController extends ITaskOrganizerController.Stub { private static final String TAG = "TaskOrganizerController"; - /** Flag indicating that an applied transaction may have effected lifecycle */ - private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1; - private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1; - - /** - * Masks specifying which configurations task-organizers can control. Incoming transactions - * will be filtered to only include these. - */ - private static final int CONTROLLABLE_CONFIGS = ActivityInfo.CONFIG_WINDOW_CONFIGURATION - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE; - private static final int CONTROLLABLE_WINDOW_CONFIGS = WindowConfiguration.WINDOW_CONFIG_BOUNDS - | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS; /** * Masks specifying which configurations are important to report back to an organizer when * changed. @@ -181,13 +156,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub final HashMap mTaskOrganizersForWindowingMode = new HashMap(); final HashMap mTaskOrganizerStates = new HashMap(); - final HashMap mTaskOrganizersByPendingSyncId = new HashMap(); - private final WeakHashMap mLastSentTaskInfos = new WeakHashMap<>(); private final ArrayList mPendingTaskInfoChanges = new ArrayList<>(); - private final BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine(); - final ActivityTaskManagerService mService; RunningTaskInfo mTmpTaskInfo; @@ -498,253 +469,4 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub Binder.restoreCallingIdentity(ident); } } - - private int sanitizeAndApplyChange(WindowContainer container, - WindowContainerTransaction.Change change) { - if (!(container instanceof Task)) { - throw new RuntimeException("Invalid token in task transaction"); - } - final Task task = (Task) container; - // The "client"-facing API should prevent bad changes; however, just in case, sanitize - // masks here. - final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS; - final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS; - int effects = 0; - if (configMask != 0) { - Configuration c = new Configuration(container.getRequestedOverrideConfiguration()); - c.setTo(change.getConfiguration(), configMask, windowMask); - container.onRequestedOverrideConfigurationChanged(c); - // TODO(b/145675353): remove the following once we could apply new bounds to the - // pinned stack together with its children. - resizePinnedStackIfNeeded(container, configMask, windowMask, c); - effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; - } - if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) { - if (container.setFocusable(change.getFocusable())) { - effects |= TRANSACT_EFFECTS_LIFECYCLE; - } - } - if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) { - if (task.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, change.getHidden())) { - effects |= TRANSACT_EFFECTS_LIFECYCLE; - } - } - return effects; - } - - private int sanitizeAndApplyHierarchyOp(WindowContainer container, - WindowContainerTransaction.HierarchyOp hop) { - if (!(container instanceof Task)) { - throw new IllegalArgumentException("Invalid container in hierarchy op"); - } - if (container.getDisplayContent() == null) { - Slog.w(TAG, "Container is no longer attached: " + container); - return 0; - } - if (hop.isReparent()) { - // special case for tiles since they are "virtual" parents - if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { - ActivityStack as = (ActivityStack) container; - TaskTile newParent = hop.getNewParent() == null ? null - : (TaskTile) WindowContainer.fromBinder(hop.getNewParent()); - if (as.getTile() != newParent) { - if (as.getTile() != null) { - as.getTile().removeChild(as); - } - if (newParent != null) { - if (!as.affectedBySplitScreenResize()) { - return 0; - } - newParent.addChild(as, POSITION_TOP); - } - } - if (hop.getToTop()) { - as.getDisplay().positionStackAtTop(as, false /* includingParents */); - } else { - as.getDisplay().positionStackAtBottom(as); - } - } else if (container instanceof Task) { - throw new RuntimeException("Reparenting leaf Tasks is not supported now."); - } - } else { - // Ugh, of course ActivityStack has its own special reorder logic... - if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { - ActivityStack as = (ActivityStack) container; - if (hop.getToTop()) { - as.getDisplay().positionStackAtTop(as, false /* includingParents */); - } else { - as.getDisplay().positionStackAtBottom(as); - } - } else { - container.getParent().positionChildAt( - hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, - container, false /* includingParents */); - } - } - return TRANSACT_EFFECTS_LIFECYCLE; - } - - private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, - int windowMask, Configuration config) { - if ((container instanceof ActivityStack) - && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) - && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) { - final ActivityStack stack = (ActivityStack) container; - if (stack.inPinnedWindowingMode()) { - stack.resize(config.windowConfiguration.getBounds(), - null /* configBounds */, PRESERVE_WINDOWS, true /* deferResume */); - } - } - } - - private int applyWindowContainerChange(WindowContainer wc, - WindowContainerTransaction.Change c) { - int effects = sanitizeAndApplyChange(wc, c); - - final Task tr = wc.asTask(); - - final SurfaceControl.Transaction t = c.getBoundsChangeTransaction(); - if (t != null) { - tr.setMainWindowSizeChangeTransaction(t); - } - - Rect enterPipBounds = c.getEnterPipBounds(); - if (enterPipBounds != null) { - mService.mStackSupervisor.updatePictureInPictureMode(tr, - enterPipBounds, true); - } - - final int windowingMode = c.getWindowingMode(); - if (windowingMode > -1) { - tr.setWindowingMode(windowingMode); - } - final int childWindowingMode = c.getActivityWindowingMode(); - if (childWindowingMode > -1) { - tr.setActivityWindowingMode(childWindowingMode); - } - - return effects; - } - - @Override - public int applyContainerTransaction(WindowContainerTransaction t, ITaskOrganizer organizer) { - enforceStackPermission("applyContainerTransaction()"); - int syncId = -1; - if (t == null) { - throw new IllegalArgumentException( - "Null transaction passed to applyContainerTransaction"); - } - long ident = Binder.clearCallingIdentity(); - try { - synchronized (mGlobalLock) { - int effects = 0; - - /** - * If organizer is non-null we are looking to synchronize this transaction - * by collecting all the results in to a SurfaceFlinger transaction and - * then delivering that to the given organizers transaction ready callback. - * See {@link BLASTSyncEngine} for the details of the operation. But at - * a high level we create a sync operation with a given ID and an associated - * organizer. Then we notify each WindowContainer in this WindowContainer - * transaction that it is participating in a sync operation with that - * ID. Once everything is notified we tell the BLASTSyncEngine - * "setSyncReady" which means that we have added everything - * to the set. At any point after this, all the WindowContainers - * will eventually finish applying their changes and notify the - * BLASTSyncEngine which will deliver the Transaction to the organizer. - */ - if (organizer != null) { - syncId = startSyncWithOrganizer(organizer); - } - mService.deferWindowLayout(); - try { - ArraySet haveConfigChanges = new ArraySet<>(); - Iterator> entries = - t.getChanges().entrySet().iterator(); - while (entries.hasNext()) { - final Map.Entry entry = - entries.next(); - final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); - int containerEffect = applyWindowContainerChange(wc, entry.getValue()); - effects |= containerEffect; - - // Lifecycle changes will trigger ensureConfig for everything. - if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 - && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - haveConfigChanges.add(wc); - } - if (syncId >= 0) { - mBLASTSyncEngine.addToSyncSet(syncId, wc); - } - } - // Hierarchy changes - final List hops = t.getHierarchyOps(); - for (int i = 0, n = hops.size(); i < n; ++i) { - final WindowContainerTransaction.HierarchyOp hop = hops.get(i); - final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); - effects |= sanitizeAndApplyHierarchyOp(wc, hop); - } - if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { - // Already calls ensureActivityConfig - mService.mRootWindowContainer.ensureActivitiesVisible( - null, 0, PRESERVE_WINDOWS); - } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { - final PooledConsumer f = PooledLambda.obtainConsumer( - ActivityRecord::ensureActivityConfiguration, - PooledLambda.__(ActivityRecord.class), 0, - false /* preserveWindow */); - try { - for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { - final WindowContainer wc = haveConfigChanges.valueAt(i); - final Task task = wc.asTask(); - final TaskTile tile = task != null ? task.asTile() : null; - if (tile != null) { - // Special case for tile. Can't override normal forAllActivities - // because it generates duplicate calls and messes up existing - // code-paths. - tile.forAllTileActivities(f); - } else { - wc.forAllActivities(f); - } - } - } finally { - f.recycle(); - } - } - } finally { - mService.continueWindowLayout(); - if (syncId >= 0) { - setSyncReady(syncId); - } - } - } - } finally { - Binder.restoreCallingIdentity(ident); - } - return syncId; - } - - @Override - public void transactionReady(int id, SurfaceControl.Transaction sc) { - final ITaskOrganizer organizer = mTaskOrganizersByPendingSyncId.get(id); - if (organizer == null) { - Slog.e(TAG, "Got transaction complete for unexpected ID"); - } - try { - organizer.transactionReady(id, sc); - } catch (RemoteException e) { - } - - mTaskOrganizersByPendingSyncId.remove(id); - } - - int startSyncWithOrganizer(ITaskOrganizer organizer) { - int id = mBLASTSyncEngine.startSyncSet(this); - mTaskOrganizersByPendingSyncId.put(id, organizer); - return id; - } - - void setSyncReady(int id) { - mBLASTSyncEngine.setReady(id); - } } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java new file mode 100644 index 0000000000000..ebfe1096540ef --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -0,0 +1,347 @@ +/* + * 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 com.android.server.wm; + +import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS; + +import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; +import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG; +import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; + +import android.app.WindowConfiguration; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.ArraySet; +import android.util.Slog; +import android.view.SurfaceControl; +import android.window.ITaskOrganizerController; +import android.window.IWindowContainerTransactionCallback; +import android.window.IWindowOrganizerController; +import android.window.WindowContainerTransaction; + +import com.android.internal.util.function.pooled.PooledConsumer; +import com.android.internal.util.function.pooled.PooledLambda; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Server side implementation for the interface for organizing windows + * @see android.window.WindowOrganizer + */ +class WindowOrganizerController extends IWindowOrganizerController.Stub + implements BLASTSyncEngine.TransactionReadyListener { + + private static final String TAG = "WindowOrganizerController"; + + /** Flag indicating that an applied transaction may have effected lifecycle */ + private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1; + private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1; + + /** + * Masks specifying which configurations task-organizers can control. Incoming transactions + * will be filtered to only include these. + */ + static final int CONTROLLABLE_CONFIGS = ActivityInfo.CONFIG_WINDOW_CONFIGURATION + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_SCREEN_SIZE; + static final int CONTROLLABLE_WINDOW_CONFIGS = WindowConfiguration.WINDOW_CONFIG_BOUNDS + | WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS; + + private final ActivityTaskManagerService mService; + private final WindowManagerGlobalLock mGlobalLock; + + private final BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine(); + private final HashMap + mTransactionCallbacksByPendingSyncId = new HashMap(); + + final TaskOrganizerController mTaskOrganizerController; + + WindowOrganizerController(ActivityTaskManagerService atm) { + mService = atm; + mGlobalLock = atm.mGlobalLock; + mTaskOrganizerController = new TaskOrganizerController(mService); + } + + @Override + public void applyTransaction(WindowContainerTransaction t) { + applySyncTransaction(t, null /*callback*/); + } + + @Override + public int applySyncTransaction(WindowContainerTransaction t, + IWindowContainerTransactionCallback callback) { + enforceStackPermission("applySyncTransaction()"); + int syncId = -1; + if (t == null) { + throw new IllegalArgumentException( + "Null transaction passed to applySyncTransaction"); + } + long ident = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + int effects = 0; + + /** + * If callback is non-null we are looking to synchronize this transaction by + * collecting all the results in to a SurfaceFlinger transaction and then delivering + * that to the given transaction ready callback. See {@link BLASTSyncEngine} for the + * details of the operation. But at a high level we create a sync operation with a + * given ID and an associated callback. Then we notify each WindowContainer in this + * WindowContainer transaction that it is participating in a sync operation with + * that ID. Once everything is notified we tell the BLASTSyncEngine "setSyncReady" + * which means that we have added everything to the set. At any point after this, + * all the WindowContainers will eventually finish applying their changes and notify + * the BLASTSyncEngine which will deliver the Transaction to the callback. + */ + if (callback != null) { + syncId = startSyncWithOrganizer(callback); + } + mService.deferWindowLayout(); + try { + ArraySet haveConfigChanges = new ArraySet<>(); + Iterator> entries = + t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry entry = + entries.next(); + final WindowContainer wc = WindowContainer.fromBinder(entry.getKey()); + int containerEffect = applyWindowContainerChange(wc, entry.getValue()); + effects |= containerEffect; + + // Lifecycle changes will trigger ensureConfig for everything. + if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0 + && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { + haveConfigChanges.add(wc); + } + if (syncId >= 0) { + mBLASTSyncEngine.addToSyncSet(syncId, wc); + } + } + // Hierarchy changes + final List hops = t.getHierarchyOps(); + for (int i = 0, n = hops.size(); i < n; ++i) { + final WindowContainerTransaction.HierarchyOp hop = hops.get(i); + final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); + effects |= sanitizeAndApplyHierarchyOp(wc, hop); + } + if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { + // Already calls ensureActivityConfig + mService.mRootWindowContainer.ensureActivitiesVisible( + null, 0, PRESERVE_WINDOWS); + } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { + final PooledConsumer f = PooledLambda.obtainConsumer( + ActivityRecord::ensureActivityConfiguration, + PooledLambda.__(ActivityRecord.class), 0, + false /* preserveWindow */); + try { + for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { + final WindowContainer wc = haveConfigChanges.valueAt(i); + final Task task = wc.asTask(); + final TaskTile tile = task != null ? task.asTile() : null; + if (tile != null) { + // Special case for tile. Can't override normal forAllActivities + // because it generates duplicate calls and messes up existing + // code-paths. + tile.forAllTileActivities(f); + } else { + wc.forAllActivities(f); + } + } + } finally { + f.recycle(); + } + } + } finally { + mService.continueWindowLayout(); + if (syncId >= 0) { + setSyncReady(syncId); + } + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + return syncId; + } + + private int sanitizeAndApplyChange(WindowContainer container, + WindowContainerTransaction.Change change) { + if (!(container instanceof Task)) { + throw new RuntimeException("Invalid token in task transaction"); + } + final Task task = (Task) container; + // The "client"-facing API should prevent bad changes; however, just in case, sanitize + // masks here. + final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS; + final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS; + int effects = 0; + if (configMask != 0) { + Configuration c = new Configuration(container.getRequestedOverrideConfiguration()); + c.setTo(change.getConfiguration(), configMask, windowMask); + container.onRequestedOverrideConfigurationChanged(c); + // TODO(b/145675353): remove the following once we could apply new bounds to the + // pinned stack together with its children. + resizePinnedStackIfNeeded(container, configMask, windowMask, c); + effects |= TRANSACT_EFFECTS_CLIENT_CONFIG; + } + if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) { + if (container.setFocusable(change.getFocusable())) { + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } + } + if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_HIDDEN) != 0) { + if (task.setForceHidden(FLAG_FORCE_HIDDEN_FOR_TASK_ORG, change.getHidden())) { + effects |= TRANSACT_EFFECTS_LIFECYCLE; + } + } + return effects; + } + + private int sanitizeAndApplyHierarchyOp(WindowContainer container, + WindowContainerTransaction.HierarchyOp hop) { + if (!(container instanceof Task)) { + throw new IllegalArgumentException("Invalid container in hierarchy op"); + } + if (container.getDisplayContent() == null) { + Slog.w(TAG, "Container is no longer attached: " + container); + return 0; + } + if (hop.isReparent()) { + // special case for tiles since they are "virtual" parents + if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { + ActivityStack as = (ActivityStack) container; + TaskTile newParent = hop.getNewParent() == null ? null + : (TaskTile) WindowContainer.fromBinder(hop.getNewParent()); + if (as.getTile() != newParent) { + if (as.getTile() != null) { + as.getTile().removeChild(as); + } + if (newParent != null) { + if (!as.affectedBySplitScreenResize()) { + return 0; + } + newParent.addChild(as, POSITION_TOP); + } + } + if (hop.getToTop()) { + as.getDisplay().positionStackAtTop(as, false /* includingParents */); + } else { + as.getDisplay().positionStackAtBottom(as); + } + } else if (container instanceof Task) { + throw new RuntimeException("Reparenting leaf Tasks is not supported now."); + } + } else { + // Ugh, of course ActivityStack has its own special reorder logic... + if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) { + ActivityStack as = (ActivityStack) container; + if (hop.getToTop()) { + as.getDisplay().positionStackAtTop(as, false /* includingParents */); + } else { + as.getDisplay().positionStackAtBottom(as); + } + } else { + container.getParent().positionChildAt( + hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, + container, false /* includingParents */); + } + } + return TRANSACT_EFFECTS_LIFECYCLE; + } + + private int applyWindowContainerChange(WindowContainer wc, + WindowContainerTransaction.Change c) { + int effects = sanitizeAndApplyChange(wc, c); + + final Task tr = wc.asTask(); + + final SurfaceControl.Transaction t = c.getBoundsChangeTransaction(); + if (t != null) { + tr.setMainWindowSizeChangeTransaction(t); + } + + Rect enterPipBounds = c.getEnterPipBounds(); + if (enterPipBounds != null) { + mService.mStackSupervisor.updatePictureInPictureMode(tr, + enterPipBounds, true); + } + + final int windowingMode = c.getWindowingMode(); + if (windowingMode > -1) { + tr.setWindowingMode(windowingMode); + } + final int childWindowingMode = c.getActivityWindowingMode(); + if (childWindowingMode > -1) { + tr.setActivityWindowingMode(childWindowingMode); + } + + return effects; + } + + private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask, + int windowMask, Configuration config) { + if ((container instanceof ActivityStack) + && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0) + && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) { + final ActivityStack stack = (ActivityStack) container; + if (stack.inPinnedWindowingMode()) { + stack.resize(config.windowConfiguration.getBounds(), + null /* configBounds */, PRESERVE_WINDOWS, true /* deferResume */); + } + } + } + + @Override + public ITaskOrganizerController getTaskOrganizerController() { + enforceStackPermission("getTaskOrganizerController()"); + return mTaskOrganizerController; + } + + int startSyncWithOrganizer(IWindowContainerTransactionCallback callback) { + int id = mBLASTSyncEngine.startSyncSet(this); + mTransactionCallbacksByPendingSyncId.put(id, callback); + return id; + } + + void setSyncReady(int id) { + mBLASTSyncEngine.setReady(id); + } + + @Override + public void transactionReady(int mSyncId, SurfaceControl.Transaction mergedTransaction) { + final IWindowContainerTransactionCallback callback = + mTransactionCallbacksByPendingSyncId.get(mSyncId); + + try { + callback.transactionReady(mSyncId, mergedTransaction); + } catch (RemoteException e) { + } + + mTransactionCallbacksByPendingSyncId.remove(mSyncId); + } + + private void enforceStackPermission(String func) { + mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 873fa02220026..658ba1ba8a4a8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -1026,9 +1026,6 @@ public class ActivityStarterTests extends ActivityTestsBase { public void taskVanished(ActivityManager.RunningTaskInfo info) { } @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { - } - @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { if (mInSplit) { return; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java index 1624bbc1d4725..5359bd33e70f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java @@ -231,7 +231,7 @@ public class TaskOrganizerTests extends WindowTestsBase { WindowContainerTransaction t = new WindowContainerTransaction(); Rect newBounds = new Rect(10, 10, 100, 100); t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100)); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertEquals(newBounds, task.getBounds()); } @@ -246,7 +246,7 @@ public class TaskOrganizerTests extends WindowTestsBase { assertEquals(stack.mRemoteToken, info.stackToken); Rect newBounds = new Rect(10, 10, 100, 100); t.setBounds(info.stackToken, new Rect(10, 10, 100, 100)); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertEquals(newBounds, stack.getBounds()); } @@ -257,7 +257,7 @@ public class TaskOrganizerTests extends WindowTestsBase { final WindowContainerTransaction t = new WindowContainerTransaction(); t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertEquals(WINDOWING_MODE_FULLSCREEN, stack.getWindowingMode()); } @@ -270,7 +270,7 @@ public class TaskOrganizerTests extends WindowTestsBase { t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_PINNED); t.setActivityWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode()); assertEquals(WINDOWING_MODE_PINNED, stack.getWindowingMode()); @@ -285,10 +285,10 @@ public class TaskOrganizerTests extends WindowTestsBase { WindowContainerTransaction t = new WindowContainerTransaction(); assertTrue(task.isFocusable()); t.setFocusable(stack.mRemoteToken, false); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertFalse(task.isFocusable()); t.setFocusable(stack.mRemoteToken, true); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertTrue(task.isFocusable()); } @@ -300,10 +300,10 @@ public class TaskOrganizerTests extends WindowTestsBase { WindowContainerTransaction t = new WindowContainerTransaction(); assertTrue(stack.shouldBeVisible(null)); t.setHidden(stack.mRemoteToken, true); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertFalse(stack.shouldBeVisible(null)); t.setHidden(stack.mRemoteToken, false); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertTrue(stack.shouldBeVisible(null)); } @@ -315,19 +315,19 @@ public class TaskOrganizerTests extends WindowTestsBase { final Task task = stack.getTopMostTask(); WindowContainerTransaction t = new WindowContainerTransaction(); t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100)); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); final int origScreenWDp = task.getConfiguration().screenHeightDp; final int origScreenHDp = task.getConfiguration().screenHeightDp; t = new WindowContainerTransaction(); // verify that setting config overrides on parent restricts children. t.setScreenSizeDp(stack.mRemoteToken, origScreenWDp, origScreenHDp); t.setBounds(task.mRemoteToken, new Rect(10, 10, 150, 200)); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertEquals(origScreenHDp, task.getConfiguration().screenHeightDp); t = new WindowContainerTransaction(); t.setScreenSizeDp(stack.mRemoteToken, Configuration.SCREEN_WIDTH_DP_UNDEFINED, Configuration.SCREEN_HEIGHT_DP_UNDEFINED); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(t); assertNotEquals(origScreenHDp, task.getConfiguration().screenHeightDp); } @@ -401,9 +401,6 @@ public class TaskOrganizerTests extends WindowTestsBase { @Override public void taskVanished(RunningTaskInfo container) { } - @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { } - @Override public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException { lastReportedTiles.add(info); @@ -455,9 +452,6 @@ public class TaskOrganizerTests extends WindowTestsBase { @Override public void taskVanished(RunningTaskInfo container) { } - @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { } - @Override public void onTaskInfoChanged(RunningTaskInfo info) { lastReportedTiles.put(info.token.asBinder(), info); @@ -487,8 +481,7 @@ public class TaskOrganizerTests extends WindowTestsBase { WindowContainerTransaction wct = new WindowContainerTransaction(); wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */); wct.reparent(stack2.mRemoteToken, info2.token, true /* onTop */); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, - null /* organizer */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); assertFalse(lastReportedTiles.isEmpty()); assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(info1.token.asBinder()).topActivityType); @@ -498,8 +491,7 @@ public class TaskOrganizerTests extends WindowTestsBase { lastReportedTiles.clear(); wct = new WindowContainerTransaction(); wct.reparent(stack2.mRemoteToken, info1.token, false /* onTop */); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, - null /* organizer */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); assertFalse(lastReportedTiles.isEmpty()); // Standard should still be on top of tile 1, so no change there assertFalse(lastReportedTiles.containsKey(info1.token.asBinder())); @@ -524,8 +516,7 @@ public class TaskOrganizerTests extends WindowTestsBase { lastReportedTiles.clear(); wct = new WindowContainerTransaction(); wct.reorder(stack2.mRemoteToken, true /* onTop */); - mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(wct, - null /* organizer */); + mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct); // Home should now be on top. No change occurs in second tile, so not reported assertEquals(1, lastReportedTiles.size()); assertEquals(ACTIVITY_TYPE_HOME, @@ -683,9 +674,6 @@ public class TaskOrganizerTests extends WindowTestsBase { public void taskVanished(RunningTaskInfo info) { } @Override - public void transactionReady(int id, SurfaceControl.Transaction t) { - } - @Override public void onTaskInfoChanged(RunningTaskInfo info) { } }; diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java index cb75c8ba58732..f186ed3b75cf7 100644 --- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java +++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java @@ -17,9 +17,9 @@ package com.android.test.taskembed; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; +import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.Activity; import android.app.ActivityOptions; import android.content.Context; @@ -27,6 +27,8 @@ import android.content.Intent; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; import android.view.Gravity; import android.view.MotionEvent; import android.view.SurfaceControl; @@ -34,8 +36,10 @@ import android.view.SurfaceHolder; import android.view.View; import android.view.ViewGroup; import android.window.ITaskOrganizer; +import android.window.IWindowContainerTransactionCallback; import android.window.WindowContainerTransaction; import android.widget.LinearLayout; +import android.window.WindowOrganizer; public class TaskOrganizerMultiWindowTest extends Activity { class SplitLayout extends LinearLayout implements View.OnTouchListener { @@ -112,8 +116,7 @@ public class TaskOrganizerMultiWindowTest extends Activity { final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.setBounds(mWc, new Rect(0, 0, width, height)); try { - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, - mOrganizer); + WindowOrganizer.applySyncTransaction(wct, mOrganizer.mTransactionCallback); } catch (Exception e) { // Oh well } @@ -127,6 +130,25 @@ public class TaskOrganizerMultiWindowTest extends Activity { class Organizer extends ITaskOrganizer.Stub { private int receivedTransactions = 0; SurfaceControl.Transaction mergedTransaction = new SurfaceControl.Transaction(); + IWindowContainerTransactionCallback mTransactionCallback = + new IWindowContainerTransactionCallback() { + @Override + public void transactionReady(int id, SurfaceControl.Transaction t) + throws RemoteException { + mergedTransaction.merge(t); + receivedTransactions++; + if (receivedTransactions == 2) { + mergedTransaction.apply(); + receivedTransactions = 0; + } + } + + @Override + public IBinder asBinder() { + return null; + } + }; + @Override public void taskAppeared(ActivityManager.RunningTaskInfo ti) { if (!gotFirstTask) { @@ -138,14 +160,6 @@ public class TaskOrganizerMultiWindowTest extends Activity { } public void taskVanished(ActivityManager.RunningTaskInfo ti) { } - public void transactionReady(int id, SurfaceControl.Transaction t) { - mergedTransaction.merge(t); - receivedTransactions++; - if (receivedTransactions == 2) { - mergedTransaction.apply(); - receivedTransactions = 0; - } - } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { } @@ -158,9 +172,7 @@ public class TaskOrganizerMultiWindowTest extends Activity { super.onCreate(savedInstanceState); try { - ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(mOrganizer, - WINDOWING_MODE_MULTI_WINDOW); - + TaskOrganizer.registerOrganizer(mOrganizer, WINDOWING_MODE_MULTI_WINDOW); } catch (Exception e) { } diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java index 177841d97ff5b..a2f40dc0fd6f2 100644 --- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java +++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java @@ -17,19 +17,19 @@ package com.android.test.taskembed; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.window.WindowOrganizer.TaskOrganizer; import android.app.ActivityManager; -import android.app.ActivityTaskManager; import android.app.Service; import android.content.Intent; import android.graphics.Rect; import android.os.IBinder; -import android.view.SurfaceControl; import android.view.ViewGroup; import android.window.ITaskOrganizer; import android.window.WindowContainerTransaction; import android.view.WindowManager; import android.widget.FrameLayout; +import android.window.WindowOrganizer; public class TaskOrganizerPipTest extends Service { static final int PIP_WIDTH = 640; @@ -44,14 +44,12 @@ public class TaskOrganizerPipTest extends Service { final WindowContainerTransaction wct = new WindowContainerTransaction(); wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT)); try { - ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct, null); + WindowOrganizer.applyTransaction(wct); } catch (Exception e) { } } public void taskVanished(ActivityManager.RunningTaskInfo ti) { } - public void transactionReady(int id, SurfaceControl.Transaction t) { - } public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { } } @@ -68,9 +66,7 @@ public class TaskOrganizerPipTest extends Service { super.onCreate(); try { - ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(mOrganizer, - WINDOWING_MODE_PINNED); - + TaskOrganizer.registerOrganizer(mOrganizer, WINDOWING_MODE_PINNED); } catch (Exception e) { }