[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
This commit is contained in:
Hongwei Wang
2020-08-25 18:03:18 -07:00
parent 128ad1be22
commit a2673cdfd4
5 changed files with 112 additions and 13 deletions

View File

@@ -176,6 +176,13 @@ public class TaskInfo {
*/ */
public boolean isResizeable; public boolean isResizeable;
/**
* Screen orientation set by {@link #baseActivity} via
* {@link Activity#setRequestedOrientation(int)}.
* @hide
*/
public @ActivityInfo.ScreenOrientation int requestedOrientation;
TaskInfo() { TaskInfo() {
// Do nothing // Do nothing
} }
@@ -247,6 +254,7 @@ public class TaskInfo {
? ActivityInfo.CREATOR.createFromParcel(source) ? ActivityInfo.CREATOR.createFromParcel(source)
: null; : null;
isResizeable = source.readBoolean(); isResizeable = source.readBoolean();
requestedOrientation = source.readInt();
} }
/** /**
@@ -297,6 +305,7 @@ public class TaskInfo {
topActivityInfo.writeToParcel(dest, flags); topActivityInfo.writeToParcel(dest, flags);
} }
dest.writeBoolean(isResizeable); dest.writeBoolean(isResizeable);
dest.writeInt(requestedOrientation);
} }
@Override @Override
@@ -315,6 +324,7 @@ public class TaskInfo {
+ " token=" + token + " token=" + token
+ " topActivityType=" + topActivityType + " topActivityType=" + topActivityType
+ " pictureInPictureParams=" + pictureInPictureParams + " pictureInPictureParams=" + pictureInPictureParams
+ " topActivityInfo=" + topActivityInfo; + " topActivityInfo=" + topActivityInfo
+ " requestedOrientation=" + requestedOrientation;
} }
} }

View File

@@ -40,7 +40,6 @@ import android.app.PictureInPictureParams;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
@@ -104,7 +103,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
private final Rect mLastReportedBounds = new Rect(); private final Rect mLastReportedBounds = new Rect();
private final int mEnterExitAnimationDuration; private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Map<IBinder, Configuration> mInitialState = new HashMap<>(); private final Map<IBinder, PipWindowConfigurationCompact> mCompactState = new HashMap<>();
private final Divider mSplitDivider; private final Divider mSplitDivider;
// These callbacks are called on the update thread // These callbacks are called on the update thread
@@ -202,6 +201,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
*/ */
private boolean mShouldDeferEnteringPip; private boolean mShouldDeferEnteringPip;
private @ActivityInfo.ScreenOrientation int mRequestedOrientation;
@Inject @Inject
public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler, public PipTaskOrganizer(Context context, @NonNull PipBoundsHandler boundsHandler,
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper, @NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@@ -281,11 +282,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements
mPipUiEventLoggerLogger.log( mPipUiEventLoggerLogger.log(
PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN); PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final Configuration initialConfig = mInitialState.remove(mToken.asBinder()); final PipWindowConfigurationCompact config = mCompactState.remove(mToken.asBinder());
final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation() config.syncWithScreenOrientation(mRequestedOrientation,
mPipBoundsHandler.getDisplayRotation());
final boolean orientationDiffers = config.getRotation()
!= mPipBoundsHandler.getDisplayRotation(); != mPipBoundsHandler.getDisplayRotation();
final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction wct = new WindowContainerTransaction();
final Rect destinationBounds = initialConfig.windowConfiguration.getBounds(); final Rect destinationBounds = config.getBounds();
final int direction = syncWithSplitScreenBounds(destinationBounds) final int direction = syncWithSplitScreenBounds(destinationBounds)
? TRANSITION_DIRECTION_TO_SPLIT_SCREEN ? TRANSITION_DIRECTION_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_TO_FULLSCREEN; : TRANSITION_DIRECTION_TO_FULLSCREEN;
@@ -351,7 +354,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
.setPipAnimationCallback(mPipAnimationCallback) .setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration) .setDuration(mEnterExitAnimationDuration)
.start()); .start());
mInitialState.remove(mToken.asBinder()); mCompactState.remove(mToken.asBinder());
mExitingPip = true; mExitingPip = true;
} }
@@ -377,8 +380,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements
mInPip = true; mInPip = true;
mExitingPip = false; mExitingPip = false;
mLeash = leash; mLeash = leash;
mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); mCompactState.put(mToken.asBinder(),
new PipWindowConfigurationCompact(mTaskInfo.configuration.windowConfiguration));
mPictureInPictureParams = mTaskInfo.pictureInPictureParams; mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
mRequestedOrientation = info.requestedOrientation;
mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo); mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER); mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
@@ -521,6 +526,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
@Override @Override
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) { public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken"); Objects.requireNonNull(mToken, "onTaskInfoChanged requires valid existing mToken");
mRequestedOrientation = info.requestedOrientation;
// check PictureInPictureParams for aspect ratio change.
final PictureInPictureParams newParams = info.pictureInPictureParams; final PictureInPictureParams newParams = info.pictureInPictureParams;
if (newParams == null || !applyPictureInPictureParams(newParams)) { if (newParams == null || !applyPictureInPictureParams(newParams)) {
Log.d(TAG, "Ignored onTaskInfoChanged with PiP param: " + 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 * @param destinationBoundsOut the current destination bounds will be populated to this param
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -963,9 +968,9 @@ public class PipTaskOrganizer extends TaskOrganizer implements
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams); pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds); pw.println(innerPrefix + "mLastReportedBounds=" + mLastReportedBounds);
pw.println(innerPrefix + "mInitialState:"); pw.println(innerPrefix + "mInitialState:");
for (Map.Entry<IBinder, Configuration> e : mInitialState.entrySet()) { for (Map.Entry<IBinder, PipWindowConfigurationCompact> e : mCompactState.entrySet()) {
pw.println(innerPrefix + " binder=" + e.getKey() pw.println(innerPrefix + " binder=" + e.getKey()
+ " winConfig=" + e.getValue().windowConfiguration); + " config=" + e.getValue());
} }
} }

View File

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

View File

@@ -3627,6 +3627,9 @@ class Task extends WindowContainer<WindowContainer> {
info.topActivityInfo = mReuseActivitiesReport.top != null info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info ? mReuseActivitiesReport.top.info
: null; : null;
info.requestedOrientation = mReuseActivitiesReport.base != null
? mReuseActivitiesReport.base.getRequestedOrientation()
: SCREEN_ORIENTATION_UNSET;
} }
/** /**

View File

@@ -458,7 +458,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
|| mTmpTaskInfo.topActivityType != lastInfo.topActivityType || mTmpTaskInfo.topActivityType != lastInfo.topActivityType
|| mTmpTaskInfo.isResizeable != lastInfo.isResizeable || mTmpTaskInfo.isResizeable != lastInfo.isResizeable
|| mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams || mTmpTaskInfo.pictureInPictureParams != lastInfo.pictureInPictureParams
|| !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription); || !TaskDescription.equals(mTmpTaskInfo.taskDescription, lastInfo.taskDescription)
|| mTmpTaskInfo.requestedOrientation != lastInfo.requestedOrientation;
if (!changed) { if (!changed) {
int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration); int cfgChanges = mTmpTaskInfo.configuration.diff(lastInfo.configuration);
final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0 final int winCfgChanges = (cfgChanges & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0