Merge "Introduce WindowOrganizer" into rvc-dev am: e5cfca4454 am: b5f6daab3f am: ef812e4b33
Change-Id: If45bda185771280f9eec1c4b1b29f5859239217f
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
46
core/java/android/window/IWindowOrganizerController.aidl
Normal file
46
core/java/android/window/IWindowOrganizerController.aidl
Normal 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();
|
||||
}
|
||||
157
core/java/android/window/WindowOrganizer.java
Normal file
157
core/java/android/window/WindowOrganizer.java
Normal 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user