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

Commit e81a27f4 authored by Andrii Kulian's avatar Andrii Kulian Committed by Android (Google) Code Review
Browse files

Merge changes from topic "rotation_config_update_fixes" into pi-dev

* changes:
  Force-update the orientation of before sending to client
  Update visibility and config at the same time
  Don't update configuration for invisible windows
  Don't let top activity to influence the orientation
parents 50258128 6cdcfe4e
Loading
Loading
Loading
Loading
+28 −25
Original line number Diff line number Diff line
@@ -1360,7 +1360,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    }

    void goToSleep() {
        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        // Ensure visibility without updating configuration, as activities are about to sleep.
        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS,
                false /* updateConfiguration */);

        // Make sure any paused or stopped but visible activities are now sleeping.
        // This ensures that the activity's onStop() is called.
@@ -1829,12 +1831,23 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    }

    /**
     * Make sure that all activities that need to be visible (that is, they
     * currently can be seen by the user) actually are.
     * Make sure that all activities that need to be visible in the stack (that is, they
     * currently can be seen by the user) actually are and update their configuration.
     */
    // TODO: Should be re-worked based on the fact that each task as a stack in most cases.
    final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows) {
        ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
                true /* updateConfiguration */);
    }

    /**
     * Ensure visibility with an option to also update the configuration of visible activities.
     * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
     * @see ActivityStackSupervisor#ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
     */
    // TODO: Should be re-worked based on the fact that each task as a stack in most cases.
    final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows, boolean updateConfiguration) {
        mTopActivityOccludesKeyguard = false;
        mTopDismissingKeyguardActivity = null;
        mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate();
@@ -1886,9 +1899,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                                + " finishing=" + r.finishing + " state=" + r.getState());
                        // First: if this is not the current activity being started, make
                        // sure it matches the current configuration.
                        if (r != starting) {
                            // Ensure activity configuration ignoring stop state since we are
                            // becoming visible.
                        if (r != starting && updateConfiguration) {
                            r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
                                    true /* ignoreStopState */);
                        }
