From cb0362a7e8b60b551aff191e225d3b072d96bf62 Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Tue, 18 Jun 2019 10:59:11 -0700 Subject: [PATCH] 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 --- .../phone/FloatingRotationButton.java | 6 +- .../phone/NavigationBarFragment.java | 3 - .../statusbar/phone/NavigationBarView.java | 7 ++ .../phone/RotationButtonController.java | 76 +++++++++---------- .../phone/RotationContextButton.java | 7 -- 5 files changed, 43 insertions(+), 56 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java index 6bbeffaa9bfee..deb314bae5c97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FloatingRotationButton.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 79976d0e104de..9cf66df267377 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index ed486cdce6657..9919abd018dfc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java index 1e5406f3a5370..0147e7ff7cb21 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationButtonController.java @@ -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 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 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,11 +287,9 @@ 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, - NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS); - } + mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal); + mMainThreadHandler.postDelayed(mCancelPendingRotationProposal, + NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS); } } @@ -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() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java index 24e73362defee..bd9675280b0b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/RotationContextButton.java @@ -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;