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

Commit 8759f138 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce fixed rotation transform"

parents 48b2f066 6f548e99
Loading
Loading
Loading
Loading
+40 −21
Original line number Diff line number Diff line
@@ -6224,6 +6224,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        return mRemoteAnimationDefinition;
    }

    @Override
    void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
            Configuration config) {
        super.applyFixedRotationTransform(info, displayFrames, config);
        ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
    }

    void setRequestedOrientation(int requestedOrientation) {
        setOrientation(requestedOrientation, mayFreezeScreenLocked());
        mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged(
@@ -6462,11 +6469,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A

    @Override
    void resolveOverrideConfiguration(Configuration newParentConfiguration) {
        Configuration resolvedConfig = getResolvedOverrideConfiguration();
        super.resolveOverrideConfiguration(newParentConfiguration);
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        if (isFixedRotationTransforming()) {
            // The resolved configuration is applied with rotated display configuration. If this
            // activity matches its parent (the following resolving procedures are no-op), then it
            // can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio),
            // the rotated configuration is used as parent configuration to compute the actual
            // resolved configuration. It is like putting the activity in a rotated container.
            mTmpConfig.setTo(resolvedConfig);
            newParentConfiguration = mTmpConfig;
        }
        if (mCompatDisplayInsets != null) {
            resolveSizeCompatModeConfiguration(newParentConfiguration);
        } else {
            super.resolveOverrideConfiguration(newParentConfiguration);
            // We ignore activities' requested orientation in multi-window modes. Task level may
            // take them into consideration when calculating bounds.
            if (getParent() != null && getParent().inMultiWindowMode()) {
@@ -6495,7 +6511,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
     * inheriting the parent bounds.
     */
    private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) {
        super.resolveOverrideConfiguration(newParentConfiguration);
        final Configuration resolvedConfig = getResolvedOverrideConfiguration();
        final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds();

@@ -6669,15 +6684,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        mTmpPrevBounds.set(getBounds());
        super.onConfigurationChanged(newParentConfig);

        if (shouldUseSizeCompatMode()) {
            final Rect overrideBounds = getResolvedOverrideBounds();
        if (task != null && !overrideBounds.isEmpty()
                // If the changes come from change-listener, the incoming parent configuration is
                // still the old one. Make sure their orientations are the same to reduce computing
                // the compatibility bounds for the intermediate state.
                && (task.getConfiguration().orientation == newParentConfig.orientation)) {
            if (task != null && !overrideBounds.isEmpty()) {
                final Rect taskBounds = task.getBounds();
            // Since we only center the activity horizontally, if only the fixed height is smaller
            // than its container, the override bounds don't need to take effect.
                // Since we only center the activity horizontally, if only the fixed height is
                // smaller than its container, the override bounds don't need to take effect.
                if ((overrideBounds.width() != taskBounds.width()
                        || overrideBounds.height() > taskBounds.height())) {
                    calculateCompatBoundsTransformation(newParentConfig);
@@ -6692,6 +6704,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
                mSizeCompatScale = 1f;
                updateSurfacePosition();
            }
        }

        final int newWinMode = getWindowingMode();
        if ((prevWinMode != newWinMode) && (mDisplayContent != null)
@@ -7710,6 +7723,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
            return;
        }
        win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
        if (isFixedRotationTransforming()) {
            // This activity has been rotated but the display is still in old rotation. Because the
            // animation applies in display space coordinates, the rotated animation frames need to
            // be unrotated to avoid being cropped.
            unrotateAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
        }
    }

    void setPictureInPictureParams(PictureInPictureParams p) {
+7 −0
Original line number Diff line number Diff line
@@ -528,6 +528,12 @@ public class AppTransition implements Dump {
        }
    }

    private void notifyAppTransitionTimeoutLocked() {
        for (int i = 0; i < mListeners.size(); i++) {
            mListeners.get(i).onAppTransitionTimeoutLocked();
        }
    }

    private int notifyAppTransitionStartingLocked(int transit, long duration,
            long statusBarAnimationStartTime, long statusBarAnimationDuration) {
        int redoLayout = 0;
@@ -2300,6 +2306,7 @@ public class AppTransition implements Dump {
            if (dc == null) {
                return;
            }
            notifyAppTransitionTimeoutLocked();
            if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
                    || !dc.mChangingApps.isEmpty()) {
                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+3 −12
Original line number Diff line number Diff line
@@ -113,13 +113,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
     * @see #mFullConfiguration
     */
    public void onConfigurationChanged(Configuration newParentConfig) {
        onConfigurationChanged(newParentConfig, true /*forwardToChildren*/);
    }

    // TODO(root-unify): Consolidate with onConfigurationChanged() method above once unification is
    //  done. This is only currently need during the process of unification where we don't want
    //  configuration forwarded to a child from both parents.
    public void onConfigurationChanged(Configuration newParentConfig, boolean forwardToChildren) {
        mResolvedTmpConfig.setTo(mResolvedOverrideConfiguration);
        resolveOverrideConfiguration(newParentConfig);
        mFullConfiguration.setTo(newParentConfig);
@@ -141,13 +134,11 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
            mChangeListeners.get(i).onMergedOverrideConfigurationChanged(
                    mMergedOverrideConfiguration);
        }
        if (forwardToChildren) {
        for (int i = getChildCount() - 1; i >= 0; --i) {
            final ConfigurationContainer child = getChildAt(i);
            child.onConfigurationChanged(mFullConfiguration);
        }
    }
    }

    /**
     * Resolves the current requested override configuration into
+200 −33
Original line number Diff line number Diff line
@@ -259,6 +259,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        implements WindowManagerPolicy.DisplayContentInfo {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
    private static final String TAG_STACK = TAG + POSTFIX_STACK;
    private static final int NO_ROTATION = -1;

    /** The default scaling mode that scales content automatically. */
    static final int FORCE_SCALING_MODE_AUTO = 0;
@@ -515,6 +516,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     */
    ActivityRecord mFocusedApp = null;

    /**
     * The launching activity which is using fixed rotation transformation.
     *
     * @see #handleTopActivityLaunchingInDifferentOrientation
     */
    ActivityRecord mFixedRotationLaunchingApp;

    /** Windows added since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
    final ArrayList<WindowState> mWinAddedSinceNullFocus = new ArrayList<>();

@@ -1308,6 +1316,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        if (mDisplayRotation.isWaitingForRemoteRotation()) {
            return;
        }
        // Clear the record because the display will sync to current rotation.
        mFixedRotationLaunchingApp = null;

        final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
        if (configUpdated) {
            return;
@@ -1367,7 +1378,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
     *         {@link #sendNewConfiguration} if the method returns {@code true}.
     */
    boolean updateOrientation() {
        return mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */);
        return updateOrientation(false /* forceUpdate */);
    }

    /**
@@ -1390,7 +1401,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        }

        Configuration config = null;
        if (mDisplayRotation.updateOrientation(getOrientation(), forceUpdate)) {
        if (updateOrientation(forceUpdate)) {
            // If we changed the orientation but mOrientationChangeComplete is already true,
            // we used seamless rotation, and we don't need to freeze the screen.
            if (freezeDisplayToken != null && !mWmService.mRoot.mOrientationChangeComplete) {
@@ -1421,6 +1432,126 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        return config;
    }

    private boolean updateOrientation(boolean forceUpdate) {
        final int orientation = getOrientation();
        // The last orientation source is valid only after getOrientation.
        final WindowContainer orientationSource = getLastOrientationSource();
        final ActivityRecord r =
                orientationSource != null ? orientationSource.asActivityRecord() : null;
        // Currently there is no use case from non-activity.
        if (r != null && handleTopActivityLaunchingInDifferentOrientation(r)) {
            mFixedRotationLaunchingApp = r;
            // Display orientation should be deferred until the top fixed rotation is finished.
            return false;
        }
        return mDisplayRotation.updateOrientation(orientation, forceUpdate);
    }

    /** @return a valid rotation if the activity can use different orientation than the display. */
    @Surface.Rotation
    private int rotationForActivityInDifferentOrientation(@NonNull ActivityRecord r) {
        if (!mWmService.mIsFixedRotationTransformEnabled) {
            return NO_ROTATION;
        }
        if (r.inMultiWindowMode()
                || r.getRequestedConfigurationOrientation() == getConfiguration().orientation) {
            return NO_ROTATION;
        }
        final int currentRotation = getRotation();
        final int rotation = mDisplayRotation.rotationForOrientation(r.getRequestedOrientation(),
                currentRotation);
        if (rotation == currentRotation) {
            return NO_ROTATION;
        }
        return rotation;
    }

    /**
     * We need to keep display rotation fixed for a while when the activity in different orientation
     * is launching until the launch animation is done to avoid showing the previous activity
     * inadvertently in a wrong orientation.
     *
     * @return {@code true} if the fixed rotation is started.
     */
    private boolean handleTopActivityLaunchingInDifferentOrientation(@NonNull ActivityRecord r) {
        if (!mWmService.mIsFixedRotationTransformEnabled) {
            return false;
        }
        if (r.isFinishingFixedRotationTransform()) {
            return false;
        }
        if (r.hasFixedRotationTransform()) {
            // It has been set and not yet finished.
            return true;
        }
        if (!mAppTransition.isTransitionSet()) {
            // Apply normal rotation animation in case of the activity set different requested
            // orientation without activity switch.
            return false;
        }
        if (!mOpeningApps.contains(r)
                // Without screen rotation, the rotation behavior of non-top visible activities is
                // undefined. So the fixed rotated activity needs to cover the screen.
                && r.findMainWindow() != mDisplayPolicy.getTopFullscreenOpaqueWindow()) {
            return false;
        }
        final int rotation = rotationForActivityInDifferentOrientation(r);
        if (rotation == NO_ROTATION) {
            return false;
        }
        if (!r.getParent().matchParentBounds()) {
            // Because the fixed rotated configuration applies to activity directly, if its parent
            // has it own policy for bounds, the activity bounds based on parent is unknown.
            return false;
        }

        startFixedRotationTransform(r, rotation);
        mAppTransition.registerListenerLocked(new WindowManagerInternal.AppTransitionListener() {
            void done() {
                r.clearFixedRotationTransform();
                mAppTransition.unregisterListener(this);
            }

            @Override
            public void onAppTransitionFinishedLocked(IBinder token) {
                if (token == r.token) {
                    done();
                }
            }

            @Override
            public void onAppTransitionCancelledLocked(int transit) {
                done();
            }

            @Override
            public void onAppTransitionTimeoutLocked() {
                done();
            }
        });
        return true;
    }

    /** @return {@code true} if the display orientation will be changed. */
    boolean continueUpdateOrientationForDiffOrienLaunchingApp(WindowToken token) {
        if (token != mFixedRotationLaunchingApp) {
            return false;
        }
        if (updateOrientation()) {
            sendNewConfiguration();
            return true;
        }
        return false;
    }

    private void startFixedRotationTransform(WindowToken token, int rotation) {
        mTmpConfiguration.unset();
        final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
        final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
        final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, info, cutout);
        token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
    }

    /**
     * Update rotation of the display.
     *
@@ -1621,6 +1752,63 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
    }

    /**
     * Compute display info and configuration according to the given rotation without changing
     * current display.
     */
    DisplayInfo computeScreenConfiguration(Configuration outConfig, int rotation) {
        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
        final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
        final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
        outConfig.windowConfiguration.getBounds().set(0, 0, dw, dh);

        final int uiMode = getConfiguration().uiMode;
        final DisplayCutout displayCutout =
                calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
        computeScreenAppConfiguration(outConfig, dw, dh, rotation, uiMode, displayCutout);

        final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
        displayInfo.rotation = rotation;
        displayInfo.logicalWidth = dw;
        displayInfo.logicalHeight = dh;
        final Rect appBounds = outConfig.windowConfiguration.getAppBounds();
        displayInfo.appWidth = appBounds.width();
        displayInfo.appHeight = appBounds.height();
        displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
        computeSizeRangesAndScreenLayout(displayInfo, rotated, uiMode, dw, dh,
                mDisplayMetrics.density, outConfig);
        return displayInfo;
    }

    /** Compute configuration related to application without changing current display. */
    private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,
            int rotation, int uiMode, DisplayCutout displayCutout) {
        final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
                displayCutout);
        final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
                displayCutout);
        mDisplayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
        final int leftInset = mTmpRect.left;
        final int topInset = mTmpRect.top;
        // AppBounds at the root level should mirror the app screen size.
        outConfig.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,
                leftInset + appWidth /* right */, topInset + appHeight /* bottom */);
        outConfig.windowConfiguration.setRotation(rotation);
        outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;

        final float density = mDisplayMetrics.density;
        outConfig.screenWidthDp = (int) (mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation,
                uiMode, displayCutout) / density);
        outConfig.screenHeightDp = (int) (mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation,
                uiMode, displayCutout) / density);
        outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
        outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);

        final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
        outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, uiMode, dw,
                dh, displayCutout);
    }

    /**
     * Compute display configuration based on display properties and policy settings.
     * Do not call if mDisplayReady == false.
@@ -1629,42 +1817,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config);
        calculateBounds(displayInfo, mTmpBounds);
        config.windowConfiguration.setBounds(mTmpBounds);

        final int dw = displayInfo.logicalWidth;
        final int dh = displayInfo.logicalHeight;
        config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
        config.windowConfiguration.setWindowingMode(getWindowingMode());
        config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
        config.windowConfiguration.setRotation(displayInfo.rotation);

        final float density = mDisplayMetrics.density;
        config.screenWidthDp =
                (int)(mDisplayPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
                        config.uiMode, displayInfo.displayCutout) / density);
        config.screenHeightDp =
                (int)(mDisplayPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
                        config.uiMode, displayInfo.displayCutout) / density);

        mDisplayPolicy.getNonDecorInsetsLw(displayInfo.rotation, dw, dh,
                displayInfo.displayCutout, mTmpRect);
        final int leftInset = mTmpRect.left;
        final int topInset = mTmpRect.top;
        // appBounds at the root level should mirror the app screen size.
        config.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,
                leftInset + displayInfo.appWidth /* right */,
                topInset + displayInfo.appHeight /* bottom */);
        final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
                || displayInfo.rotation == Surface.ROTATION_270);
        final int dw = displayInfo.logicalWidth;
        final int dh = displayInfo.logicalHeight;
        computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation, config.uiMode,
                displayInfo.displayCutout);

        config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
                | ((displayInfo.flags & Display.FLAG_ROUND) != 0
                ? Configuration.SCREENLAYOUT_ROUND_YES
                : Configuration.SCREENLAYOUT_ROUND_NO);

        config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
        config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
        config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
                dh, displayInfo.displayCutout);
        config.densityDpi = displayInfo.logicalDensityDpi;

        config.colorMode =
