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

Commit cb0362a7 authored by Tracy Zhou's avatar Tracy Zhou
Browse files

Fix a couple of rotation bugs

- device stuck in landscape mode: rotation watcher should not be
unregistered when rotation button is hidden. In the case of launcher
forcing portrait mode, rotation watcher listens to the rotation change
and update the current rotation on the System UI side
- floating rotation button animation timeout: because we attach and
detach the view upon rotation visibility change, posting the callback on
the view is not a good idea. We change it to post on the main thread
instead.

Fixes: 134643704
Test: Open any app in the fully gestural mode, rotate to landscape mode
using the rotation button, and swipe up. Go back to the app and observe
it's opened in the portrait mode.
Test: Previously if user changes the device orientation and presses on
the rotation button in the middle of the animation, and quickly changes
the orientation back, the second rotation button animation duration is
cut short. Now the duration of both animations are the full 5 seconds.

Change-Id: I9b58ef3d284e7366e83ffaa777fd822ed1e0bc23
parent b8886dd6
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -115,7 +115,6 @@ public class FloatingRotationButton implements RotationButton {
            return false;
        }
        mWindowManager.removeViewImmediate(mKeyButtonView);
        mRotationButtonController.cleanUp();
        mIsShowing = false;
        return true;
    }
@@ -141,10 +140,7 @@ public class FloatingRotationButton implements RotationButton {

    @Override
    public void setOnClickListener(View.OnClickListener onClickListener) {
        mKeyButtonView.setOnClickListener(view -> {
            hide();
            onClickListener.onClick(view);
        });
        mKeyButtonView.setOnClickListener(onClickListener);
    }

    @Override
+0 −3
Original line number Diff line number Diff line
@@ -872,9 +872,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        boolean[] feedbackEnabled = new boolean[1];
        int a11yFlags = getA11yButtonState(feedbackEnabled);

        mNavigationBarView.getRotationButtonController().setAccessibilityFeedbackEnabled(
                feedbackEnabled[0]);

        boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
        boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
        mNavigationBarView.setAccessibilityButtonState(clickable, longClickable);
+7 −0
Original line number Diff line number Diff line
@@ -1040,6 +1040,9 @@ public class NavigationBarView extends FrameLayout implements
        reorient();
        onNavigationModeChanged(mNavBarMode);
        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
        if (mRotationButtonController != null) {
            mRotationButtonController.registerListeners();
        }

        mEdgeBackGestureHandler.onNavBarAttached();
        getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
@@ -1053,6 +1056,10 @@ public class NavigationBarView extends FrameLayout implements
        for (int i = 0; i < mButtonDispatchers.size(); ++i) {
            mButtonDispatchers.valueAt(i).onDestroy();
        }
        if (mRotationButtonController != null) {
            mRotationButtonController.unregisterListeners();
        }

        mEdgeBackGestureHandler.onNavBarDetached();
        getViewTreeObserver().removeOnComputeInternalInsetsListener(
                mOnComputeInternalInsetsListener);
+35 −41
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import android.app.StatusBarManager;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.Looper;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.IRotationWatcher.Stub;
@@ -34,6 +34,7 @@ import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -42,6 +43,7 @@ import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.KeyButtonDrawable;
import com.android.systemui.statusbar.policy.RotationLockController;

@@ -64,8 +66,10 @@ public class RotationButtonController {
    private boolean mPendingRotationSuggestion;
    private boolean mHoveringRotationSuggestion;
    private RotationLockController mRotationLockController;
    private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
    private TaskStackListenerImpl mTaskStackListener;
    private Consumer<Integer> mRotWatcherListener;
    private boolean mListenersRegistered = false;
    private boolean mIsNavigationBarShowing;

    private final Runnable mRemoveRotationProposal =
@@ -73,22 +77,17 @@ public class RotationButtonController {
    private final Runnable mCancelPendingRotationProposal =
            () -> mPendingRotationSuggestion = false;
    private Animator mRotateHideAnimator;
    private boolean mAccessibilityFeedbackEnabled;

    private final Context mContext;
    private final RotationButton mRotationButton;
    private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());

    private final Stub mRotationWatcher = new Stub() {
        @Override
        public void onRotationChanged(final int rotation) throws RemoteException {
            if (mRotationButton.getCurrentView() == null) {
                return;
            }

            // We need this to be scheduled as early as possible to beat the redrawing of
            // window in response to the orientation change.
            Handler h = mRotationButton.getCurrentView().getHandler();
            Message msg = Message.obtain(h, () -> {
            mMainThreadHandler.postAtFrontOfQueue(() -> {
                // If the screen rotation changes while locked, potentially update lock to flow with
                // new screen rotation and hide any showing suggestions.
                if (mRotationLockController.isRotationLocked()) {
@@ -102,8 +101,6 @@ public class RotationButtonController {
                    mRotWatcherListener.accept(rotation);
                }
            });
            msg.setAsynchronous(true);
            h.sendMessageAtFrontOfQueue(msg);
        }
    };

@@ -124,40 +121,49 @@ public class RotationButtonController {
        mStyleRes = style;
        mIsNavigationBarShowing = true;
        mRotationLockController = Dependency.get(RotationLockController.class);
        mAccessibilityManagerWrapper = Dependency.get(AccessibilityManagerWrapper.class);

        // Register the task stack listener
        mTaskStackListener = new TaskStackListenerImpl();
        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
        mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
        mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
    }

    void registerListeners() {
        if (mListenersRegistered) {
            return;
        }

        mListenersRegistered = true;
        try {
            WindowManagerGlobal.getWindowManagerService()
                    .watchRotation(mRotationWatcher, mContext.getDisplay().getDisplayId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
    }

    void cleanUp() {
        // Unregister the task stack listener
        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
    void unregisterListeners() {
        if (!mListenersRegistered) {
            return;
        }

        mListenersRegistered = false;
        try {
            WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
    }

    void addRotationCallback(Consumer<Integer> watcher) {
        mRotWatcherListener = watcher;
    }

    void setAccessibilityFeedbackEnabled(boolean flag) {
        mAccessibilityFeedbackEnabled = flag;
    }

    void setRotationLockedAtAngle(int rotationSuggestion) {
        mRotationLockController.setRotationLockedAtAngle(true /* locked */, rotationSuggestion);
    }
@@ -185,7 +191,7 @@ public class RotationButtonController {

        // Clear any pending suggestion flag as it has either been nullified or is being shown
        mPendingRotationSuggestion = false;
        view.removeCallbacks(mCancelPendingRotationProposal);
        mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);

        // Handle the visibility change and animation
        if (visible) { // Appear and change (cannot force)
@@ -255,13 +261,9 @@ public class RotationButtonController {
            return;
        }

        final View currentView = mRotationButton.getCurrentView();

        // If window rotation matches suggested rotation, remove any current suggestions
        if (rotation == windowRotation) {
            if (currentView != null) {
                currentView.removeCallbacks(mRemoveRotationProposal);
            }
            mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
            setRotateSuggestionButtonState(false /* visible */);
            return;
        }
@@ -285,13 +287,11 @@ public class RotationButtonController {
            // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
            // visible given some time limit.
            mPendingRotationSuggestion = true;
            if (currentView != null) {
                currentView.removeCallbacks(mCancelPendingRotationProposal);
                currentView.postDelayed(mCancelPendingRotationProposal,
            mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
            mMainThreadHandler.postDelayed(mCancelPendingRotationProposal,
                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
        }
    }
    }

    void onDisable2FlagChanged(int state2) {
        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
@@ -334,9 +334,7 @@ public class RotationButtonController {
    private void onRotationSuggestionsDisabled() {
        // Immediately hide the rotate button and clear any planned removal
        setRotateSuggestionButtonState(false /* visible */, true /* force */);
        if (mRotationButton.getCurrentView() != null) {
            mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
        }
        mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
    }

    private void showAndLogRotationSuggestion() {
@@ -369,10 +367,6 @@ public class RotationButtonController {
    }

    private void rescheduleRotationTimeout(final boolean reasonHover) {
        if (mRotationButton.getCurrentView() == null) {
            return;
        }

        // May be called due to a new rotation proposal or a change in hover state
        if (reasonHover) {
            // Don't reschedule if a hide animator is running
@@ -382,16 +376,16 @@ public class RotationButtonController {
        }

        // Stop any pending removal
        mRotationButton.getCurrentView().removeCallbacks(mRemoveRotationProposal);
        mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
        // Schedule timeout
        mRotationButton.getCurrentView().postDelayed(mRemoveRotationProposal,
        mMainThreadHandler.postDelayed(mRemoveRotationProposal,
                computeRotationProposalTimeout());
    }

    private int computeRotationProposalTimeout() {
        if (mAccessibilityFeedbackEnabled) return 10000;
        if (mHoveringRotationSuggestion) return 8000;
        return 5000;
        return mAccessibilityManagerWrapper.getRecommendedTimeoutMillis(
                mHoveringRotationSuggestion ? 16000 : 5000,
                AccessibilityManager.FLAG_CONTENT_CONTROLS);
    }

    private boolean isRotateSuggestionIntroduced() {
+0 −7
Original line number Diff line number Diff line
@@ -63,13 +63,6 @@ public class RotationContextButton extends ContextualButton implements
                null /* ovalBackgroundColor */);
    }

    @Override
    public void onDestroy() {
        if (mRotationButtonController != null) {
            mRotationButtonController.cleanUp();
        }
    }

    @Override
    public void onNavigationModeChanged(int mode) {
        mNavBarMode = mode;