@@ -2608,25 +2619,16 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                boolean notUpdated = true;

                if (mStackSupervisor.isFocusedStack(this)) {

                    // We have special rotation behavior when Keyguard is locked. Make sure all
                    // activity visibilities are set correctly as well as the transition is updated
                    // if needed to get the correct rotation behavior.
                    // We have special rotation behavior when here is some active activity that
                    // requests specific orientation or Keyguard is locked. Make sure all activity
                    // visibilities are set correctly as well as the transition is updated if needed
                    // to get the correct rotation behavior. Otherwise the following call to update
                    // the orientation may cause incorrect configurations delivered to client as a
                    // result of invisible window resize.
                    // TODO: Remove this once visibilities are set correctly immediately when
                    // starting an activity.
                    if (mStackSupervisor.getKeyguardController().isKeyguardLocked()) {
                        mStackSupervisor.ensureActivitiesVisibleLocked(null /* starting */,
                                0 /* configChanges */, false /* preserveWindows */);
                    }
                    final Configuration config = mWindowManager.updateOrientationFromAppTokens(
                            mStackSupervisor.getDisplayOverrideConfiguration(mDisplayId),
                            next.mayFreezeScreenLocked(next.app) ? next.appToken : null,
                                    mDisplayId);
                    if (config != null) {
                        next.frozenBeforeDestroy = true;
                    }
                    notUpdated = !mService.updateDisplayOverrideConfigurationLocked(config, next,
                            false /* deferResume */, mDisplayId);
                    notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                            true /* markFrozenIfConfigChanged */, false /* deferResume */);
                }

                if (notUpdated) {
@@ -3834,7 +3836,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
            if (finishingActivityInNonFocusedStack) {
                // Finishing activity that was in paused state and it was in not currently focused
                // stack, need to make something visible in its place.
                mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                mStackSupervisor.ensureVisibilityAndConfig(null, mDisplayId,
                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
            }
            if (activityRemoved) {
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
+42 −7
Original line number Diff line number Diff line
@@ -1409,15 +1409,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
            // manager with a new orientation.  We don't care about that, because the activity is
            // not currently running so we are just restarting it anyway.
            if (checkConfig) {
                final int displayId = r.getDisplayId();
                final Configuration config = mWindowManager.updateOrientationFromAppTokens(
                        getDisplayOverrideConfiguration(displayId),
                        r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId);
                // Deferring resume here because we're going to launch new activity shortly.
                // We don't want to perform a redundant launch of the same record while ensuring
                // configurations and trying to resume top activity of focused stack.
                mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */,
                        displayId);
                ensureVisibilityAndConfig(r, r.getDisplayId(),
                        false /* markFrozenIfConfigChanged */, true /* deferResume */);
            }

            if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */,
@@ -1630,6 +1626,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        return true;
    }

    /**
     * Ensure all activities visibility, update orientation and configuration.
     */
    boolean ensureVisibilityAndConfig(ActivityRecord r, int displayId,
            boolean markFrozenIfConfigChanged, boolean deferResume) {
        // First ensure visibility without updating the config just yet. We need this to know what
        // activities are affecting configuration now.
        ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
                false /* preserveWindows */, false /* updateConfiguration */);

        // Force-update the orientation from the WindowManager, since we need the true configuration
        // to send to the client now.
        final Configuration config = mWindowManager.updateOrientationFromAppTokens(
                getDisplayOverrideConfiguration(displayId),
                r != null && r.mayFreezeScreenLocked(r.app) ? r.appToken : null,
                displayId, true /* forceUpdate */);
        if (r != null && markFrozenIfConfigChanged && config != null) {
            r.frozenBeforeDestroy = true;
        }

        // Update the configuration of the activities on the display.
        return mService.updateDisplayOverrideConfigurationLocked(config, r,
                deferResume, displayId);
    }

    private void logIfTransactionTooLarge(Intent intent, Bundle icicle) {
        int extrasSize = 0;
        if (intent != null) {
@@ -3647,8 +3668,21 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
        mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
    }

    /**
     * Make sure that all activities that need to be visible in the system actually are and update
     * their configuration.
     */
    void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows) {
        ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
                true /* updateConfiguration */);
    }

    /**
     * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean)
     */
    void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
            boolean preserveWindows, boolean updateConfiguration) {
        getKeyguardController().beginActivityVisibilityUpdate();
        try {
            // First the front stacks. In case any are not fullscreen and are in front of home.
@@ -3656,7 +3690,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
                final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
                for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                    final ActivityStack stack = display.getChildAt(stackNdx);
                    stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows);
                    stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
                            updateConfiguration);
                }
            }
        } finally {
+1 −1
Original line number Diff line number Diff line
@@ -1297,7 +1297,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
        // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
        // an Activity in another task being started in the wrong orientation during the transition.
        if (!(sendingToBottom || mService.mClosingApps.contains(this))
                && (isVisible() || mService.mOpeningApps.contains(this) || isOnTop())) {
                && (isVisible() || mService.mOpeningApps.contains(this))) {
            return mOrientation;
        }

+42 −25
Original line number Diff line number Diff line
@@ -944,10 +944,26 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
    /**
     * Update rotation of the display.
     *
     * Returns true if the rotation has been changed.  In this case YOU MUST CALL
     * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
     *         {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
     */
    boolean updateRotationUnchecked() {
        return updateRotationUnchecked(false /* forceUpdate */);
    }

    /**
     * Update rotation of the display with an option to force the update.
     * @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
     *                    orientation because we're waiting for some rotation to finish or display
     *                    to unfreeze, which results in configuration of the previously visible
     *                    activity being applied to a newly visible one. Forcing the rotation
     *                    update allows to workaround this issue.
     * @return {@code true} if the rotation has been changed.  In this case YOU MUST CALL
     *         {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
     */
    boolean updateRotationUnchecked(boolean forceUpdate) {
        ScreenRotationAnimation screenRotationAnimation;
        if (!forceUpdate) {
            if (mService.mDeferredRotationPauseCount > 0) {
                // Rotation updates have been paused temporarily.  Defer the update until
                // updates have been resumed.
@@ -955,7 +971,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                return false;
            }

        ScreenRotationAnimation screenRotationAnimation =
            screenRotationAnimation =
                    mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
                // Rotation updates cannot be performed while the previous rotation change
@@ -972,6 +988,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                        "Deferring rotation, still finishing previous rotation");
                return false;
            }
        }

        if (!mService.mDisplayEnabled) {
            // No point choosing a rotation if the display is not enabled.
@@ -992,7 +1009,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo

        if (mayRotateSeamlessly) {
            final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
            if (seamlessRotated != null) {
            if (seamlessRotated != null && !forceUpdate) {
                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
                // to complete (that is, waiting for windows to redraw). It's tempting to check
                // w.mSeamlessRotationCount but that could be incorrect in the case of
+15 −9
Original line number Diff line number Diff line
@@ -2372,6 +2372,12 @@ public class WindowManagerService extends IWindowManager.Stub
    @Override
    public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
            IBinder freezeThisOneIfNeeded, int displayId) {
        return updateOrientationFromAppTokens(currentConfig, freezeThisOneIfNeeded, displayId,
                false /* forceUpdate */);
    }

    public Configuration updateOrientationFromAppTokens(Configuration currentConfig,
            IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
        if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }
@@ -2381,7 +2387,7 @@ public class WindowManagerService extends IWindowManager.Stub
        try {
            synchronized(mWindowMap) {
                config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
                        displayId);
                        displayId, forceUpdate);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
@@ -2391,13 +2397,13 @@ public class WindowManagerService extends IWindowManager.Stub
    }

    private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
            IBinder freezeThisOneIfNeeded, int displayId) {
            IBinder freezeThisOneIfNeeded, int displayId, boolean forceUpdate) {
        if (!mDisplayReady) {
            return null;
        }
        Configuration config = null;

        if (updateOrientationFromAppTokensLocked(displayId)) {
        if (updateOrientationFromAppTokensLocked(displayId, 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 (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2445,11 +2451,15 @@ public class WindowManagerService extends IWindowManager.Stub
     * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
     */
    boolean updateOrientationFromAppTokensLocked(int displayId) {
        return updateOrientationFromAppTokensLocked(displayId, false /* forceUpdate */);
    }

    boolean updateOrientationFromAppTokensLocked(int displayId, boolean forceUpdate) {
        long ident = Binder.clearCallingIdentity();
        try {
            final DisplayContent dc = mRoot.getDisplayContent(displayId);
            final int req = dc.getOrientation();
            if (req != dc.getLastOrientation()) {
            if (req != dc.getLastOrientation() || forceUpdate) {
                dc.setLastOrientation(req);
                //send a message to Policy indicating orientation change to take
                //action like disabling/enabling sensors etc.,
@@ -2457,12 +2467,8 @@ public class WindowManagerService extends IWindowManager.Stub
                if (dc.isDefaultDisplay) {
                    mPolicy.setCurrentOrientationLw(req);
                }
                if (dc.updateRotationUnchecked()) {
                    // changed
                    return true;
                }
                return dc.updateRotationUnchecked(forceUpdate);
            }

            return false;
        } finally {
            Binder.restoreCallingIdentity(ident);
Loading