Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2673cdf authored by Hongwei Wang's avatar Hongwei Wang
Browse files

[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
parent 128ad1be
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -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;
    }
}
+16 −11
Original line number Diff line number Diff line
@@ -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<IBinder, Configuration> mInitialState = new HashMap<>();
    private final Map<IBinder, PipWindowConfigurationCompact> 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<IBinder, Configuration> e : mInitialState.entrySet()) {
        for (Map.Entry<IBinder, PipWindowConfigurationCompact> e : mCompactState.entrySet()) {
            pw.println(innerPrefix + "  binder=" + e.getKey()
                    + " winConfig=" + e.getValue().windowConfiguration);
                    + " config=" + e.getValue());
        }
    }

+80 −0
Original line number Diff line number Diff line
/*
 * 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 + ")";
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -3627,6 +3627,9 @@ class Task extends WindowContainer<WindowContainer> {
        info.topActivityInfo = mReuseActivitiesReport.top != null
                ? mReuseActivitiesReport.top.info
                : null;
        info.requestedOrientation = mReuseActivitiesReport.base != null
                ? mReuseActivitiesReport.base.getRequestedOrientation()
                : SCREEN_ORIENTATION_UNSET;
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -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