Merge "Introduce WindowOrganizer" into rvc-dev am: e5cfca4454 am: b5f6daab3f am: ef812e4b33

Change-Id: If45bda185771280f9eec1c4b1b29f5859239217f
This commit is contained in:
Wale Ogunwale
2020-03-24 02:30:48 +00:00
committed by Automerger Merge Worker
21 changed files with 689 additions and 460 deletions

View File

@@ -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<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
new Singleton<ITaskOrganizerController>() {
@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}

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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<IWindowOrganizerController> IWindowOrganizerControllerSingleton =
new Singleton<IWindowOrganizerController>() {
@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<ActivityManager.RunningTaskInfo> 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<ActivityManager.RunningTaskInfo> 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<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
new Singleton<ITaskOrganizerController>() {
@Override
protected ITaskOrganizerController create() {
try {
return getWindowOrganizerController().getTaskOrganizerController();
} catch (RemoteException e) {
return null;
}
}
};
}
}

View File

@@ -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;
@@ -76,7 +77,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<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
@@ -188,7 +188,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);
@@ -264,10 +263,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;
@@ -450,7 +445,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);
}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -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<ActivityManager.RunningTaskInfo> 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<ActivityManager.RunningTaskInfo> 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<ActivityManager.RunningTaskInfo> primaryChildren =
ActivityTaskManager.getTaskOrganizerController().getChildTasks(
tiles.mPrimary.token, null /* activityTypes */);
TaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
List<ActivityManager.RunningTaskInfo> 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<ActivityManager.RunningTaskInfo> 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);
}

View File

@@ -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;
}
/**

View File

@@ -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();

View File

@@ -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<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
final HashMap<Integer, ITaskOrganizer> mTaskOrganizersByPendingSyncId = new HashMap();
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> 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<WindowContainer> haveConfigChanges = new ArraySet<>();
Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
t.getChanges().entrySet().iterator();
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> 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<WindowContainerTransaction.HierarchyOp> 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);
}
}

View File

@@ -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<Integer, IWindowContainerTransactionCallback>
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<WindowContainer> haveConfigChanges = new ArraySet<>();
Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
t.getChanges().entrySet().iterator();
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> 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<WindowContainerTransaction.HierarchyOp> 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);
}
}

View File

@@ -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;

View File

@@ -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) {
}
};

View File

@@ -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) {
}

View File

@@ -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) {
}