summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/IWindowManager.aidl7
-rw-r--r--core/java/android/view/SyncRtSurfaceTransactionApplier.java26
-rw-r--r--core/java/android/view/WindowManager.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java95
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java170
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java14
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java11
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java55
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
14 files changed, 327 insertions, 149 deletions
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 11423e6de93e..924fc6d6dca0 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -153,11 +153,10 @@ interface IWindowManager
* WindowlessWindowManager).
*
* @param client an IWindow used for window-level communication (ime, finish draw, etc.).
- * @param windowType used by WM to determine the z-order. This is the same as the window type
- * used in {@link WindowManager.LayoutParams}.
+ * @param shellRootLayer The container's layer. See WindowManager#ShellRootLayer.
* @return a SurfaceControl to add things to.
*/
- SurfaceControl addShellRoot(int displayId, IWindow client, int windowType);
+ SurfaceControl addShellRoot(int displayId, IWindow client, int shellRootLayer);
/**
* Sets the window token sent to accessibility for a particular shell root. The
@@ -165,7 +164,7 @@ interface IWindowManager
*
* @param target The IWindow that accessibility service interfaces with.
*/
- void setShellRootAccessibilityWindow(int displayId, int windowType, IWindow target);
+ void setShellRootAccessibilityWindow(int displayId, int shellRootLayer, IWindow target);
/**
* Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index bce78b572360..b10370aa5d4c 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -38,6 +38,7 @@ public class SyncRtSurfaceTransactionApplier {
public static final int FLAG_CORNER_RADIUS = 1 << 4;
public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
public static final int FLAG_VISIBILITY = 1 << 6;
+ public static final int FLAG_TRANSACTION = 1 << 7;
private SurfaceControl mTargetSc;
private final ViewRootImpl mTargetViewRootImpl;
@@ -93,6 +94,10 @@ public class SyncRtSurfaceTransactionApplier {
}
public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
+ if ((params.flags & FLAG_TRANSACTION) != 0) {
+ t.merge(params.mergeTransaction);
+ }
+
if ((params.flags & FLAG_MATRIX) != 0) {
t.setMatrix(params.surface, params.matrix, tmpFloat9);
}
@@ -161,6 +166,7 @@ public class SyncRtSurfaceTransactionApplier {
Rect windowCrop;
int layer;
boolean visible;
+ Transaction mergeTransaction;
/**
* @param surface The surface to modify.
@@ -240,17 +246,28 @@ public class SyncRtSurfaceTransactionApplier {
}
/**
+ * @param mergeTransaction The transaction to apply to the surface. Note this is applied
+ * first before all the other properties.
+ * @return this Builder
+ */
+ public Builder withMergeTransaction(Transaction mergeTransaction) {
+ this.mergeTransaction = mergeTransaction;
+ flags |= FLAG_TRANSACTION;
+ return this;
+ }
+
+ /**
* @return a new SurfaceParams instance
*/
public SurfaceParams build() {
return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
- cornerRadius, backgroundBlurRadius, visible);
+ cornerRadius, backgroundBlurRadius, visible, mergeTransaction);
}
}
private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
- Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius,
- boolean visible) {
+ Rect windowCrop, int layer, float cornerRadius,
+ int backgroundBlurRadius, boolean visible, Transaction mergeTransaction) {
this.flags = params;
this.surface = surface;
this.alpha = alpha;
@@ -260,6 +277,7 @@ public class SyncRtSurfaceTransactionApplier {
this.cornerRadius = cornerRadius;
this.backgroundBlurRadius = backgroundBlurRadius;
this.visible = visible;
+ this.mergeTransaction = mergeTransaction;
}
private final int flags;
@@ -286,5 +304,7 @@ public class SyncRtSurfaceTransactionApplier {
public final int layer;
public final boolean visible;
+
+ public final Transaction mergeTransaction;
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f85489871730..f7578abfe4f0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -133,6 +133,22 @@ public interface WindowManager extends ViewManager {
/** @hide */
String INPUT_CONSUMER_RECENTS_ANIMATION = "recents_animation_input_consumer";
+ /** @hide */
+ int SHELL_ROOT_LAYER_DIVIDER = 0;
+ /** @hide */
+ int SHELL_ROOT_LAYER_PIP = 1;
+
+ /**
+ * Declares the layer the shell root will belong to. This is for z-ordering.
+ * @hide
+ */
+ @IntDef(prefix = { "SHELL_ROOT_LAYER_" }, value = {
+ SHELL_ROOT_LAYER_DIVIDER,
+ SHELL_ROOT_LAYER_PIP
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ShellRootLayer {}
+
/**
* Not set up for a transition.
* @hide
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 24381d937e2f..4c06a2ca3bca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -101,13 +101,13 @@ public class SystemWindows {
* Adds a view to system-ui window management.
*/
public void addView(View view, WindowManager.LayoutParams attrs, int displayId,
- int windowType) {
+ @WindowManager.ShellRootLayer int shellRootLayer) {
PerDisplay pd = mPerDisplay.get(displayId);
if (pd == null) {
pd = new PerDisplay(displayId);
mPerDisplay.put(displayId, pd);
}
- pd.addView(view, attrs, windowType);
+ pd.addView(view, attrs, shellRootLayer);
}
/**
@@ -149,18 +149,6 @@ public class SystemWindows {
}
/**
- * Adds a root for system-ui window management with no views. Only useful for IME.
- */
- public void addRoot(int displayId, int windowType) {
- PerDisplay pd = mPerDisplay.get(displayId);
- if (pd == null) {
- pd = new PerDisplay(displayId);
- mPerDisplay.put(displayId, pd);
- }
- pd.addRoot(windowType);
- }
-
- /**
* Get the IWindow token for a specific root.
*
* @param windowType A window type from {@link WindowManager}.
@@ -198,8 +186,9 @@ public class SystemWindows {
mDisplayId = displayId;
}
- public void addView(View view, WindowManager.LayoutParams attrs, int windowType) {
- SysUiWindowManager wwm = addRoot(windowType);
+ public void addView(View view, WindowManager.LayoutParams attrs,
+ @WindowManager.ShellRootLayer int shellRootLayer) {
+ SysUiWindowManager wwm = addRoot(shellRootLayer);
if (wwm == null) {
Slog.e(TAG, "Unable to create systemui root");
return;
@@ -213,23 +202,22 @@ public class SystemWindows {
mViewRoots.put(view, viewRoot);
try {
- mWmService.setShellRootAccessibilityWindow(mDisplayId, windowType,
+ mWmService.setShellRootAccessibilityWindow(mDisplayId, shellRootLayer,
viewRoot.getWindowToken());
} catch (RemoteException e) {
Slog.e(TAG, "Error setting accessibility window for " + mDisplayId + ":"
- + windowType, e);
+ + shellRootLayer, e);
}
}
-
- SysUiWindowManager addRoot(int windowType) {
- SysUiWindowManager wwm = mWwms.get(windowType);
+ SysUiWindowManager addRoot(@WindowManager.ShellRootLayer int shellRootLayer) {
+ SysUiWindowManager wwm = mWwms.get(shellRootLayer);
if (wwm != null) {
return wwm;
}
SurfaceControl rootSurface = null;
ContainerWindow win = new ContainerWindow();
try {
- rootSurface = mWmService.addShellRoot(mDisplayId, win, windowType);
+ rootSurface = mWmService.addShellRoot(mDisplayId, win, shellRootLayer);
} catch (RemoteException e) {
}
if (rootSurface == null) {
@@ -238,7 +226,7 @@ public class SystemWindows {
}
Context displayContext = mDisplayController.getDisplayContext(mDisplayId);
wwm = new SysUiWindowManager(mDisplayId, displayContext, rootSurface, win);
- mWwms.put(windowType, wwm);
+ mWwms.put(shellRootLayer, wwm);
return wwm;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index d223934fcf34..f44ebf3a3a5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -52,9 +52,6 @@ import android.util.Log;
import android.util.Rational;
import android.util.Size;
import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.View;
-import android.view.WindowManager;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -66,6 +63,7 @@ import com.android.internal.os.SomeArgs;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.pip.phone.PipMotionHelper;
import com.android.wm.shell.pip.phone.PipUpdateThread;
@@ -138,6 +136,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final Handler mUpdateHandler;
private final PipBoundsState mPipBoundsState;
private final PipBoundsHandler mPipBoundsHandler;
+ private final PipMenuActivityController mMenuActivityController;
+ private final SystemWindows mSystemWindows;
private final PipAnimationController mPipAnimationController;
private final PipUiEventLogger mPipUiEventLoggerLogger;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
@@ -146,8 +146,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private final Map<IBinder, Configuration> mInitialState = new HashMap<>();
private final Optional<SplitScreen> mSplitScreenOptional;
protected final ShellTaskOrganizer mTaskOrganizer;
- private SurfaceControlViewHost mPipViewHost;
- private SurfaceControl mPipMenuSurface;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -267,15 +265,19 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
@NonNull PipBoundsHandler boundsHandler,
+ PipMenuActivityController menuActivityController,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional,
@NonNull DisplayController displayController,
@NonNull PipUiEventLogger pipUiEventLogger,
- @NonNull ShellTaskOrganizer shellTaskOrganizer) {
+ @NonNull ShellTaskOrganizer shellTaskOrganizer,
+ @NonNull SystemWindows systemWindows) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsState = pipBoundsState;
mPipBoundsHandler = boundsHandler;
+ mMenuActivityController = menuActivityController;
+ mSystemWindows = systemWindows;
mEnterExitAnimationDuration = context.getResources()
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
@@ -640,60 +642,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Setup the ViewHost and attach the provided menu view to the ViewHost.
- * @return The input token belonging to the PipMenuView.
- */
- public IBinder attachPipMenuViewHost(View menuView, WindowManager.LayoutParams lp) {
- if (mPipMenuSurface != null) {
- Log.e(TAG, "PIP Menu View already created and attached.");
- return null;
- }
-
- if (mLeash == null) {
- Log.e(TAG, "PiP Leash is not yet ready.");
- return null;
- }
-
- if (Looper.getMainLooper() != Looper.myLooper()) {
- throw new RuntimeException("PipMenuView needs to be attached on the main thread.");
- }
- final Context context = menuView.getContext();
- mPipViewHost = new SurfaceControlViewHost(context, context.getDisplay(),
- (android.os.Binder) null);
- mPipMenuSurface = mPipViewHost.getSurfacePackage().getSurfaceControl();
- SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
- transaction.reparent(mPipMenuSurface, mLeash);
- transaction.show(mPipMenuSurface);
- transaction.setRelativeLayer(mPipMenuSurface, mLeash, 1);
- transaction.apply();
- mPipViewHost.setView(menuView, lp);
-
- return mPipViewHost.getSurfacePackage().getInputToken();
- }
-
-
- /**
- * Releases the PIP Menu's View host, remove it from PIP task surface.
- */
- public void detachPipMenuViewHost() {
- if (mPipMenuSurface != null) {
- SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
- transaction.remove(mPipMenuSurface);
- transaction.apply();
- mPipMenuSurface = null;
- mPipViewHost = null;
- }
- }
-
- /**
- * Return whether the PiP Menu has been attached to the leash yet.
- */
- public boolean isPipMenuViewHostAttached() {
- return mPipViewHost != null;
- }
-
-
- /**
* Note that dismissing PiP is now originated from SystemUI, see {@link #exitPip(int)}.
* Meanwhile this callback is invoked whenever the task is removed. For instance:
* - as a result of removeRootTasksInWindowingModes from WM
@@ -998,7 +946,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
mSurfaceTransactionHelper
.crop(tx, mLeash, destinationBounds)
.round(tx, mLeash, mState.isInPip());
- tx.apply();
+ if (mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() -> {
+ mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds);
+ });
+ } else {
+ tx.apply();
+ }
}
private void userResizePip(Rect startBounds, Rect destinationBounds) {
@@ -1019,7 +973,13 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
- tx.apply();
+ if (mMenuActivityController.isMenuVisible()) {
+ runOnMainHandler(() -> {
+ mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds);
+ });
+ } else {
+ tx.apply();
+ }
}
private void finishResize(SurfaceControl.Transaction tx, Rect destinationBounds,
@@ -1034,6 +994,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
removePipImmediately();
return;
} else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ // TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
+ runOnMainHandler(() -> {
+ mMenuActivityController.movePipMenu(null, null, destinationBounds);
+ mMenuActivityController.updateMenuBounds(destinationBounds);
+ });
return;
}
@@ -1041,10 +1006,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
prepareFinishResizeTransaction(destinationBounds, direction, tx, wct);
applyFinishBoundsResize(wct, direction);
runOnMainHandler(() -> {
- if (mPipViewHost != null) {
- mPipViewHost.relayout(PipMenuActivityController.getPipMenuLayoutParams(
- destinationBounds.width(), destinationBounds.height()));
- }
+ mMenuActivityController.movePipMenu(null, null, destinationBounds);
+ mMenuActivityController.updateMenuBounds(destinationBounds);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
index a87fa20a7f11..a5252654aa23 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuActivityController.java
@@ -18,25 +18,37 @@ package com.android.wm.shell.pip.phone;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
+
+import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.RemoteAction;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMediaController.ActionListener;
-import com.android.wm.shell.pip.PipTaskOrganizer;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -51,6 +63,7 @@ import java.util.List;
public class PipMenuActivityController {
private static final String TAG = "PipMenuActController";
+ private static final String MENU_WINDOW_TITLE = "PipMenuView";
private static final boolean DEBUG = false;
public static final int MENU_STATE_NONE = 0;
@@ -85,13 +98,18 @@ public class PipMenuActivityController {
void onPipShowMenu();
}
- private Context mContext;
- private PipTaskOrganizer mPipTaskOrganizer;
- private PipMediaController mMediaController;
+ private final Matrix mMoveTransform = new Matrix();
+ private final Rect mTmpSourceBounds = new Rect();
+ private final RectF mTmpSourceRectF = new RectF();
+ private final RectF mTmpDestinationRectF = new RectF();
+ private final Context mContext;
+ private final PipMediaController mMediaController;
- private ArrayList<Listener> mListeners = new ArrayList<>();
+ private final ArrayList<Listener> mListeners = new ArrayList<>();
+ private final SystemWindows mSystemWindows;
private ParceledListSlice<RemoteAction> mAppActions;
private ParceledListSlice<RemoteAction> mMediaActions;
+ private SyncRtSurfaceTransactionApplier mApplier;
private int mMenuState;
private PipMenuView mPipMenuView;
@@ -106,10 +124,10 @@ public class PipMenuActivityController {
};
public PipMenuActivityController(Context context,
- PipMediaController mediaController, PipTaskOrganizer pipTaskOrganizer) {
+ PipMediaController mediaController, SystemWindows systemWindows) {
mContext = context;
mMediaController = mediaController;
- mPipTaskOrganizer = pipTaskOrganizer;
+ mSystemWindows = systemWindows;
}
public boolean isMenuVisible() {
@@ -122,9 +140,7 @@ public class PipMenuActivityController {
public void onActivityUnpinned() {
hideMenu();
- mPipTaskOrganizer.detachPipMenuViewHost();
- mPipMenuView = null;
- mPipMenuInputToken = null;
+ detachPipMenuView();
}
public void onPinnedStackAnimationEnded() {
@@ -136,15 +152,39 @@ public class PipMenuActivityController {
private void attachPipMenuView() {
if (mPipMenuView == null) {
mPipMenuView = new PipMenuView(mContext, this);
-
}
- // If we haven't gotten the input toekn, that means we haven't had a success attempt
- // yet at attaching the PipMenuView
- if (mPipMenuInputToken == null) {
- mPipMenuInputToken = mPipTaskOrganizer.attachPipMenuViewHost(mPipMenuView,
- getPipMenuLayoutParams(0, 0));
+ mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(0, 0), 0, SHELL_ROOT_LAYER_PIP);
+ }
+
+ private void detachPipMenuView() {
+ if (mPipMenuView == null) {
+ return;
}
+
+ mApplier = null;
+ mSystemWindows.removeView(mPipMenuView);
+ mPipMenuView = null;
+ mPipMenuInputToken = null;
+ }
+
+ /**
+ * Updates the layout parameters of the menu.
+ * @param destinationBounds New Menu bounds.
+ */
+ public void updateMenuBounds(Rect destinationBounds) {
+ mSystemWindows.updateViewLayout(mPipMenuView,
+ getPipMenuLayoutParams(destinationBounds.width(), destinationBounds.height()));
+ }
+
+ /**
+ * Tries to grab a surface control from {@link PipMenuView}. If this isn't available for some
+ * reason (ie. the window isn't ready yet, thus {@link android.view.ViewRootImpl} is
+ * {@code null}), it will get the leash that the WindowlessWM has assigned to it.
+ */
+ public SurfaceControl getSurfaceControl() {
+ SurfaceControl sf = mPipMenuView.getWindowSurfaceControl();
+ return sf != null ? sf : mSystemWindows.getViewSurface(mPipMenuView);
}
/**
@@ -190,16 +230,95 @@ public class PipMenuActivityController {
+ " callers=\n" + Debug.getCallers(5, " "));
}
- if (!mPipTaskOrganizer.isPipMenuViewHostAttached()) {
- Log.d(TAG, "PipMenu has not been attached yet. Attaching now at showMenuInternal().");
- attachPipMenuView();
- }
+ maybeCreateSyncApplier();
mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
showResizeHandle);
}
/**
+ * Move the PiP menu, which does a translation and possibly a scale transformation.
+ */
+ public void movePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds) {
+ if (destinationBounds.isEmpty()) {
+ return;
+ }
+
+ if (!maybeCreateSyncApplier()) {
+ return;
+ }
+
+ // If there is no pip leash supplied, that means the PiP leash is already finalized
+ // resizing and the PiP menu is also resized. We then want to do a scale from the current
+ // new menu bounds.
+ if (pipLeash != null && t != null) {
+ mPipMenuView.getBoundsOnScreen(mTmpSourceBounds);
+ } else {
+ mTmpSourceBounds.set(0, 0, destinationBounds.width(), destinationBounds.height());
+ }
+
+ mTmpSourceRectF.set(mTmpSourceBounds);
+ mTmpDestinationRectF.set(destinationBounds);
+ mMoveTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+ SurfaceControl surfaceControl = getSurfaceControl();
+ SurfaceParams params = new SurfaceParams.Builder(surfaceControl)
+ .withMatrix(mMoveTransform)
+ .build();
+ if (pipLeash != null && t != null) {
+ SurfaceParams pipParams = new SurfaceParams.Builder(pipLeash)
+ .withMergeTransaction(t)
+ .build();
+ mApplier.scheduleApply(params, pipParams);
+ } else {
+ mApplier.scheduleApply(params);
+ }
+ }
+
+ /**
+ * Does an immediate window crop of the PiP menu.
+ */
+ public void resizePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds) {
+ if (destinationBounds.isEmpty()) {
+ return;
+ }
+
+ if (!maybeCreateSyncApplier()) {
+ return;
+ }
+
+ SurfaceControl surfaceControl = getSurfaceControl();
+ SurfaceParams params = new SurfaceParams.Builder(surfaceControl)
+ .withWindowCrop(destinationBounds)
+ .build();
+ if (pipLeash != null && t != null) {
+ SurfaceParams pipParams = new SurfaceParams.Builder(pipLeash)
+ .withMergeTransaction(t)
+ .build();
+ mApplier.scheduleApply(params, pipParams);
+ } else {
+ mApplier.scheduleApply(params);
+ }
+ }
+
+ private boolean maybeCreateSyncApplier() {
+ if (mPipMenuView == null) {
+ Log.v(TAG, "Not going to move PiP since the menu is not created.");
+ return false;
+ }
+
+ if (mApplier == null) {
+ mApplier = new SyncRtSurfaceTransactionApplier(mPipMenuView);
+ mPipMenuInputToken = mPipMenuView.getViewRootImpl().getInputToken();
+ }
+
+ return mApplier != null;
+ }
+
+ /**
* Pokes the menu, indicating that the user is interacting with it.
*/
public void pokeMenu() {
@@ -296,8 +415,13 @@ public class PipMenuActivityController {
* @param height the PIP stack height.
*/
public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
- return new WindowManager.LayoutParams(width, height,
- WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSLUCENT);
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
+ TYPE_APPLICATION_OVERLAY,
+ FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
+ PixelFormat.TRANSLUCENT);
+
+ lp.setTitle(MENU_WINDOW_TITLE);
+ return lp;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 3e06ec44989e..6e3cd8e9aa09 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -32,6 +32,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.app.PendingIntent.CanceledException;
import android.app.RemoteAction;
import android.content.ComponentName;
@@ -50,8 +51,10 @@ import android.util.Pair;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
@@ -268,10 +271,12 @@ public class PipMenuView extends FrameLayout {
return;
}
mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
+ setVisibility(VISIBLE);
mMenuContainerAnimator.start();
});
} else {
notifyMenuStateChange(menuState, resizeMenuOnShow, null);
+ setVisibility(VISIBLE);
mMenuContainerAnimator.start();
}
} else {
@@ -283,6 +288,18 @@ public class PipMenuView extends FrameLayout {
}
}
+ @Nullable SurfaceControl getWindowSurfaceControl() {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ final SurfaceControl out = root.getSurfaceControl();
+ if (out != null && out.isValid()) {
+ return out;
+ }
+ return null;
+ }
+
/**
* Different from {@link #hideMenu()}, this function does not try to finish this menu activity
* and instead, it fades out the controls by setting the alpha to 0 directly without menu
@@ -338,6 +355,7 @@ public class PipMenuView extends FrameLayout {
mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ setVisibility(GONE);
if (animationFinishedRunnable != null) {
animationFinishedRunnable.run();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
index 0b4e17c27398..f2becc99eae8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/DividerWindowManager.java
@@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
import android.graphics.PixelFormat;
import android.graphics.Region;
@@ -63,7 +64,7 @@ final class DividerWindowManager {
view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
- mSystemWindows.addView(view, mLp, displayId, TYPE_DOCK_DIVIDER);
+ mSystemWindows.addView(view, mLp, displayId, SHELL_ROOT_LAYER_DIVIDER);
mView = view;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 1d10a84c53b9..ccc679797472 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -41,6 +41,8 @@ import android.window.WindowContainerToken;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.pip.phone.PipMenuActivityController;
import com.android.wm.shell.splitscreen.SplitScreen;
import org.junit.Before;
@@ -62,10 +64,12 @@ public class PipTaskOrganizerTest extends PipTestCase {
@Mock private DisplayController mMockdDisplayController;
@Mock private PipBoundsHandler mMockPipBoundsHandler;
+ @Mock private PipMenuActivityController mMenuActivityController;
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
@Mock private PipUiEventLogger mMockPipUiEventLogger;
@Mock private Optional<SplitScreen> mMockOptionalSplitScreen;
@Mock private ShellTaskOrganizer mMockShellTaskOrganizer;
+ @Mock private SystemWindows mSystemWindows;
private PipBoundsState mPipBoundsState;
private ComponentName mComponent1;
@@ -78,8 +82,9 @@ public class PipTaskOrganizerTest extends PipTestCase {
mComponent2 = new ComponentName(mContext, "component2");
mPipBoundsState = new PipBoundsState();
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
- mMockPipBoundsHandler, mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen,
- mMockdDisplayController, mMockPipUiEventLogger, mMockShellTaskOrganizer));
+ mMockPipBoundsHandler, mMenuActivityController, mMockPipSurfaceTransactionHelper,
+ mMockOptionalSplitScreen, mMockdDisplayController, mMockPipUiEventLogger,
+ mMockShellTaskOrganizer, mSystemWindows));
preparePipTaskOrg();
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index b7efa7c4c5ac..bbabaf429859 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.WMSingleton;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipBoundsState;
@@ -106,9 +107,10 @@ public abstract class TvPipModule {
PipBoundsHandler pipBoundsHandler,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
- PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
+ SystemWindows systemWindows) {
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
- pipSurfaceTransactionHelper, splitScreenOptional, displayController,
- pipUiEventLogger, shellTaskOrganizer);
+ null /* menuActivityController */, pipSurfaceTransactionHelper, splitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, systemWindows);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index b6fbd589ae2c..1ca04af393ff 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -106,9 +106,9 @@ public class WMShellModule {
@WMSingleton
@Provides
- static PipMenuActivityController providePipMenuActivityController(Context context,
- PipMediaController pipMediaController, PipTaskOrganizer pipTaskOrganizer) {
- return new PipMenuActivityController(context, pipMediaController, pipTaskOrganizer);
+ static PipMenuActivityController providesPipMenuActivityController(Context context,
+ PipMediaController pipMediaController, SystemWindows systemWindows) {
+ return new PipMenuActivityController(context, pipMediaController, systemWindows);
}
@WMSingleton
@@ -128,11 +128,13 @@ public class WMShellModule {
static PipTaskOrganizer providePipTaskOrganizer(Context context,
PipBoundsState pipBoundsState,
PipBoundsHandler pipBoundsHandler,
+ PipMenuActivityController menuActivityController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
- PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
+ PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer,
+ SystemWindows systemWindows) {
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsHandler,
- pipSurfaceTransactionHelper, splitScreenOptional, displayController,
- pipUiEventLogger, shellTaskOrganizer);
+ menuActivityController, pipSurfaceTransactionHelper, splitScreenOptional,
+ displayController, pipUiEventLogger, shellTaskOrganizer, systemWindows);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 26c5d70a2c45..6453ddf80faa 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1084,23 +1084,24 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return token;
}
- SurfaceControl addShellRoot(@NonNull IWindow client, int windowType) {
- ShellRoot root = mShellRoots.get(windowType);
+ SurfaceControl addShellRoot(@NonNull IWindow client,
+ @WindowManager.ShellRootLayer int shellRootLayer) {
+ ShellRoot root = mShellRoots.get(shellRootLayer);
if (root != null) {
if (root.getClient() == client) {
return root.getSurfaceControl();
}
root.clear();
- mShellRoots.remove(windowType);
+ mShellRoots.remove(shellRootLayer);
}
- root = new ShellRoot(client, this, windowType);
+ root = new ShellRoot(client, this, shellRootLayer);
SurfaceControl rootLeash = root.getSurfaceControl();
if (rootLeash == null) {
// Root didn't finish initializing, so don't add it.
root.clear();
return null;
}
- mShellRoots.put(windowType, root);
+ mShellRoots.put(shellRootLayer, root);
SurfaceControl out = new SurfaceControl(rootLeash, "DisplayContent.addShellRoot");
return out;
}
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 759f341c0fe0..62c0527dfe1b 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -16,7 +16,10 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
+import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
@@ -31,6 +34,7 @@ import android.view.DisplayInfo;
import android.view.IWindow;
import android.view.SurfaceControl;
import android.view.WindowInfo;
+import android.view.WindowManager;
import android.view.animation.Animation;
/**
@@ -39,6 +43,7 @@ import android.view.animation.Animation;
public class ShellRoot {
private static final String TAG = "ShellRoot";
private final DisplayContent mDisplayContent;
+ private final int mShellRootLayer;
private IWindow mClient;
private WindowToken mToken;
private final IBinder.DeathRecipient mDeathRecipient;
@@ -46,17 +51,31 @@ public class ShellRoot {
private IWindow mAccessibilityWindow;
private IBinder.DeathRecipient mAccessibilityWindowDeath;
- ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc, final int windowType) {
+ ShellRoot(@NonNull IWindow client, @NonNull DisplayContent dc,
+ @WindowManager.ShellRootLayer final int shellRootLayer) {
mDisplayContent = dc;
- mDeathRecipient = () -> mDisplayContent.removeShellRoot(windowType);
+ mShellRootLayer = shellRootLayer;
+ mDeathRecipient = () -> mDisplayContent.removeShellRoot(shellRootLayer);
try {
client.asBinder().linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to add shell root for layer " + windowType + " on display "
+ Slog.e(TAG, "Unable to add shell root layer " + shellRootLayer + " on display "
+ dc.getDisplayId(), e);
return;
}
mClient = client;
+ int windowType;
+ switch (shellRootLayer) {
+ case SHELL_ROOT_LAYER_DIVIDER:
+ windowType = TYPE_DOCK_DIVIDER;
+ break;
+ case SHELL_ROOT_LAYER_PIP:
+ windowType = TYPE_APPLICATION_OVERLAY;
+ break;
+ default:
+ throw new IllegalArgumentException(shellRootLayer
+ + " is not an acceptable shell root layer.");
+ }
mToken = new WindowToken(
dc.mWmService, client.asBinder(), windowType, true, dc, true, false);
mSurfaceControl = mToken.makeChildSurface(null)
@@ -111,10 +130,16 @@ public class ShellRoot {
}
WindowInfo getWindowInfo() {
- if (mToken.windowType != TYPE_DOCK_DIVIDER) {
+ if (mShellRootLayer != SHELL_ROOT_LAYER_DIVIDER
+ && mShellRootLayer != SHELL_ROOT_LAYER_PIP) {
+ return null;
+ }
+ if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER
+ && !mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
return null;
}
- if (!mDisplayContent.getDefaultTaskDisplayArea().isSplitScreenModeActivated()) {
+ if (mShellRootLayer == SHELL_ROOT_LAYER_PIP
+ && mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask() == null) {
return null;
}
if (mAccessibilityWindow == null) {
@@ -125,13 +150,25 @@ public class ShellRoot {
windowInfo.type = mToken.windowType;
windowInfo.layer = mToken.getWindowLayerFromType();
windowInfo.token = mAccessibilityWindow.asBinder();
- windowInfo.title = "Splitscreen Divider";
windowInfo.focused = false;
- windowInfo.inPictureInPicture = false;
windowInfo.hasFlagWatchOutsideTouch = false;
final Rect regionRect = new Rect();
- mDisplayContent.getDockedDividerController().getTouchRegion(regionRect);
- windowInfo.regionInScreen.set(regionRect);
+
+
+ // DividerView
+ if (mShellRootLayer == SHELL_ROOT_LAYER_DIVIDER) {
+ windowInfo.inPictureInPicture = false;
+ mDisplayContent.getDockedDividerController().getTouchRegion(regionRect);
+ windowInfo.regionInScreen.set(regionRect);
+ windowInfo.title = "Splitscreen Divider";
+ }
+ // PipMenuView
+ if (mShellRootLayer == SHELL_ROOT_LAYER_PIP) {
+ windowInfo.inPictureInPicture = true;
+ mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask().getBounds(regionRect);
+ windowInfo.regionInScreen.set(regionRect);
+ windowInfo.title = "Picture-in-Picture menu";
+ }
return windowInfo;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 136b4163ee4d..084b7667b5a5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4035,7 +4035,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public SurfaceControl addShellRoot(int displayId, IWindow client, int windowType) {
+ public SurfaceControl addShellRoot(int displayId, IWindow client,
+ @WindowManager.ShellRootLayer int shellRootLayer) {
if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
@@ -4047,7 +4048,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (dc == null) {
return null;
}
- return dc.addShellRoot(client, windowType);
+ return dc.addShellRoot(client, shellRootLayer);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4055,7 +4056,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void setShellRootAccessibilityWindow(int displayId, int windowType, IWindow target) {
+ public void setShellRootAccessibilityWindow(int displayId,
+ @WindowManager.ShellRootLayer int shellRootLayer, IWindow target) {
if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS);
@@ -4067,7 +4069,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (dc == null) {
return;
}
- ShellRoot root = dc.mShellRoots.get(windowType);
+ ShellRoot root = dc.mShellRoots.get(shellRootLayer);
if (root == null) {
return;
}