From a2673cdfd40db7e2f0f587df66502fdfa29333e3 Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Tue, 25 Aug 2020 18:03:18 -0700 Subject: [PATCH] [DO NOT MERGE] Sync app requested orientation on PiP exit When exiting PiP to fullscreen, SysUI compares the initial rotation with the screen rotation and skips the animation if they are different, with the intention that the app should get back to its state prior to PiP. This generally works well except that app may request setRequestedOrientation after entering PiP and the initial rotation SysUI gets in onTaskAppeared would be obsoleted. This is fixed in this CL by - Adding a requestedOrientation field in TaskInfo to pass this information to SysUI, in both onTaskAppeared and onTaskInfoChanged callbacks - Sync with the requested orientation as well as display rotation on PiP exit. Moves also the information we need into PipWindowConfigurationCompact Video: http://rcll/aaaaaabFQoRHlzixHdtY/gOPXfx5KO9krmzeor49DgG Bug: 163218295 Test: See video Change-Id: Idd0b9412dfdfd6fd293a800cded7c7a6b94cafde --- core/java/android/app/TaskInfo.java | 12 ++- .../systemui/pip/PipTaskOrganizer.java | 27 ++++--- .../pip/PipWindowConfigurationCompact.java | 80 +++++++++++++++++++ .../core/java/com/android/server/wm/Task.java | 3 + .../server/wm/TaskOrganizerController.java | 3 +- 5 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/pip/PipWindowConfigurationCompact.java diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java index f3f00e50715b3..f99d4e937f920 100644 --- a/core/java/android/app/TaskInfo.java +++ b/core/java/android/app/TaskInfo.java @@ -176,6 +176,13 @@ public class TaskInfo { */ public boolean isResizeable; + /** + * Screen orientation set by {@link #baseActivity} via + * {@link Activity#setRequestedOrientation(int)}. + * @hide + */ + public @ActivityInfo.ScreenOrientation int requestedOrientation; + TaskInfo() { // Do nothing } @@ -247,6 +254,7 @@ public class TaskInfo { ? ActivityInfo.CREATOR.createFromParcel(source) : null; isResizeable = source.readBoolean(); + requestedOrientation = source.readInt(); } /** @@ -297,6 +305,7 @@ public class TaskInfo { topActivityInfo.writeToParcel(dest, flags); } dest.writeBoolean(isResizeable); + dest.writeInt(requestedOrientation); } @Override @@ -315,6 +324,7 @@ public class TaskInfo { + " token=" + token + " topActivityType=" + topActivityType + " pictureInPictureParams=" + pictureInPictureParams - + " topActivityInfo=" + topActivityInfo; + + " topActivityInfo=" + topActivityInfo + + " requestedOrientation=" + requestedOrientation; } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index d19fc013bd8d3..8d4ca5e46fae1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -40,7 +40,6 @@ import android.app.PictureInPictureParams; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; -import android.content.res.Configuration; import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; @@ -104,7 +103,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private final Rect mLastReportedBounds = new Rect(); private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; - private final Map mInitialState = new HashMap<>(); + private final Map mCompactState = new HashMap<>(); private final Divider mSplitDivider; // These callbacks are called on the update thread @@ -202,6 +201,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements */ private boolean mShouldDeferEnteringPip; + private @ActivityInfo.ScreenOrientation int mRequestedOrientation; + @Inject public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @@ -281,11 +282,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements mPipUiEventLoggerLogger.log( PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN); - final Configuration initialConfig = mInitialState.remove(mToken.asBinder()); - final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation() + final PipWindowConfigurationCompact config = mCompactState.remove(mToken.asBinder()); + config.syncWithScreenOrientation(mRequestedOrientation, + mPipBoundsHandler.getDisplayRotation()); + final boolean orientationDiffers = config.getRotation() != mPipBoundsHandler.getDisplayRotation(); final WindowContainerTransaction wct = new WindowContainerTransaction(); - final Rect destinationBounds = initialConfig.windowConfiguration.getBounds(); + final Rect destinationBounds = config.getBounds(); final int direction = syncWithSplitScreenBounds(destinationBounds) ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN : TRANSITION_DIRECTION_TO_FULLSCREEN; @@ -351,7 +354,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements .setPipAnimationCallback(mPipAnimationCallback) .setDuration(mEnterExitAnimationDuration) .start()); - mInitialState.remove(mToken.asBinder()); + mCompactState.remove(mToken.asBinder()); mExitingPip = true; } @@ -377,8 +380,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements mInPip = true; mExitingPip = false; mLeash = leash; - mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); + mCompactState.put(mToken.asBinder(), + new PipWindowConfigurationCompact(mTaskInfo.configuration.windowConfiguration)); mPictureInPictureParams = mTaskInfo.pictureInPictureParams; + mRequestedOrientation = info.requestedOrientation; mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo); mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER); @@ -521,6 +526,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken"); + mRequestedOrientation = info.requestedOrientation; + // check PictureInPictureParams for aspect ratio change. final PictureInPictureParams newParams = info.pictureInPictureParams; if (newParams == null || !applyPictureInPictureParams(newParams)) { Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + newParams); @@ -558,8 +565,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements } /** - * TODO(b/152809058): consolidate the display info handling logic in SysUI - * * @param destinationBoundsOut the current destination bounds will be populated to this param */ @SuppressWarnings("unchecked") @@ -963,9 +968,9 @@ public class PipTaskOrganizer extends TaskOrganizer implements pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams); pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds); pw.println(innerPrefix + "mInitialState:"); - for (Map.Entry e : mInitialState.entrySet()) { + for (Map.Entry e : mCompactState.entrySet()) { pw.println(innerPrefix + " binder=" + e.getKey() - + " winConfig=" + e.getValue().windowConfiguration); + + " config=" + e.getValue()); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipWindowConfigurationCompact.java b/packages/SystemUI/src/com/android/systemui/pip/PipWindowConfigurationCompact.java new file mode 100644 index 0000000000000..ba104d676cd2a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/PipWindowConfigurationCompact.java @@ -0,0 +1,80 @@ +/* + * 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.systemui.pip; + +import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; +import static android.view.Surface.ROTATION_0; +import static android.view.Surface.ROTATION_180; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; + +import android.app.WindowConfiguration; +import android.content.pm.ActivityInfo; +import android.graphics.Rect; +import android.view.Surface; + +/** + * Compact {@link WindowConfiguration} for PiP usage and supports operations such as rotate. + */ +class PipWindowConfigurationCompact { + private @Surface.Rotation int mRotation; + private Rect mBounds; + + PipWindowConfigurationCompact(WindowConfiguration windowConfiguration) { + mRotation = windowConfiguration.getRotation(); + mBounds = windowConfiguration.getBounds(); + } + + @Surface.Rotation int getRotation() { + return mRotation; + } + + Rect getBounds() { + return mBounds; + } + + void syncWithScreenOrientation(@ActivityInfo.ScreenOrientation int screenOrientation, + @Surface.Rotation int displayRotation) { + if (mBounds.top != 0 || mBounds.left != 0) { + // Supports fullscreen bounds like (0, 0, width, height) only now. + return; + } + boolean rotateNeeded = false; + if (ActivityInfo.isFixedOrientationPortrait(screenOrientation) + && (mRotation == ROTATION_90 || mRotation == ROTATION_270)) { + mRotation = ROTATION_0; + rotateNeeded = true; + } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation) + && (mRotation == ROTATION_0 || mRotation == ROTATION_180)) { + mRotation = ROTATION_90; + rotateNeeded = true; + } else if (screenOrientation == SCREEN_ORIENTATION_UNSPECIFIED + && mRotation != displayRotation) { + mRotation = displayRotation; + rotateNeeded = true; + } + if (rotateNeeded) { + mBounds.set(0, 0, mBounds.height(), mBounds.width()); + } + } + + @Override + public String toString() { + return "PipWindowConfigurationCompact(rotation=" + mRotation + + " bounds=" + mBounds + ")"; + } +} diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 76927e2774129..954b7a026bf54 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3627,6 +3627,9 @@ class Task extends WindowContainer { info.topActivityInfo = mReuseActivitiesReport.top != null ? mReuseActivitiesReport.top.info : null; + info.requestedOrientation = mReuseActivitiesReport.base != null + ? mReuseActivitiesReport.base.getRequestedOrientation() + : SCREEN_ORIENTATION_UNSET; } /** diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index f70bf18cdea57..e153befde8ad5 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -458,7 +458,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { || mTmpTaskInfo.topActivityType != lastInfo.topActivityType || mTmpTaskInfo.isResizeable != lastInfo.isResizeable || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams - || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription); + || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription) + || mTmpTaskInfo.requestedOrientation != lastInfo.requestedOrientation; if (!changed) { int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration); final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0