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
This commit is contained in:
Tracy Zhou
2019-06-18 10:59:11 -07:00
parent b8886dd613
commit cb0362a7e8
5 changed files with 43 additions and 56 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,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() {

View File

@@ -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;