@@ -2111,19 +2276,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    /**
     * In the general case, the orientation is computed from the above app windows first. If none of
     * the above app windows specify orientation, the orientation is computed from the child window
     * container, e.g. {@link AppWindowToken#getOrientation(int)}.
     * container, e.g. {@link ActivityRecord#getOrientation(int)}.
     */
    @ScreenOrientation
    @Override
    int getOrientation() {
        final WindowManagerPolicy policy = mWmService.mPolicy;
        mLastOrientationSource = null;

        if (mIgnoreRotationForApps) {
            return SCREEN_ORIENTATION_USER;
        }

        if (mWmService.mDisplayFrozen) {
            if (policy.isKeyguardLocked()) {
            if (mWmService.mPolicy.isKeyguardLocked()) {
                // Use the last orientation the while the display is frozen with the keyguard
                // locked. This could be the keyguard forced orientation or from a SHOW_WHEN_LOCKED
                // window. We don't want to check the show when locked window directly though as
@@ -2135,7 +2300,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                return getLastOrientation();
            }
        }
        return mRootDisplayArea.getOrientation();
        final int rootOrientation = mRootDisplayArea.getOrientation();
        mLastOrientationSource = mRootDisplayArea.getLastOrientationSource();
        return rootOrientation;
    }

    void updateDisplayInfo() {
+5 −4
Original line number Diff line number Diff line
@@ -1430,7 +1430,7 @@ public class DisplayPolicy {
        }
    }

    private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames, int uiMode,
    private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
            InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) {
        win.setSimulatedWindowFrames(simulatedWindowFrames);
        try {
@@ -1454,7 +1454,7 @@ public class DisplayPolicy {
        final WindowFrames simulatedWindowFrames = new WindowFrames();
        if (mNavigationBar != null) {
            simulateLayoutDecorWindow(
                    mNavigationBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
                    mNavigationBar, displayFrames, insetsState, simulatedWindowFrames,
                    () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible,
                            mLastNavTranslucent, mLastNavAllowedHidden,
                            mLastNotificationShadeForcesShowingNavigation,
@@ -1462,7 +1462,7 @@ public class DisplayPolicy {
        }
        if (mStatusBar != null) {
            simulateLayoutDecorWindow(
                    mStatusBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
                    mStatusBar, displayFrames, insetsState, simulatedWindowFrames,
                    () -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
                            false /* isRealLayout */));
        }
@@ -1536,7 +1536,7 @@ public class DisplayPolicy {
        if (updateSysUiVisibility) {
            updateSystemUiVisibilityLw();
        }
        layoutScreenDecorWindows(displayFrames, null /* transientFrames */);
        layoutScreenDecorWindows(displayFrames, null /* simulatedFrames */);
        postAdjustDisplayFrames(displayFrames);
        mLastNavVisible = navVisible;
        mLastNavTranslucent = navTranslucent;
@@ -1939,6 +1939,7 @@ public class DisplayPolicy {
        final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
        final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);

        displayFrames = win.getDisplayFrames(displayFrames);
        final WindowFrames windowFrames = win.getWindowFrames();

        sTmpLastParentFrame.set(windowFrames.mParentFrame);
Loading