Move rotation bounds calculation into SysUI
Also included in this CL
- Cleanup all bounds calculation in PinnedStackController
- Move PipSnapAlgorithm to SysUI
Bug: 139016833
Bug: 139016576
Bug: 145133340
Test: atest PinnedStackTests
Test: atest MultiDisplayActivityLaunchTest
Test: atest MultiDisplaySystemDecorationTests
Change-Id: Ifa0621a1cb69e76498e020aef7d8fa815df4ce48
diff --git a/core/java/android/view/IPinnedStackController.aidl b/core/java/android/view/IPinnedStackController.aidl
index f1d152b..00edb3a 100644
--- a/core/java/android/view/IPinnedStackController.aidl
+++ b/core/java/android/view/IPinnedStackController.aidl
@@ -45,4 +45,17 @@
* {@param animationDuration} suggests the animation duration transitioning to PiP window.
*/
void startAnimation(in Rect destinationBounds, in Rect sourceRectHint, int animationDuration);
+
+ /**
+ * Notifies the controller to reset on bounds animation, if there is any.
+ * This could happen when screen rotation is happening and we need to notify the WM to reset
+ * any running bounds animation on the pinned stack.
+ * {@param bounds} here is the final destination bounds.
+ */
+ void resetBoundsAnimation(in Rect bounds);
+
+ /**
+ * Reports the current default and movement bounds to controller.
+ */
+ void reportBounds(in Rect defaultBounds, in Rect movementBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 75e260e..d1d9b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -20,11 +20,13 @@
import android.content.res.Configuration;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.wm.DisplayWindowController;
import java.io.PrintWriter;
public interface BasePipManager {
- void initialize(Context context, BroadcastDispatcher broadcastDispatcher);
+ void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+ DisplayWindowController displayWindowController);
void showPictureInPictureMenu();
default void expandPip() {}
default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index f10274a..8e34a90 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -16,8 +16,14 @@
package com.android.systemui.pip;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
@@ -32,10 +38,9 @@
import android.view.Gravity;
import android.view.IPinnedStackController;
import android.view.IWindowManager;
+import android.view.WindowContainerTransaction;
import android.view.WindowManagerGlobal;
-import com.android.internal.policy.PipSnapAlgorithm;
-
import java.io.PrintWriter;
/**
@@ -154,6 +159,7 @@
*/
public void onMinimizedStateChanged(boolean minimized) {
mIsMinimized = minimized;
+ mSnapAlgorithm.setMinimized(minimized);
}
/**
@@ -199,6 +205,7 @@
mReentrySnapFraction = INVALID_SNAP_FRACTION;
mReentrySize = null;
mLastPipComponentName = null;
+ mLastDestinationBounds.setEmpty();
}
public Rect getLastDestinationBounds() {
@@ -235,8 +242,9 @@
*/
public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
final Rect destinationBounds;
+ final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
if (bounds == null) {
- destinationBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
+ destinationBounds = new Rect(defaultBounds);
} else {
destinationBounds = new Rect(bounds);
}
@@ -253,12 +261,85 @@
mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
-1 /* animationDuration */);
mLastDestinationBounds.set(destinationBounds);
+ mPinnedStackController.reportBounds(defaultBounds,
+ getMovementBounds(defaultBounds));
} catch (RemoteException e) {
Log.e(TAG, "Failed to start PiP animation from SysUI", e);
}
}
/**
+ * Updates the display info, calculating and returning the new stack and movement bounds in the
+ * new orientation of the device if necessary.
+ *
+ * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise.
+ */
+ public boolean onDisplayRotationChanged(Rect outBounds, int displayId, int fromRotation,
+ int toRotation, WindowContainerTransaction t) {
+ // Bail early if the event is not sent to current {@link #mDisplayInfo}
+ if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
+ return false;
+ }
+
+ // Bail early if the pinned stack is staled.
+ final ActivityManager.StackInfo pinnedStackInfo;
+ try {
+ pinnedStackInfo = ActivityTaskManager.getService()
+ .getStackInfo(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
+ if (pinnedStackInfo == null) return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get StackInfo for pinned stack", e);
+ return false;
+ }
+
+ // Calculate the snap fraction of the current stack along the old movement bounds
+ final Rect postChangeStackBounds = new Rect(mLastDestinationBounds);
+ final float snapFraction = getSnapFraction(postChangeStackBounds);
+
+ // Populate the new {@link #mDisplayInfo}.
+ // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
+ // therefore, the width/height may require a swap first.
+ // Moving forward, we should get the new dimensions after rotation from DisplayLayout.
+ mDisplayInfo.rotation = toRotation;
+ updateDisplayInfoIfNeeded();
+
+ // Calculate the stack bounds in the new orientation based on same fraction along the
+ // rotated movement bounds.
+ final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
+ false /* adjustForIme */);
+ mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
+ snapFraction);
+ if (mIsMinimized) {
+ applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
+ }
+
+ try {
+ outBounds.set(postChangeStackBounds);
+ mLastDestinationBounds.set(outBounds);
+ mPinnedStackController.resetBoundsAnimation(outBounds);
+ mPinnedStackController.reportBounds(outBounds, getMovementBounds(outBounds));
+ t.setBounds(pinnedStackInfo.stackToken, outBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to resize PiP on display rotation", e);
+ }
+ return true;
+ }
+
+ private void updateDisplayInfoIfNeeded() {
+ final boolean updateNeeded;
+ if ((mDisplayInfo.rotation == ROTATION_0) || (mDisplayInfo.rotation == ROTATION_180)) {
+ updateNeeded = (mDisplayInfo.logicalWidth > mDisplayInfo.logicalHeight);
+ } else {
+ updateNeeded = (mDisplayInfo.logicalWidth < mDisplayInfo.logicalHeight);
+ }
+ if (updateNeeded) {
+ final int newLogicalHeight = mDisplayInfo.logicalWidth;
+ mDisplayInfo.logicalWidth = mDisplayInfo.logicalHeight;
+ mDisplayInfo.logicalHeight = newLogicalHeight;
+ }
+ }
+
+ /**
* @return whether the given {@param aspectRatio} is valid.
*/
private boolean isValidPictureInPictureAspectRatio(float aspectRatio) {
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
similarity index 99%
rename from core/java/com/android/internal/policy/PipSnapAlgorithm.java
rename to packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
index e3623c5..f3e707c 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSnapAlgorithm.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.policy;
+package com.android.systemui.pip;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
index 583ce67..29de90b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java
@@ -28,6 +28,7 @@
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.wm.DisplayWindowController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -44,15 +45,17 @@
private final CommandQueue mCommandQueue;
private BasePipManager mPipManager;
private final BroadcastDispatcher mBroadcastDispatcher;
-
+ private final DisplayWindowController mDisplayWindowController;
private boolean mSupportsPip;
@Inject
public PipUI(Context context, CommandQueue commandQueue,
- BroadcastDispatcher broadcastDispatcher) {
+ BroadcastDispatcher broadcastDispatcher,
+ DisplayWindowController displayWindowController) {
super(context);
mBroadcastDispatcher = broadcastDispatcher;
mCommandQueue = commandQueue;
+ mDisplayWindowController = displayWindowController;
}
@Override
@@ -72,7 +75,7 @@
mPipManager = pm.hasSystemFeature(FEATURE_LEANBACK_ONLY)
? com.android.systemui.pip.tv.PipManager.getInstance()
: com.android.systemui.pip.phone.PipManager.getInstance();
- mPipManager.initialize(mContext, mBroadcastDispatcher);
+ mPipManager.initialize(mContext, mBroadcastDispatcher, mDisplayWindowController);
mCommandQueue.addCallback(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index a4707cf..0a89017 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -34,6 +34,7 @@
import android.util.Pair;
import android.view.DisplayInfo;
import android.view.IPinnedStackController;
+import android.view.WindowContainerTransaction;
import com.android.systemui.Dependency;
import com.android.systemui.UiOffloadThread;
@@ -45,6 +46,7 @@
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
import java.io.PrintWriter;
@@ -75,9 +77,22 @@
private PipAppOpsListener mAppOpsListener;
/**
+ * Handler for display rotation changes.
+ */
+ private final DisplayWindowController.OnDisplayWindowRotationController mRotationController = (
+ int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> {
+ final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds,
+ displayId, fromRotation, toRotation, t);
+ if (changed) {
+ updateMovementBounds(mTmpNormalBounds, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */);
+ }
+ };
+
+ /**
* Handler for system task stack changes.
*/
- TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
mTouchHandler.onActivityPinned();
@@ -214,7 +229,8 @@
/**
* Initializes {@link PipManager}.
*/
- public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+ public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+ DisplayWindowController displayWindowController) {
mContext = context;
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
@@ -235,6 +251,7 @@
mMenuController, mInputConsumerController, mPipBoundsHandler);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
+ displayWindowController.addRotationController(mRotationController);
// If SystemUI restart, and it already existed a pinned stack,
// register the pip input consumer to ensure touch can send to it.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index fa60477..6afa0bf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -46,7 +46,7 @@
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.os.SomeArgs;
-import com.android.internal.policy.PipSnapAlgorithm;
+import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.statusbar.FlingAnimationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 2e90a3e..054f573 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -46,9 +46,9 @@
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.policy.PipSnapAlgorithm;
import com.android.systemui.R;
import com.android.systemui.pip.PipBoundsHandler;
+import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.statusbar.FlingAnimationUtils;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 195fca8..696db68 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -55,6 +55,7 @@
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.wm.DisplayWindowController;
import java.util.ArrayList;
import java.util.List;
@@ -228,7 +229,8 @@
/**
* Initializes {@link PipManager}.
*/
- public void initialize(Context context, BroadcastDispatcher broadcastDispatcher) {
+ public void initialize(Context context, BroadcastDispatcher broadcastDispatcher,
+ DisplayWindowController displayWindowController) {
if (mInitialized) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
index ae82115..aa56ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java
@@ -101,10 +101,11 @@
}
DisplayRecord record = new DisplayRecord();
record.mDisplayId = displayId;
- Display display = getDisplay(displayId);
- record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
- : mContext.createDisplayContext(display);
- record.mDisplayLayout = new DisplayLayout(record.mContext, display);
+ // TODO(b/146566787): disabled for MultiDisplayActivityLaunchTests
+ // Display display = getDisplay(displayId);
+ // record.mContext = (displayId == Display.DEFAULT_DISPLAY) ? mContext
+ // : mContext.createDisplayContext(display);
+ // record.mDisplayLayout = new DisplayLayout(record.mContext, display);
mDisplays.put(displayId, record);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayAdded(displayId);
@@ -123,13 +124,14 @@
+ " display.");
return;
}
- Display display = getDisplay(displayId);
- Context perDisplayContext = mContext;
- if (displayId != Display.DEFAULT_DISPLAY) {
- perDisplayContext = mContext.createDisplayContext(display);
- }
- dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
- dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
+ // TODO(b/146566787): disabled for MultiDisplaySystemDecorationTests
+ // Display display = getDisplay(displayId);
+ // Context perDisplayContext = mContext;
+ // if (displayId != Display.DEFAULT_DISPLAY) {
+ // perDisplayContext = mContext.createDisplayContext(display);
+ // }
+ // dr.mContext = perDisplayContext.createConfigurationContext(newConfig);
+ // dr.mDisplayLayout = new DisplayLayout(dr.mContext, display);
for (int i = 0; i < mDisplayChangedListeners.size(); ++i) {
mDisplayChangedListeners.get(i).onDisplayConfigurationChanged(
displayId, newConfig);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 0d6e928..cae205e 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -821,10 +821,7 @@
// Update bounds if applicable
boolean hasNewOverrideBounds = false;
// Use override windowing mode to prevent extra bounds changes if inheriting the mode.
- if (overrideWindowingMode == WINDOWING_MODE_PINNED) {
- // Pinned calculation already includes rotation
- hasNewOverrideBounds = calculatePinnedBoundsForConfigChange(newBounds);
- } else if (!matchParentBounds()) {
+ if ((overrideWindowingMode != WINDOWING_MODE_PINNED) && !matchParentBounds()) {
// If the parent (display) has rotated, rotate our bounds to best-fit where their
// bounds were on the pre-rotated display.
final int newRotation = getWindowConfiguration().getRotation();
@@ -882,9 +879,6 @@
null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
null /* tempOtherTaskBounds */, null /* tempOtherTaskInsetBounds */,
PRESERVE_WINDOWS, true /* deferResume */);
- } else {
- resize(new Rect(newBounds), null /* tempTaskBounds */,
- null /* tempTaskInsetBounds */, PRESERVE_WINDOWS, true /* deferResume */);
}
}
if (prevIsAlwaysOnTop != isAlwaysOnTop()) {
@@ -4102,45 +4096,27 @@
}
/**
- * Updates the passed-in {@code inOutBounds} based on the current state of the
- * pinned controller. This gets run *after* the override configuration is updated, so it's
- * safe to rely on the controller's state in here (though eventually this dependence should
- * be removed).
+ * Reset the current animation running on {@link #mBoundsAnimationTarget}.
*
- * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
- * update pinned controller state.
- *
- * @param inOutBounds the bounds to update (both input and output).
- * @return true if bounds were updated to some non-empty value.
+ * @param destinationBounds the final destination bounds
*/
- boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
- boolean animating = false;
- if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
- animating = true;
- getFinalAnimationBounds(mTmpRect2);
- } else {
- mTmpRect2.set(inOutBounds);
- }
- boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
- mTmpRect2, mTmpRect3);
- if (updated) {
- inOutBounds.set(mTmpRect3);
+ void resetCurrentBoundsAnimation(Rect destinationBounds) {
+ boolean animating = (mBoundsAnimatingRequested || mBoundsAnimating)
+ && !mBoundsAnimationTarget.isEmpty();
- // The final boundary is updated while there is an existing boundary animation. Let's
- // cancel this animation to prevent the obsolete animation overwritten updated bounds.
- if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
- final DisplayContent displayContent = getDisplayContent();
- displayContent.mBoundsAnimationController.getHandler().post(() ->
- displayContent.mBoundsAnimationController.cancel(this));
- }
- // Once we've set the bounds based on the rotation of the old bounds in the new
- // orientation, clear the animation target bounds since they are obsolete, and
- // cancel any currently running animations
- mBoundsAnimationTarget.setEmpty();
- mBoundsAnimationSourceHintBounds.setEmpty();
- mCancelCurrentBoundsAnimation = true;
+ // The final boundary is updated while there is an existing boundary animation. Let's
+ // cancel this animation to prevent the obsolete animation overwritten updated bounds.
+ if (animating && !destinationBounds.equals(mBoundsAnimationTarget)) {
+ final BoundsAnimationController controller =
+ getDisplayContent().mBoundsAnimationController;
+ controller.getHandler().post(() -> controller.cancel(this));
}
- return updated;
+ // Once we've set the bounds based on the rotation of the old bounds in the new
+ // orientation, clear the animation target bounds since they are obsolete, and
+ // cancel any currently running animations
+ mBoundsAnimationTarget.setEmpty();
+ mBoundsAnimationSourceHintBounds.setEmpty();
+ mCancelCurrentBoundsAnimation = true;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f0bc412..fbd25b7 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3302,6 +3302,23 @@
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);
+ }
+
+ 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 /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ PRESERVE_WINDOWS, true /* deferResume */);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index 5dc88b3..9b464c2 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -185,6 +185,10 @@
resume();
};
+ // If this animator is explicitly cancelled when it's in paused state, we should not
+ // attempt to resume the animation. Use this flag to avoid such behavior.
+ private boolean mIsCancelled;
+
BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
@SchedulePipModeChangedState int prevShedulePipModeChangedState,
@@ -221,6 +225,7 @@
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
+ " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState
+ " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
+ mIsCancelled = false;
mFinishAnimationAfterTransition = false;
mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
mFrom.top + mFrozenTaskHeight);
@@ -293,7 +298,7 @@
public void resume() {
if (DEBUG) Slog.d(TAG, "resume:");
mHandler.removeCallbacks(mResumeRunnable);
- super.resume();
+ if (!mIsCancelled) super.resume();
}
@Override
@@ -376,6 +381,7 @@
@Override
public void onAnimationCancel(Animator animation) {
+ mIsCancelled = true;
// Always skip the final resize when the animation is canceled
mSkipFinalResize = true;
mMoveToFullscreen = false;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index a8e7aea..b4f75e5 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -16,38 +16,29 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static com.android.server.wm.PinnedStackControllerProto.DEFAULT_BOUNDS;
import static com.android.server.wm.PinnedStackControllerProto.MOVEMENT_BOUNDS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.annotation.NonNull;
import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Size;
import android.util.Slog;
-import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
import android.view.DisplayInfo;
-import android.view.Gravity;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
-import com.android.internal.policy.PipSnapAlgorithm;
-import com.android.internal.util.Preconditions;
import com.android.server.UiThread;
import java.io.PrintWriter;
@@ -74,7 +65,6 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "PinnedStackController" : TAG_WM;
- private static final float INVALID_SNAP_FRACTION = -1f;
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
private final Handler mHandler = UiThread.getHandler();
@@ -84,7 +74,6 @@
new PinnedStackListenerDeathHandler();
private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
- private final PipSnapAlgorithm mSnapAlgorithm;
// States that affect how the PIP can be manipulated
private boolean mIsMinimized;
@@ -97,13 +86,9 @@
// Used to calculate stack bounds across rotations
private final DisplayInfo mDisplayInfo = new DisplayInfo();
- private final Rect mStableInsets = new Rect();
// The size and position information that describes where the pinned stack will go by default.
- private int mDefaultMinSize;
- private int mDefaultStackGravity;
private float mDefaultAspectRatio;
- private Point mScreenEdgeInsets;
// The aspect ratio bounds of the PIP.
private float mMinAspectRatio;
@@ -111,10 +96,11 @@
// Temp vars for calculation
private final DisplayMetrics mTmpMetrics = new DisplayMetrics();
- private final Rect mTmpInsets = new Rect();
- private final Rect mTmpRect = new Rect();
- private final Point mTmpDisplaySize = new Point();
+ // TODO(b/141200935): remove this when we have default/movement bounds tests in SysUI.
+ // Keep record of the default and movement bounds
+ private final Rect mLastReportedDefaultBounds = new Rect();
+ private final Rect mLastReportedMovementBounds = new Rect();
/**
* The callback object passed to listeners for them to notify the controller of state changes.
@@ -125,7 +111,6 @@
public void setIsMinimized(final boolean isMinimized) {
mHandler.post(() -> {
mIsMinimized = isMinimized;
- mSnapAlgorithm.setMinimized(isMinimized);
});
}
@@ -145,6 +130,27 @@
sourceRectHint, animationDuration, true /* fromFullscreen */);
}
}
+
+ @Override
+ public void resetBoundsAnimation(Rect bounds) {
+ synchronized (mService.mGlobalLock) {
+ if (mDisplayContent.hasPinnedStack()) {
+ final ActivityStack pinnedStack = mDisplayContent.getTopStackInWindowingMode(
+ WINDOWING_MODE_PINNED);
+ if (pinnedStack != null) {
+ pinnedStack.resetCurrentBoundsAnimation(bounds);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void reportBounds(Rect defaultBounds, Rect movementBounds) {
+ synchronized (mService.mGlobalLock) {
+ mLastReportedDefaultBounds.set(defaultBounds);
+ mLastReportedMovementBounds.set(movementBounds);
+ }
+ }
}
/**
@@ -165,7 +171,6 @@
PinnedStackController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
- mSnapAlgorithm = new PipSnapAlgorithm(service.mContext);
mDisplayInfo.copyFrom(mDisplayContent.getDisplayInfo());
reloadResources();
// Initialize the aspect ratio to the default aspect ratio. Don't do this in reload
@@ -183,21 +188,9 @@
*/
private void reloadResources() {
final Resources res = mService.mContext.getResources();
- mDefaultMinSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.default_minimal_size_pip_resizable_task);
mDefaultAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureDefaultAspectRatio);
- final String screenEdgeInsetsDpString = res.getString(
- com.android.internal.R.string.config_defaultPictureInPictureScreenEdgeInsets);
- final Size screenEdgeInsetsDp = !screenEdgeInsetsDpString.isEmpty()
- ? Size.parseSize(screenEdgeInsetsDpString)
- : null;
- mDefaultStackGravity = res.getInteger(
- com.android.internal.R.integer.config_defaultPictureInPictureGravity);
mDisplayContent.getDisplay().getRealMetrics(mTmpMetrics);
- mScreenEdgeInsets = screenEdgeInsetsDp == null ? new Point()
- : new Point(dpToPx(screenEdgeInsetsDp.getWidth(), mTmpMetrics),
- dpToPx(screenEdgeInsetsDp.getHeight(), mTmpMetrics));
mMinAspectRatio = res.getFloat(
com.android.internal.R.dimen.config_pictureInPictureMinAspectRatio);
mMaxAspectRatio = res.getFloat(
@@ -215,7 +208,7 @@
notifyDisplayInfoChanged(mDisplayInfo);
notifyImeVisibilityChanged(mIsImeShowing, mImeHeight);
// The movement bounds notification needs to be sent before the minimized state, since
- // SystemUI may use the bounds to retore the minimized position
+ // SystemUI may use the bounds to restore the minimized position
notifyMovementBoundsChanged(false /* fromImeAdjustment */,
false /* fromShelfAdjustment */);
notifyActionsChanged(mActions);
@@ -257,30 +250,6 @@
}
}
- /**
- * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
- * will apply the default bounds to the provided snap fraction.
- */
- private Rect getDefaultBounds(float snapFraction) {
- synchronized (mService.mGlobalLock) {
- final Rect insetBounds = new Rect();
- getInsetBounds(insetBounds);
-
- final Rect defaultBounds = new Rect();
- final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
- mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
- if (snapFraction != INVALID_SNAP_FRACTION) {
- defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
- final Rect movementBounds = getMovementBounds(defaultBounds);
- mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
- } else {
- Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
- 0, mIsImeShowing ? mImeHeight : 0, defaultBounds);
- }
- return defaultBounds;
- }
- }
-
private void setDisplayInfo(DisplayInfo displayInfo) {
mDisplayInfo.copyFrom(displayInfo);
notifyDisplayInfoChanged(mDisplayInfo);
@@ -300,51 +269,6 @@
}
/**
- * Updates the display info, calculating and returning the new stack and movement bounds in the
- * new orientation of the device if necessary.
- */
- boolean onTaskStackBoundsChanged(Rect targetBounds, Rect outBounds) {
- synchronized (mService.mGlobalLock) {
- final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
- if (isSameDimensionAndRotation(mDisplayInfo, displayInfo)) {
- // No dimension/rotation change, ignore
- outBounds.setEmpty();
- return false;
- } else if (targetBounds.isEmpty()) {
- // The stack is null, we are just initializing the stack, so just store the display
- // info and ignore
- setDisplayInfo(displayInfo);
- outBounds.setEmpty();
- return false;
- }
-
- mTmpRect.set(targetBounds);
- final Rect postChangeStackBounds = mTmpRect;
-
- // Calculate the snap fraction of the current stack along the old movement bounds
- final float snapFraction = getSnapFraction(postChangeStackBounds);
-
- setDisplayInfo(displayInfo);
-
- // Calculate the stack bounds in the new orientation to the same same fraction along the
- // rotated movement bounds.
- final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
- false /* adjustForIme */);
- mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
- snapFraction);
- if (mIsMinimized) {
- applyMinimizedOffset(postChangeStackBounds, postChangeMovementBounds);
- }
-
- notifyMovementBoundsChanged(false /* fromImeAdjustment */,
- false /* fromShelfAdjustment */);
-
- outBounds.set(postChangeStackBounds);
- return true;
- }
- }
-
- /**
* Sets the Ime state and height.
*/
void setAdjustedForIme(boolean adjustedForIme, int imeHeight) {
@@ -400,15 +324,6 @@
notifyPrepareAnimation(sourceRectHint, aspectRatio, stackBounds);
}
- private boolean isSameDimensionAndRotation(@NonNull DisplayInfo display1,
- @NonNull DisplayInfo display2) {
- Preconditions.checkNotNull(display1);
- Preconditions.checkNotNull(display2);
- return ((display1.rotation == display2.rotation)
- && (display1.logicalWidth == display2.logicalWidth)
- && (display1.logicalHeight == display2.logicalHeight));
- }
-
/**
* Notifies listeners that the PIP needs to be adjusted for the IME.
*/
@@ -504,86 +419,11 @@
}
}
- /**
- * @return the bounds on the screen that the PIP can be visible in.
- */
- private void getInsetBounds(Rect outRect) {
- synchronized (mService.mGlobalLock) {
- mDisplayContent.getDisplayPolicy().getStableInsetsLw(mDisplayInfo.rotation,
- mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
- mDisplayInfo.displayCutout, mTmpInsets);
- outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
- mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
- mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
- }
- }
-
- /**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
- */
- private Rect getMovementBounds(Rect stackBounds) {
- synchronized (mService.mGlobalLock) {
- return getMovementBounds(stackBounds, true /* adjustForIme */);
- }
- }
-
- /**
- * @return the movement bounds for the given {@param stackBounds} and the current state of the
- * controller.
- */
- private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
- synchronized (mService.mGlobalLock) {
- final Rect movementBounds = new Rect();
- getInsetBounds(movementBounds);
-
- // Apply the movement bounds adjustments based on the current state.
- // Note that shelf offset does not affect the movement bounds here
- // since it's been taken care of in system UI.
- mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
- (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
- return movementBounds;
- }
- }
-
- /**
- * Applies the minimized offsets to the given stack bounds.
- */
- private void applyMinimizedOffset(Rect stackBounds, Rect movementBounds) {
- synchronized (mService.mGlobalLock) {
- mTmpDisplaySize.set(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
- mService.getStableInsetsLocked(mDisplayContent.getDisplayId(), mStableInsets);
- mSnapAlgorithm.applyMinimizedOffset(stackBounds, movementBounds, mTmpDisplaySize,
- mStableInsets);
- }
- }
-
- /**
- * @return the default snap fraction to apply instead of the default gravity when calculating
- * the default stack bounds when first entering PiP.
- */
- private float getSnapFraction(Rect stackBounds) {
- return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
- }
-
- /**
- * @return the pixels for a given dp value.
- */
- private int dpToPx(float dpValue, DisplayMetrics dm) {
- return (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, dpValue, dm);
- }
-
void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "PinnedStackController");
- pw.print(prefix + " defaultBounds=");
- getDefaultBounds(INVALID_SNAP_FRACTION).printShortString(pw);
- pw.println();
- pw.println(prefix + " mDefaultMinSize=" + mDefaultMinSize);
- pw.println(prefix + " mDefaultStackGravity=" + mDefaultStackGravity);
+ pw.println(prefix + " mLastReportedDefaultBounds=" + mLastReportedDefaultBounds);
+ pw.println(prefix + " mLastReportedMovementBounds=" + mLastReportedMovementBounds);
pw.println(prefix + " mDefaultAspectRatio=" + mDefaultAspectRatio);
- mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
- pw.print(prefix + " movementBounds="); getMovementBounds(mTmpRect).printShortString(pw);
- pw.println();
pw.println(prefix + " mIsImeShowing=" + mIsImeShowing);
pw.println(prefix + " mImeHeight=" + mImeHeight);
pw.println(prefix + " mIsMinimized=" + mIsMinimized);
@@ -606,9 +446,8 @@
void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- getDefaultBounds(INVALID_SNAP_FRACTION).dumpDebug(proto, DEFAULT_BOUNDS);
- mService.getStackBounds(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mTmpRect);
- getMovementBounds(mTmpRect).dumpDebug(proto, MOVEMENT_BOUNDS);
+ mLastReportedDefaultBounds.dumpDebug(proto, DEFAULT_BOUNDS);
+ mLastReportedMovementBounds.dumpDebug(proto, MOVEMENT_BOUNDS);
proto.end(token);
}
}