149fa016a98cef9940c883b3f620a0e90537a204eJason Monk/*
249fa016a98cef9940c883b3f620a0e90537a204eJason Monk * Copyright (C) 2017 The Android Open Source Project
349fa016a98cef9940c883b3f620a0e90537a204eJason Monk *
449fa016a98cef9940c883b3f620a0e90537a204eJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
549fa016a98cef9940c883b3f620a0e90537a204eJason Monk * except in compliance with the License. You may obtain a copy of the License at
649fa016a98cef9940c883b3f620a0e90537a204eJason Monk *
749fa016a98cef9940c883b3f620a0e90537a204eJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
849fa016a98cef9940c883b3f620a0e90537a204eJason Monk *
949fa016a98cef9940c883b3f620a0e90537a204eJason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
1049fa016a98cef9940c883b3f620a0e90537a204eJason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
1149fa016a98cef9940c883b3f620a0e90537a204eJason Monk * KIND, either express or implied. See the License for the specific language governing
1249fa016a98cef9940c883b3f620a0e90537a204eJason Monk * permissions and limitations under the License.
1349fa016a98cef9940c883b3f620a0e90537a204eJason Monk */
1449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
1549fa016a98cef9940c883b3f620a0e90537a204eJason Monkpackage com.android.systemui.statusbar.phone;
1649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
1749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
1849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
1949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
2049fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport static android.app.StatusBarManager.windowStateToString;
2149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
22ab65025833344b3b55bd146a86d48cabe254a89dMike Digmanimport static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
23ab65025833344b3b55bd146a86d48cabe254a89dMike Digman
248f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ngimport static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
2549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
262a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monkimport static com.android.systemui.statusbar.phone.StatusBar.DEBUG_WINDOW_STATE;
272a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monkimport static com.android.systemui.statusbar.phone.StatusBar.dumpBarTransitions;
289c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ngimport static com.android.systemui.OverviewProxyService.OverviewProxyListener;
2949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
30048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardtimport android.accessibilityservice.AccessibilityServiceInfo;
317d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport android.animation.Animator;
327d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport android.animation.AnimatorListenerAdapter;
337d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport android.animation.ObjectAnimator;
349c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ngimport android.annotation.IdRes;
3549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.annotation.Nullable;
3649fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.app.ActivityManager;
3749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.app.ActivityManagerNative;
3849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.app.Fragment;
3949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.app.IActivityManager;
4049fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.app.StatusBarManager;
4149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.content.BroadcastReceiver;
42b9dcd66aaeb57e8427eedb52a3d9149f395bb228Casey Burkhardtimport android.content.ContentResolver;
4349fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.content.Context;
4449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.content.Intent;
4549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.content.IntentFilter;
4649fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.content.res.Configuration;
4774922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardtimport android.database.ContentObserver;
4849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.graphics.PixelFormat;
4949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.graphics.Rect;
507d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport android.graphics.drawable.AnimatedVectorDrawable;
5149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.inputmethodservice.InputMethodService;
5249fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.Binder;
5349fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.Bundle;
5449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.Handler;
5549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.IBinder;
5649fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.Message;
5749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.RemoteException;
5849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.os.UserHandle;
5974922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardtimport android.provider.Settings;
60865246dc9ac488a440f8ca13973dbd8c60fede1eJason Monkimport android.support.annotation.VisibleForTesting;
6149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.telecom.TelecomManager;
6249fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.text.TextUtils;
6349fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.util.Log;
6449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.IRotationWatcher.Stub;
6549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.KeyEvent;
6649fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.LayoutInflater;
6749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.MotionEvent;
6885ff7fa1687658d37c8701f45a534cb5866df077Mike Digmanimport android.view.Surface;
6949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.View;
7049fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.ViewGroup;
7149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.WindowManager;
7249fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.WindowManager.LayoutParams;
7349fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.WindowManagerGlobal;
7449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.accessibility.AccessibilityEvent;
7549fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport android.view.accessibility.AccessibilityManager;
7691e587ebbc5b208f152c8a882f9e137f2525410eJason Monkimport android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
7749fa016a98cef9940c883b3f620a0e90537a204eJason Monk
7849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.internal.logging.MetricsLogger;
7949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
80ea03be1056d44328b96559702791bdac2a466002Jason Monkimport com.android.internal.util.LatencyTracker;
819c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monkimport com.android.systemui.Dependency;
827d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport com.android.systemui.Interpolators;
831e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digmanimport com.android.systemui.OverviewProxyService;
8449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.R;
859c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monkimport com.android.systemui.SysUiServiceProvider;
8649fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.assist.AssistManager;
8749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.fragments.FragmentHostManager;
8849fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.fragments.FragmentHostManager.FragmentListener;
8949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.recents.Recents;
907d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
917d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport com.android.systemui.shared.system.ActivityManagerWrapper;
9249fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.stackdivider.Divider;
9349fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.statusbar.CommandQueue;
9449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.statusbar.CommandQueue.Callbacks;
9591e587ebbc5b208f152c8a882f9e137f2525410eJason Monkimport com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
967d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport com.android.systemui.statusbar.policy.KeyButtonDrawable;
9749fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.statusbar.policy.KeyButtonView;
987d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digmanimport com.android.systemui.statusbar.policy.RotationLockController;
9949fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport com.android.systemui.statusbar.stack.StackStateAnimator;
10049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
10149fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport java.io.FileDescriptor;
10249fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport java.io.PrintWriter;
103048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardtimport java.util.List;
10449fa016a98cef9940c883b3f620a0e90537a204eJason Monkimport java.util.Locale;
105121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digmanimport java.util.Optional;
10649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
10749fa016a98cef9940c883b3f620a0e90537a204eJason Monk/**
10849fa016a98cef9940c883b3f620a0e90537a204eJason Monk * Fragment containing the NavigationBarFragment. Contains logic for what happens
10949fa016a98cef9940c883b3f620a0e90537a204eJason Monk * on clicks and view states of the nav bar.
11049fa016a98cef9940c883b3f620a0e90537a204eJason Monk */
11149fa016a98cef9940c883b3f620a0e90537a204eJason Monkpublic class NavigationBarFragment extends Fragment implements Callbacks {
11249fa016a98cef9940c883b3f620a0e90537a204eJason Monk
113d4afe152bf5cd93e5034f5b8b43b2f0fe0269a7fJason Monk    public static final String TAG = "NavigationBar";
11449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private static final boolean DEBUG = false;
1153e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman    private static final boolean DEBUG_ROTATION = true;
11649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private static final String EXTRA_DISABLE_STATE = "disabled_state";
117dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    private static final String EXTRA_DISABLE2_STATE = "disabled2_state";
11849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
1191e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    private final static int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
1205aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman    private final static int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
1211e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
1225075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
1235075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
12449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    /** Allow some time inbetween the long press for back and recents. */
12549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
12649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
12749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    protected NavigationBarView mNavigationBarView = null;
12849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    protected AssistManager mAssistManager;
12949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
13049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
13149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
13249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mNavigationIconHints = 0;
13349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mNavigationBarMode;
13490402957beb698799f65aa6756633554d121bc11Mike Digman    private boolean mAccessibilityFeedbackEnabled;
135048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    private AccessibilityManager mAccessibilityManager;
13674922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt    private MagnificationContentObserver mMagnificationObserver;
137b9dcd66aaeb57e8427eedb52a3d9149f395bb228Casey Burkhardt    private ContentResolver mContentResolver;
138c94759d89804d1e8cca8c64343b19d1ebac53b32Mike Digman    private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
13949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
14049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mDisabledFlags1;
141dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    private int mDisabledFlags2;
1422a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    private StatusBar mStatusBar;
14349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private Recents mRecents;
14449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private Divider mDivider;
14549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private WindowManager mWindowManager;
14649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private CommandQueue mCommandQueue;
14749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private long mLastLockToAppLongPress;
14849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
14949fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private Locale mLocale;
15049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mLayoutDirection;
15149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
15249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private int mSystemUiVisibility;
15349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private LightBarController mLightBarController;
15449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
155dc79e5c5801b2b6ed6b0a41d8b02832bae33a848Matthew Ng    private OverviewProxyService mOverviewProxyService;
156dc79e5c5801b2b6ed6b0a41d8b02832bae33a848Matthew Ng
15749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public boolean mHomeBlockedThisTouch;
15849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
1597d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    private int mLastRotationSuggestion;
1605aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman    private boolean mPendingRotationSuggestion;
16190402957beb698799f65aa6756633554d121bc11Mike Digman    private boolean mHoveringRotationSuggestion;
1627d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    private RotationLockController mRotationLockController;
1637d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    private TaskStackListenerImpl mTaskStackListener;
1647d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
1651e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    private final Runnable mRemoveRotationProposal = () -> setRotateSuggestionButtonState(false);
1665aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman    private final Runnable mCancelPendingRotationProposal =
1675aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            () -> mPendingRotationSuggestion = false;
1687d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    private Animator mRotateHideAnimator;
1695075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    private ViewRippler mViewRippler = new ViewRippler();
1707d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
1719c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
1729c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        @Override
1739c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        public void onConnectionChanged(boolean isConnected) {
174f9e302704a3042a4a09cab5ca9dbcb9f34c4ecaaWinson Chung            mNavigationBarView.updateStates();
1759c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng            updateScreenPinningGestures();
1769c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        }
1779c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
1789c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        @Override
1792ea93b708dbc49235b42e76a587d5f353638040fMatthew Ng        public void onQuickStepStarted() {
18085a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            // Use navbar dragging as a signal to hide the rotate button
18185a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            setRotateSuggestionButtonState(false);
1829c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        }
1838f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ng
1848f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ng        @Override
1858f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ng        public void onInteractionFlagsChanged(@InteractionType int flags) {
1868f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ng            mNavigationBarView.updateStates();
187f9e302704a3042a4a09cab5ca9dbcb9f34c4ecaaWinson Chung            updateScreenPinningGestures();
1888f25fb96e2e3c064869dad00e7234013ac22c5d7Matthew Ng        }
18996985e74261a0dacec66cb127821d7f2248f8438Matthew Ng
19096985e74261a0dacec66cb127821d7f2248f8438Matthew Ng        @Override
19196985e74261a0dacec66cb127821d7f2248f8438Matthew Ng        public void onBackButtonAlphaChanged(float alpha, boolean animate) {
19296985e74261a0dacec66cb127821d7f2248f8438Matthew Ng            final ButtonDispatcher backButton = mNavigationBarView.getBackButton();
19396985e74261a0dacec66cb127821d7f2248f8438Matthew Ng            backButton.setVisibility(alpha > 0 ? View.VISIBLE : View.INVISIBLE);
19496985e74261a0dacec66cb127821d7f2248f8438Matthew Ng            backButton.setAlpha(alpha, animate);
19596985e74261a0dacec66cb127821d7f2248f8438Matthew Ng        }
1969c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    };
1977d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
19849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    // ----- Fragment Lifecycle Callbacks -----
19949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
20049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
20149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onCreate(@Nullable Bundle savedInstanceState) {
20249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onCreate(savedInstanceState);
2039c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk        mCommandQueue = SysUiServiceProvider.getComponent(getContext(), CommandQueue.class);
20449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mCommandQueue.addCallbacks(this);
2052a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
2069c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk        mRecents = SysUiServiceProvider.getComponent(getContext(), Recents.class);
2079c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk        mDivider = SysUiServiceProvider.getComponent(getContext(), Divider.class);
20849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mWindowManager = getContext().getSystemService(WindowManager.class);
20949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
21091e587ebbc5b208f152c8a882f9e137f2525410eJason Monk        Dependency.get(AccessibilityManagerWrapper.class).addCallback(
21191e587ebbc5b208f152c8a882f9e137f2525410eJason Monk                mAccessibilityListener);
212b9dcd66aaeb57e8427eedb52a3d9149f395bb228Casey Burkhardt        mContentResolver = getContext().getContentResolver();
21374922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        mMagnificationObserver = new MagnificationContentObserver(
21474922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt                getContext().getMainThreadHandler());
215b9dcd66aaeb57e8427eedb52a3d9149f395bb228Casey Burkhardt        mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
21674922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt                Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED), false,
2175d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt                mMagnificationObserver, UserHandle.USER_ALL);
21874922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt
21949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (savedInstanceState != null) {
22049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
221dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman            mDisabledFlags2 = savedInstanceState.getInt(EXTRA_DISABLE2_STATE, 0);
22249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
2239c7844cb91b43929d0a86b1c90aa1efb37f5463aJason Monk        mAssistManager = Dependency.get(AssistManager.class);
224dc79e5c5801b2b6ed6b0a41d8b02832bae33a848Matthew Ng        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
22549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
22649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        try {
22749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            WindowManagerGlobal.getWindowManagerService()
22835fa3c26adcb5f6577849fd0df5228b1f67cf2c6Andrii Kulian                    .watchRotation(mRotationWatcher, getContext().getDisplay().getDisplayId());
22949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } catch (RemoteException e) {
23049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            throw e.rethrowFromSystemServer();
23149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
2327d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
2337d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        mRotationLockController = Dependency.get(RotationLockController.class);
2347d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
235ab65025833344b3b55bd146a86d48cabe254a89dMike Digman        // Reset user rotation pref to match that of the WindowManager if starting in locked mode
236ab65025833344b3b55bd146a86d48cabe254a89dMike Digman        // This will automatically happen when switching from auto-rotate to locked mode
237ab65025833344b3b55bd146a86d48cabe254a89dMike Digman        if (mRotationLockController.isRotationLocked()) {
238ab65025833344b3b55bd146a86d48cabe254a89dMike Digman            final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
239ab65025833344b3b55bd146a86d48cabe254a89dMike Digman            mRotationLockController.setRotationLockedAtAngle(true, winRotation);
240ab65025833344b3b55bd146a86d48cabe254a89dMike Digman        }
241ab65025833344b3b55bd146a86d48cabe254a89dMike Digman
2427d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        // Register the task stack listener
2437d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        mTaskStackListener = new TaskStackListenerImpl();
2447d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
24549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
24649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
24749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
24849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onDestroy() {
24949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onDestroy();
25049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mCommandQueue.removeCallbacks(this);
25191e587ebbc5b208f152c8a882f9e137f2525410eJason Monk        Dependency.get(AccessibilityManagerWrapper.class).removeCallback(
25291e587ebbc5b208f152c8a882f9e137f2525410eJason Monk                mAccessibilityListener);
253b9dcd66aaeb57e8427eedb52a3d9149f395bb228Casey Burkhardt        mContentResolver.unregisterContentObserver(mMagnificationObserver);
25449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        try {
25549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            WindowManagerGlobal.getWindowManagerService()
25649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    .removeRotationWatcher(mRotationWatcher);
25749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } catch (RemoteException e) {
25849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            throw e.rethrowFromSystemServer();
25949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
2607d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
2617d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        // Unregister the task stack listener
2627d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskStackListener);
26349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
26449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
26549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
26649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
26749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            Bundle savedInstanceState) {
26849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return inflater.inflate(R.layout.navigation_bar, container, false);
26949fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
27049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
27149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
27249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
27349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onViewCreated(view, savedInstanceState);
27449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView = (NavigationBarView) view;
27549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
27649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.setDisabledFlags(mDisabledFlags1);
27778f88d10ba61ebe25457aaeefc88b8a2460998e4Matthew Ng        mNavigationBarView.setComponents(mRecents, mDivider, mStatusBar.getPanel());
27849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
27949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
28049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (savedInstanceState != null) {
28149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
28249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
28349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
28449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        prepareNavigationBarView();
28549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        checkNavBarModes();
28649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
287dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        setDisabled2Flags(mDisabledFlags2);
288dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
28949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
29049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        filter.addAction(Intent.ACTION_SCREEN_ON);
291a858c5f60f405621ee9b333c910084ec35150ceaPhil Weaver        filter.addAction(Intent.ACTION_USER_SWITCHED);
29249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
293d002a0a96eb857804b3aafbcd32cf66a378c5b6cSiarhei Vishniakou        notifyNavigationBarScreenOn();
2949c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        mOverviewProxyService.addCallback(mOverviewProxyListener);
29549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
29649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
29749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
29849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onDestroyView() {
29949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onDestroyView();
300aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6bJason Monk        mNavigationBarView.getLightTransitionsController().destroy(getContext());
3019c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        mOverviewProxyService.removeCallback(mOverviewProxyListener);
30249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        getContext().unregisterReceiver(mBroadcastReceiver);
30349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
30449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
30549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
30649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onSaveInstanceState(Bundle outState) {
30749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onSaveInstanceState(outState);
30849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
309dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        outState.putInt(EXTRA_DISABLE2_STATE, mDisabledFlags2);
31049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
31149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.getLightTransitionsController().saveState(outState);
31249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
31349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
31449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
31549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
31649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void onConfigurationChanged(Configuration newConfig) {
31749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        super.onConfigurationChanged(newConfig);
31849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        final Locale locale = getContext().getResources().getConfiguration().locale;
31949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
32049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (!locale.equals(mLocale) || ld != mLayoutDirection) {
32149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (DEBUG) {
32249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                Log.v(TAG, String.format(
32349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
32449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        locale, ld));
32549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
32649fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mLocale = locale;
32749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mLayoutDirection = ld;
32849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            refreshLayout(ld);
32949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
33049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        repositionNavigationBar();
33149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
33249fa016a98cef9940c883b3f620a0e90537a204eJason Monk
33349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
33449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
33549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
33649fa016a98cef9940c883b3f620a0e90537a204eJason Monk            pw.print("  mNavigationBarWindowState=");
33749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            pw.println(windowStateToString(mNavigationBarWindowState));
33849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            pw.print("  mNavigationBarMode=");
33949fa016a98cef9940c883b3f620a0e90537a204eJason Monk            pw.println(BarTransitions.modeToString(mNavigationBarMode));
34049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
34149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
34249fa016a98cef9940c883b3f620a0e90537a204eJason Monk
34349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        pw.print("  mNavigationBarView=");
34449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView == null) {
34549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            pw.println("null");
34649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } else {
34749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.dump(fd, pw, args);
34849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
34949fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
35049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
35149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    // ----- CommandQueue Callbacks -----
35249fa016a98cef9940c883b3f620a0e90537a204eJason Monk
35349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
35449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
35549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            boolean showImeSwitcher) {
35649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
35749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        int hints = mNavigationIconHints;
358386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa        switch (backDisposition) {
359386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa            case InputMethodService.BACK_DISPOSITION_DEFAULT:
360386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa            case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
361386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa            case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
362386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                if (imeShown) {
363386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                    hints |= NAVIGATION_HINT_BACK_ALT;
364386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                } else {
365386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                    hints &= ~NAVIGATION_HINT_BACK_ALT;
366386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                }
367386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                break;
368386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa            case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
369386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                hints &= ~NAVIGATION_HINT_BACK_ALT;
370386f50e04f6e93894a38951cf9e946e9fa952af8Yohei Yukawa                break;
37149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
37249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (showImeSwitcher) {
37349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            hints |= NAVIGATION_HINT_IME_SHOWN;
37449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } else {
37549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            hints &= ~NAVIGATION_HINT_IME_SHOWN;
37649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
37749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (hints == mNavigationIconHints) return;
37849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
37949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationIconHints = hints;
38049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
38149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
38249fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.setNavigationIconHints(hints);
38349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
3842a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.checkBarModes();
38549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
38649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
38749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
38849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void topAppWindowChanged(boolean showMenu) {
38949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
39049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.setMenuVisibility(showMenu);
39149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
39249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
39349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
39449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
39549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void setWindowState(int window, int state) {
39649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null
39749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
39849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                && mNavigationBarWindowState != state) {
39949fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarWindowState = state;
40049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
4015aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman
4025aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            // If the navbar is visible, show the rotate button if there's a pending suggestion
4035aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            if (state == WINDOW_STATE_SHOWING && mPendingRotationSuggestion) {
4045aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                showAndLogRotationSuggestion();
4055aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            }
40649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
40749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
40849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
4097d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    @Override
410e07773175a55807e68aba6cd8a69b2401b748883Mike Digman    public void onRotationProposal(final int rotation, boolean isValid) {
4113e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman        final int winRotation = mWindowManager.getDefaultDisplay().getRotation();
412dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(mDisabledFlags2);
4133e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman        if (DEBUG_ROTATION) {
4143e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman            Log.v(TAG, "onRotationProposal proposedRotation=" + Surface.rotationToString(rotation)
4153e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman                    + ", winRotation=" + Surface.rotationToString(winRotation)
4163e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman                    + ", isValid=" + isValid + ", mNavBarWindowState="
4173e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman                    + StatusBarManager.windowStateToString(mNavigationBarWindowState)
418dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman                    + ", rotateSuggestionsDisabled=" + rotateSuggestionsDisabled
4193e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman                    + ", isRotateButtonVisible=" + (mNavigationBarView == null ? "null" :
4203e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman                        mNavigationBarView.isRotateButtonVisible()));
4213e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman        }
4223e33da67d47fb78356cc9d3eabaad3c1198acc1fMike Digman
423dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        // Respect the disabled flag, no need for action as flag change callback will handle hiding
424dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        if (rotateSuggestionsDisabled) return;
425dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
426e07773175a55807e68aba6cd8a69b2401b748883Mike Digman        // This method will be called on rotation suggestion changes even if the proposed rotation
427e07773175a55807e68aba6cd8a69b2401b748883Mike Digman        // is not valid for the top app. Use invalid rotation choices as a signal to remove the
428e07773175a55807e68aba6cd8a69b2401b748883Mike Digman        // rotate button if shown.
429e07773175a55807e68aba6cd8a69b2401b748883Mike Digman        if (!isValid) {
4301e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            setRotateSuggestionButtonState(false);
431e07773175a55807e68aba6cd8a69b2401b748883Mike Digman            return;
432e07773175a55807e68aba6cd8a69b2401b748883Mike Digman        }
433e07773175a55807e68aba6cd8a69b2401b748883Mike Digman
4345aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        // If window rotation matches suggested rotation, remove any current suggestions
4351e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (rotation == winRotation) {
4365aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            getView().removeCallbacks(mRemoveRotationProposal);
4371e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            setRotateSuggestionButtonState(false);
4385aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            return;
4395aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        }
4405aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman
4415aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        // Prepare to show the navbar icon by updating the icon style to change anim params
4425aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        mLastRotationSuggestion = rotation; // Remember rotation for click
4435aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        if (mNavigationBarView != null) {
4445aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            final boolean rotationCCW = isRotationAnimationCCW(winRotation, rotation);
4455aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            int style;
4465aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            if (winRotation == Surface.ROTATION_0 || winRotation == Surface.ROTATION_180) {
4475aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                style = rotationCCW ? R.style.RotateButtonCCWStart90 :
4485aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                        R.style.RotateButtonCWStart90;
4495aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            } else { // 90 or 270
4505aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                style = rotationCCW ? R.style.RotateButtonCCWStart0 :
4515aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                        R.style.RotateButtonCWStart0;
4521e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            }
4535aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            mNavigationBarView.updateRotateSuggestionButtonStyle(style, true);
4545aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        }
4555aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman
4565aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        if (mNavigationBarWindowState != WINDOW_STATE_SHOWING) {
4575aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
4585aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            // visible given some time limit.
4595aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            mPendingRotationSuggestion = true;
4605aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            getView().removeCallbacks(mCancelPendingRotationProposal);
4615aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            getView().postDelayed(mCancelPendingRotationProposal,
4625aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman                    NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
4631e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
4645aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        } else { // The navbar is visible so show the icon right away
4655aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman            showAndLogRotationSuggestion();
4667d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        }
4677d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    }
4687d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
469dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    private void onRotationSuggestionsDisabled() {
470dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        // Immediately hide the rotate button and clear any planned removal
471dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        setRotateSuggestionButtonState(false, true);
472e14c475043ee6932f3dc1eddf449ca1c83536418Mike Digman
473e14c475043ee6932f3dc1eddf449ca1c83536418Mike Digman        // This method can be called before view setup is done, ensure getView isn't null
474e14c475043ee6932f3dc1eddf449ca1c83536418Mike Digman        final View v = getView();
475e14c475043ee6932f3dc1eddf449ca1c83536418Mike Digman        if (v != null) v.removeCallbacks(mRemoveRotationProposal);
476dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    }
477dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
4785aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman    private void showAndLogRotationSuggestion() {
4795aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        setRotateSuggestionButtonState(true);
4805aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        rescheduleRotationTimeout(false);
4815aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        mMetricsLogger.visible(MetricsEvent.ROTATION_SUGGESTION_SHOWN);
4825aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman    }
4835aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman
4841e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    private boolean isRotationAnimationCCW(int from, int to) {
4851e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // All 180deg WM rotation animations are CCW, match that
4861e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
4871e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
4881e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
4891e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
4901e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
4911e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
4921e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
4931e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
4941e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
4951e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
4961e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
4971e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
4981e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        return false; // Default
499a48cf192f37bc94740594a1731716403bb03ec39Mike Digman    }
500a48cf192f37bc94740594a1731716403bb03ec39Mike Digman
5011e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    public void setRotateSuggestionButtonState(final boolean visible) {
5021e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        setRotateSuggestionButtonState(visible, false);
5031e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    }
5041e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5051e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman    public void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
5061e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (mNavigationBarView == null) return;
5071e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5081e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // At any point the the button can become invisible because an a11y service became active.
5091e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // Similarly, a call to make the button visible may be rejected because an a11y service is
5101e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // active. Must account for this.
5111e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5121e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        ButtonDispatcher rotBtn = mNavigationBarView.getRotateSuggestionButton();
5131e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        final boolean currentlyVisible = mNavigationBarView.isRotateButtonVisible();
5141e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5151e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // Rerun a show animation to indicate change but don't rerun a hide animation
5161e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (!visible && !currentlyVisible) return;
5171e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5181e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        View view = rotBtn.getCurrentView();
5191e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (view == null) return;
5201e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5211e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        KeyButtonDrawable kbd = rotBtn.getImageDrawable();
5221e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (kbd == null) return;
5231e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5241e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        // The KBD and AVD is recreated every new valid suggestion because of style changes.
5251e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        AnimatedVectorDrawable animIcon = null;
5261e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (kbd.getDrawable(0) instanceof AnimatedVectorDrawable) {
5271e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            animIcon = (AnimatedVectorDrawable) kbd.getDrawable(0);
5281e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        }
5291e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5305aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        // Clear any pending suggestion flag as it has either been nullified or is being shown
5315aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        mPendingRotationSuggestion = false;
532f4c989962cd8accf027b1f10d4cbd51249886b33Mike Digman        if (getView() != null) getView().removeCallbacks(mCancelPendingRotationProposal);
5335aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman
5345aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        // Handle the visibility change and animation
5351e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        if (visible) { // Appear and change (cannot force)
53685a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            // Stop and clear any currently running hide animations
5371e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
53885a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman                mRotateHideAnimator.cancel();
5391e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            }
54085a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            mRotateHideAnimator = null;
5411e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5421e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            // Reset the alpha if any has changed due to hide animation
5431e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            view.setAlpha(1f);
5441e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5451e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            // Run the rotate icon's animation if it has one
5461e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (animIcon != null) {
5471e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                animIcon.reset();
5481e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                animIcon.start();
5491e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            }
5501e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5515075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
5525075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
5531e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            // Set visibility, may fail if a11y service is active.
5541e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            // If invisible, call will stop animation.
5559b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman            int appliedVisibility = mNavigationBarView.setRotateButtonVisibility(true);
5569b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman            if (appliedVisibility == View.VISIBLE) {
5579b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman                // If the button will actually become visible and the navbar is about to hide,
5589b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman                // tell the statusbar to keep it around for longer
5599b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman                mStatusBar.touchAutoHide();
5609b50b76700b2b0b0271e99bf844aa005f9192568Mike Digman            }
5611e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5621e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman        } else { // Hide
5631e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5645075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            mViewRippler.stop(); // Prevent any pending ripples, force hide or not
5655075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
5661e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (force) {
5671e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                // If a hide animator is running stop it and make invisible
5681e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
5691e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                    mRotateHideAnimator.pause();
5701e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                }
5711e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                mNavigationBarView.setRotateButtonVisibility(false);
5721e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                return;
5731e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            }
5741e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5751e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            // Don't start any new hide animations if one is running
5761e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
5771e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5781e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha",
5791e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                    0f);
5801e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
5811e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            fadeOut.setInterpolator(Interpolators.LINEAR);
5821e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            fadeOut.addListener(new AnimatorListenerAdapter() {
5831e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                @Override
5841e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                public void onAnimationEnd(Animator animation) {
5851e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                    mNavigationBarView.setRotateButtonVisibility(false);
5861e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                }
5871e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            });
5881e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman
5891e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            mRotateHideAnimator = fadeOut;
5901e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            fadeOut.start();
591a48cf192f37bc94740594a1731716403bb03ec39Mike Digman        }
592a48cf192f37bc94740594a1731716403bb03ec39Mike Digman    }
593a48cf192f37bc94740594a1731716403bb03ec39Mike Digman
59490402957beb698799f65aa6756633554d121bc11Mike Digman    private void rescheduleRotationTimeout(final boolean reasonHover) {
59590402957beb698799f65aa6756633554d121bc11Mike Digman        // May be called due to a new rotation proposal or a change in hover state
59690402957beb698799f65aa6756633554d121bc11Mike Digman        if (reasonHover) {
59790402957beb698799f65aa6756633554d121bc11Mike Digman            // Don't reschedule if a hide animator is running
5981e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
59990402957beb698799f65aa6756633554d121bc11Mike Digman            // Don't reschedule if not visible
6001e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            if (!mNavigationBarView.isRotateButtonVisible()) return;
60190402957beb698799f65aa6756633554d121bc11Mike Digman        }
60290402957beb698799f65aa6756633554d121bc11Mike Digman
6035aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        getView().removeCallbacks(mRemoveRotationProposal); // Stop any pending removal
6045aeca79673d142f9924f71fc6055c46d837a95e7Mike Digman        getView().postDelayed(mRemoveRotationProposal,
60590402957beb698799f65aa6756633554d121bc11Mike Digman                computeRotationProposalTimeout()); // Schedule timeout
60690402957beb698799f65aa6756633554d121bc11Mike Digman    }
60790402957beb698799f65aa6756633554d121bc11Mike Digman
60890402957beb698799f65aa6756633554d121bc11Mike Digman    private int computeRotationProposalTimeout() {
60990402957beb698799f65aa6756633554d121bc11Mike Digman        if (mAccessibilityFeedbackEnabled) return 20000;
61090402957beb698799f65aa6756633554d121bc11Mike Digman        if (mHoveringRotationSuggestion) return 16000;
611d13e43b2bdd583215805433b1dceb7eeb6e317f9Mike Digman        return 10000;
61290402957beb698799f65aa6756633554d121bc11Mike Digman    }
61390402957beb698799f65aa6756633554d121bc11Mike Digman
6145075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    private boolean isRotateSuggestionIntroduced() {
6155075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        ContentResolver cr = getContext().getContentResolver();
6165075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
6175075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman                >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
6185075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    }
6195075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
6205075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
6215075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        // Get the number of accepted suggestions
6225075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        ContentResolver cr = getContext().getContentResolver();
6235075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        final int numSuggestions = Settings.Secure.getInt(cr,
6245075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman                Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
6255075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
6265075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        // Increment the number of accepted suggestions only if it would change intro mode
6275075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
6285075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
6295075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman                    numSuggestions + 1);
6305075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        }
6315075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    }
6325075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
6332a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    // Injected from StatusBar at creation.
63449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void setCurrentSysuiVisibility(int systemUiVisibility) {
63549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mSystemUiVisibility = systemUiVisibility;
6362a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mNavigationBarMode = mStatusBar.computeBarMode(0, mSystemUiVisibility,
63749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
63849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                View.NAVIGATION_BAR_TRANSPARENT);
63949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        checkNavBarModes();
6402a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.touchAutoHide();
64149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
64249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                true /* nbModeChanged */, mNavigationBarMode);
64349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
64449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
64549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
64649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
64749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
64849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        final int oldVal = mSystemUiVisibility;
64949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        final int newVal = (oldVal & ~mask) | (vis & mask);
65049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        final int diff = newVal ^ oldVal;
65149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        boolean nbModeChanged = false;
65249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (diff != 0) {
65349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mSystemUiVisibility = newVal;
65449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
65549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            // update navigation bar mode
65649fa016a98cef9940c883b3f620a0e90537a204eJason Monk            final int nbMode = getView() == null
6572a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk                    ? -1 : mStatusBar.computeBarMode(oldVal, newVal,
65849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
65949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    View.NAVIGATION_BAR_TRANSPARENT);
66049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            nbModeChanged = nbMode != -1;
66149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (nbModeChanged) {
66249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                if (mNavigationBarMode != nbMode) {
66349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    mNavigationBarMode = nbMode;
66449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    checkNavBarModes();
66549fa016a98cef9940c883b3f620a0e90537a204eJason Monk                }
6662a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk                mStatusBar.touchAutoHide();
66749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
66849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
66949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
67049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
67149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                mNavigationBarMode);
67249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
67349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
67449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    @Override
67549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void disable(int state1, int state2, boolean animate) {
676dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        // Navigation bar flags are in both state1 and state2.
677dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        final int masked = state1 & (StatusBarManager.DISABLE_HOME
67849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                | StatusBarManager.DISABLE_RECENT
67949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                | StatusBarManager.DISABLE_BACK
68049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                | StatusBarManager.DISABLE_SEARCH);
68149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (masked != mDisabledFlags1) {
68249fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mDisabledFlags1 = masked;
68349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
6849c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng            updateScreenPinningGestures();
68549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
686dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
687dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        final int masked2 = state2 & (StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
688dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        if (masked2 != mDisabledFlags2) {
689dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman            mDisabledFlags2 = masked2;
690dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman            setDisabled2Flags(masked2);
691dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        }
692dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    }
693dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
694dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    private void setDisabled2Flags(int state2) {
695dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        // Method only called on change of disable2 flags
696dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
697dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
698dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    }
699dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman
700dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman    private boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
701dd2f49edb68996ef8d1a62e68a0493d9f98d5feaMike Digman        return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
70249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
70349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
70449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    // ----- Internal stuffz -----
70549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
70649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private void refreshLayout(int layoutDirection) {
70749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
70849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.setLayoutDirection(layoutDirection);
70949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
71049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
71149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
71249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private boolean shouldDisableNavbarGestures() {
7132a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        return !mStatusBar.isDeviceProvisioned()
714fee0b5b26a4b2ccb8aa6396ce903d0a187b26851Matthew Ng                || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
71549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
71649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
71749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private void repositionNavigationBar() {
71849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
71949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
72049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        prepareNavigationBarView();
72149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
72249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
72349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                ((View) mNavigationBarView.getParent()).getLayoutParams());
72449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
72549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
7269c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    private void updateScreenPinningGestures() {
7279c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        if (mNavigationBarView == null) {
7289c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng            return;
7299c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        }
7309c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
7319c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        // Change the cancel pin gesture to home and back if recents button is invisible
7329c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
7339c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
7349c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        if (recentsVisible) {
7359c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng            backButton.setOnLongClickListener(this::onLongPressBackRecents);
7369c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        } else {
7379c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng            backButton.setOnLongClickListener(this::onLongPressBackHome);
7389c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        }
7399c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    }
7409c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
741d002a0a96eb857804b3aafbcd32cf66a378c5b6cSiarhei Vishniakou    private void notifyNavigationBarScreenOn() {
742d0a73e7aa4f40e8cdb2f25edd9c3946beaf5c957Matthew Ng        mNavigationBarView.updateNavButtonIcons();
74349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
74449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
74549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private void prepareNavigationBarView() {
74649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.reorient();
74749fa016a98cef9940c883b3f620a0e90537a204eJason Monk
74849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
74949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        recentsButton.setOnClickListener(this::onRecentsClick);
75049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        recentsButton.setOnTouchListener(this::onRecentsTouch);
75149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        recentsButton.setLongClickable(true);
75249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
75349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
75449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
75549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        backButton.setLongClickable(true);
75649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
75749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
75849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        homeButton.setOnTouchListener(this::onHomeTouch);
759fee0b5b26a4b2ccb8aa6396ce903d0a187b26851Matthew Ng        homeButton.setOnLongClickListener(this::onHomeLongClick);
760048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
761048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
762048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        accessibilityButton.setOnClickListener(this::onAccessibilityClick);
763048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
764db9a77401356fac8b77fbf9f8180863ea4eeb924Phil Weaver        updateAccessibilityServicesState(mAccessibilityManager);
7657d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
7667d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        ButtonDispatcher rotateSuggestionButton = mNavigationBarView.getRotateSuggestionButton();
7677d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        rotateSuggestionButton.setOnClickListener(this::onRotateSuggestionClick);
76890402957beb698799f65aa6756633554d121bc11Mike Digman        rotateSuggestionButton.setOnHoverListener(this::onRotateSuggestionHover);
7699c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        updateScreenPinningGestures();
77049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
77149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
77249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private boolean onHomeTouch(View v, MotionEvent event) {
77349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
77449fa016a98cef9940c883b3f620a0e90537a204eJason Monk            return true;
77549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
77649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        // If an incoming call is ringing, HOME is totally disabled.
77749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        // (The user is already on the InCallUI at this point,
77849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        // and his ONLY options are to answer or reject the call.)
77949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        switch (event.getAction()) {
78049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            case MotionEvent.ACTION_DOWN:
78149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                mHomeBlockedThisTouch = false;
78249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                TelecomManager telecomManager =
78349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        getContext().getSystemService(TelecomManager.class);
78449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                if (telecomManager != null && telecomManager.isRinging()) {
7852a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk                    if (mStatusBar.isKeyguardShowing()) {
78649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
78749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                                "No heads up");
78849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        mHomeBlockedThisTouch = true;
78949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        return true;
79049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    }
79149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                }
79249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                break;
79349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            case MotionEvent.ACTION_UP:
79449fa016a98cef9940c883b3f620a0e90537a204eJason Monk            case MotionEvent.ACTION_CANCEL:
7952a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk                mStatusBar.awakenDreams();
79649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                break;
79749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
79849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return false;
79949fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
80049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
80149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private void onVerticalChanged(boolean isVertical) {
8022a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.setQsScrimEnabled(!isVertical);
80349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
80449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
80549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private boolean onNavigationTouch(View v, MotionEvent event) {
806cb5d316646df62e9ca84cdf0b03ce7d53ae6396bEliot Courtney        mStatusBar.checkUserAutohide(event);
80749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return false;
80849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
80949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
810865246dc9ac488a440f8ca13973dbd8c60fede1eJason Monk    @VisibleForTesting
811865246dc9ac488a440f8ca13973dbd8c60fede1eJason Monk    boolean onHomeLongClick(View v) {
8126ff33b7f5364d83fc2034af03f53efdb28d36b6eMatthew Ng        if (!mNavigationBarView.isRecentsButtonVisible()
8136ff33b7f5364d83fc2034af03f53efdb28d36b6eMatthew Ng                && ActivityManagerWrapper.getInstance().isScreenPinningActive()) {
814fee0b5b26a4b2ccb8aa6396ce903d0a187b26851Matthew Ng            return onLongPressBackHome(v);
815fee0b5b26a4b2ccb8aa6396ce903d0a187b26851Matthew Ng        }
81649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (shouldDisableNavbarGestures()) {
81749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            return false;
81849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
8192ea93b708dbc49235b42e76a587d5f353638040fMatthew Ng        mNavigationBarView.onNavigationButtonLongPress(v);
820c94759d89804d1e8cca8c64343b19d1ebac53b32Mike Digman        mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
82149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mAssistManager.startAssist(new Bundle() /* args */);
8222a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.awakenDreams();
823dc79e5c5801b2b6ed6b0a41d8b02832bae33a848Matthew Ng
82449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (mNavigationBarView != null) {
82549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mNavigationBarView.abortCurrentGesture();
82649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
82749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return true;
82849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
82949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
83049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    // additional optimization when we have software system buttons - start loading the recent
83149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    // tasks on touch down
83249fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private boolean onRecentsTouch(View v, MotionEvent event) {
83349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        int action = event.getAction() & MotionEvent.ACTION_MASK;
83449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (action == MotionEvent.ACTION_DOWN) {
83549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mCommandQueue.preloadRecentApps();
83649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } else if (action == MotionEvent.ACTION_CANCEL) {
83749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            mCommandQueue.cancelPreloadRecentApps();
83849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } else if (action == MotionEvent.ACTION_UP) {
83949fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (!v.isPressed()) {
84049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                mCommandQueue.cancelPreloadRecentApps();
84149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
84249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
84349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return false;
84449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
84549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
84649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private void onRecentsClick(View v) {
84749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (LatencyTracker.isEnabled(getContext())) {
84849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            LatencyTracker.getInstance(getContext()).onActionStart(
84949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    LatencyTracker.ACTION_TOGGLE_RECENTS);
85049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
8512a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.awakenDreams();
85249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mCommandQueue.toggleRecentApps();
85349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
85449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
8559c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    private boolean onLongPressBackHome(View v) {
8562ea93b708dbc49235b42e76a587d5f353638040fMatthew Ng        mNavigationBarView.onNavigationButtonLongPress(v);
8579c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        return onLongPressNavigationButtons(v, R.id.back, R.id.home);
8589c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    }
8599c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
8609c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    private boolean onLongPressBackRecents(View v) {
8612ea93b708dbc49235b42e76a587d5f353638040fMatthew Ng        mNavigationBarView.onNavigationButtonLongPress(v);
8629c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng        return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
8639c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    }
8649c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
86549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    /**
8669c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng     * This handles long-press of both back and recents/home. Back is the common button with
8679c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng     * combination of recents if it is visible or home if recents is invisible.
8689c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng     * They are handled together to capture them both being long-pressed
86949fa016a98cef9940c883b3f620a0e90537a204eJason Monk     * at the same time to exit screen pinning (lock task).
87049fa016a98cef9940c883b3f620a0e90537a204eJason Monk     *
8719c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng     * When accessibility mode is on, only a long-press from recents/home
87249fa016a98cef9940c883b3f620a0e90537a204eJason Monk     * is required to exit.
87349fa016a98cef9940c883b3f620a0e90537a204eJason Monk     *
87449fa016a98cef9940c883b3f620a0e90537a204eJason Monk     * In all other circumstances we try to pass through long-press events
87549fa016a98cef9940c883b3f620a0e90537a204eJason Monk     * for Back, so that apps can still use it.  Which can be from two things.
87649fa016a98cef9940c883b3f620a0e90537a204eJason Monk     * 1) Not currently in screen pinning (lock task).
8779c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng     * 2) Back is long-pressed without recents/home.
87849fa016a98cef9940c883b3f620a0e90537a204eJason Monk     */
8799c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng    private boolean onLongPressNavigationButtons(View v, @IdRes int btnId1, @IdRes int btnId2) {
88049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        try {
88149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            boolean sendBackLongPress = false;
88249fa016a98cef9940c883b3f620a0e90537a204eJason Monk            IActivityManager activityManager = ActivityManagerNative.getDefault();
88349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
88449fa016a98cef9940c883b3f620a0e90537a204eJason Monk            boolean inLockTaskMode = activityManager.isInLockTaskMode();
88549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (inLockTaskMode && !touchExplorationEnabled) {
88649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                long time = System.currentTimeMillis();
8879c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng
88849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                // If we recently long-pressed the other button then they were
88949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                // long-pressed 'together'
89049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
891a83859ffaa4d339729cbc1a8c114b73c6afedb00Benjamin Franz                    activityManager.stopSystemLockTaskMode();
89249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    // When exiting refresh disabled flags.
893d0a73e7aa4f40e8cdb2f25edd9c3946beaf5c957Matthew Ng                    mNavigationBarView.updateNavButtonIcons();
89449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    return true;
8959c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                } else if (v.getId() == btnId1) {
8969c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                    ButtonDispatcher button = btnId2 == R.id.recent_apps
8979c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                            ? mNavigationBarView.getRecentsButton()
8989c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                            : mNavigationBarView.getHomeButton();
8999c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                    if (!button.getCurrentView().isPressed()) {
9009c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                        // If we aren't pressing recents/home right now then they presses
9019c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                        // won't be together, so send the standard long-press action.
9029c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                        sendBackLongPress = true;
9039c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                    }
90449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                }
90549fa016a98cef9940c883b3f620a0e90537a204eJason Monk                mLastLockToAppLongPress = time;
90649fa016a98cef9940c883b3f620a0e90537a204eJason Monk            } else {
90749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                // If this is back still need to handle sending the long-press event.
9089c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                if (v.getId() == btnId1) {
90949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    sendBackLongPress = true;
91049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                } else if (touchExplorationEnabled && inLockTaskMode) {
9119c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                    // When in accessibility mode a long press that is recents/home (not back)
91249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    // should stop lock task.
913a83859ffaa4d339729cbc1a8c114b73c6afedb00Benjamin Franz                    activityManager.stopSystemLockTaskMode();
91449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    // When exiting refresh disabled flags.
915d0a73e7aa4f40e8cdb2f25edd9c3946beaf5c957Matthew Ng                    mNavigationBarView.updateNavButtonIcons();
91649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    return true;
9179c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                } else if (v.getId() == btnId2) {
9189c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                    return btnId2 == R.id.recent_apps
9199c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                            ? onLongPressRecents()
9209c3bce5c4444bcf98bc6342fa5c448345bb67a6cMatthew Ng                            : onHomeLongClick(mNavigationBarView.getHomeButton().getCurrentView());
92149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                }
92249fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
92349fa016a98cef9940c883b3f620a0e90537a204eJason Monk            if (sendBackLongPress) {
92449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                KeyButtonView keyButtonView = (KeyButtonView) v;
92549fa016a98cef9940c883b3f620a0e90537a204eJason Monk                keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
92649fa016a98cef9940c883b3f620a0e90537a204eJason Monk                keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
92749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                return true;
92849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
92949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        } catch (RemoteException e) {
93049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            Log.d(TAG, "Unable to reach activity manager", e);
93149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
93249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return false;
93349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
93449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
93549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private boolean onLongPressRecents() {
9369be3a060827154617eed9132c64431af56d98eb4Erik Wolsheimer        if (mRecents == null || !ActivityManager.supportsMultiWindow(getContext())
93743db6d26d8cfc7004c0f71f7e8f8de59081f6ccdMatthew Ng                || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
938074c4344f5f32a6c92ec1736cf0132242da11a21Winson Chung                || Recents.getConfiguration().isLowRamDevice
939074c4344f5f32a6c92ec1736cf0132242da11a21Winson Chung                // If we are connected to the overview service, then disable the recents button
940074c4344f5f32a6c92ec1736cf0132242da11a21Winson Chung                || mOverviewProxyService.getProxy() != null) {
94149fa016a98cef9940c883b3f620a0e90537a204eJason Monk            return false;
94249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
94349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
9442a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        return mStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
94549fa016a98cef9940c883b3f620a0e90537a204eJason Monk                MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
94649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
94749fa016a98cef9940c883b3f620a0e90537a204eJason Monk
948048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    private void onAccessibilityClick(View v) {
949048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        mAccessibilityManager.notifyAccessibilityButtonClicked();
950048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    }
951048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
952048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    private boolean onAccessibilityLongClick(View v) {
9535e8b980c5d6bc282b51b3ddfc8722ff973c7e885Casey Burkhardt        Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
9545e8b980c5d6bc282b51b3ddfc8722ff973c7e885Casey Burkhardt        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
9555d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt        v.getContext().startActivityAsUser(intent, UserHandle.CURRENT);
956048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        return true;
957048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    }
958048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
959db9a77401356fac8b77fbf9f8180863ea4eeb924Phil Weaver    private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
96074922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        int requestingServices = 0;
96174922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        try {
9625d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt            if (Settings.Secure.getIntForUser(mContentResolver,
9635d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt                    Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
9645d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt                    UserHandle.USER_CURRENT) == 1) {
96574922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt                requestingServices++;
96674922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt            }
96774922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        } catch (Settings.SettingNotFoundException e) {
96874922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        }
96974922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt
97090402957beb698799f65aa6756633554d121bc11Mike Digman        boolean feedbackEnabled = false;
9715d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt        // AccessibilityManagerService resolves services for the current user since the local
9725d6144056493b0d657e74d13de8e751c06510357Casey Burkhardt        // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS permission
973048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        final List<AccessibilityServiceInfo> services =
974db9a77401356fac8b77fbf9f8180863ea4eeb924Phil Weaver                accessibilityManager.getEnabledAccessibilityServiceList(
975048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                        AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
976048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        for (int i = services.size() - 1; i >= 0; --i) {
977048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt            AccessibilityServiceInfo info = services.get(i);
978048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt            if ((info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0) {
979048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt                requestingServices++;
980048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt            }
98190402957beb698799f65aa6756633554d121bc11Mike Digman
98290402957beb698799f65aa6756633554d121bc11Mike Digman            if (info.feedbackType != 0 && info.feedbackType !=
98390402957beb698799f65aa6756633554d121bc11Mike Digman                    AccessibilityServiceInfo.FEEDBACK_GENERIC) {
98490402957beb698799f65aa6756633554d121bc11Mike Digman                feedbackEnabled = true;
98590402957beb698799f65aa6756633554d121bc11Mike Digman            }
986048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        }
987048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
98890402957beb698799f65aa6756633554d121bc11Mike Digman        mAccessibilityFeedbackEnabled = feedbackEnabled;
98990402957beb698799f65aa6756633554d121bc11Mike Digman
990048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        final boolean showAccessibilityButton = requestingServices >= 1;
991048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        final boolean targetSelection = requestingServices >= 2;
992048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt        mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
993048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt    }
994048c2bc19af4cfcb5e959f1bc07fbfa03a72e330Casey Burkhardt
9957d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    private void onRotateSuggestionClick(View v) {
996c94759d89804d1e8cca8c64343b19d1ebac53b32Mike Digman        mMetricsLogger.action(MetricsEvent.ACTION_ROTATION_SUGGESTION_ACCEPTED);
9975075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        incrementNumAcceptedRotationSuggestionsIfNeeded();
9987d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        mRotationLockController.setRotationLockedAtAngle(true, mLastRotationSuggestion);
9997d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    }
10007d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
100190402957beb698799f65aa6756633554d121bc11Mike Digman    private boolean onRotateSuggestionHover(View v, MotionEvent event) {
100290402957beb698799f65aa6756633554d121bc11Mike Digman        final int action = event.getActionMasked();
100390402957beb698799f65aa6756633554d121bc11Mike Digman        mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
100490402957beb698799f65aa6756633554d121bc11Mike Digman                || (action == MotionEvent.ACTION_HOVER_MOVE);
100590402957beb698799f65aa6756633554d121bc11Mike Digman        rescheduleRotationTimeout(true);
100690402957beb698799f65aa6756633554d121bc11Mike Digman        return false; // Must return false so a11y hover events are dispatched correctly.
100790402957beb698799f65aa6756633554d121bc11Mike Digman    }
100890402957beb698799f65aa6756633554d121bc11Mike Digman
10092a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    // ----- Methods that StatusBar talks to (should be minimized) -----
101049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
101149fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void setLightBarController(LightBarController lightBarController) {
101249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mLightBarController = lightBarController;
101349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
101449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
101549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
101649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public boolean isSemiTransparent() {
101749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
101849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
101949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
102049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void disableAnimationsDuringHide(long delay) {
102149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.setLayoutTransitionsEnabled(false);
102249fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
102349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
102449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
102549fa016a98cef9940c883b3f620a0e90537a204eJason Monk
102649fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public BarTransitions getBarTransitions() {
102749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return mNavigationBarView.getBarTransitions();
102849fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
102949fa016a98cef9940c883b3f620a0e90537a204eJason Monk
103049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void checkNavBarModes() {
10312a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk        mStatusBar.checkBarMode(mNavigationBarMode,
103249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
103349fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
103449fa016a98cef9940c883b3f620a0e90537a204eJason Monk
103549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public void finishBarAnimations() {
103649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        mNavigationBarView.getBarTransitions().finishAnimations();
103749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
103849fa016a98cef9940c883b3f620a0e90537a204eJason Monk
103991e587ebbc5b208f152c8a882f9e137f2525410eJason Monk    private final AccessibilityServicesStateChangeListener mAccessibilityListener =
104091e587ebbc5b208f152c8a882f9e137f2525410eJason Monk            this::updateAccessibilityServicesState;
104191e587ebbc5b208f152c8a882f9e137f2525410eJason Monk
104274922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt    private class MagnificationContentObserver extends ContentObserver {
104374922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt
104474922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        public MagnificationContentObserver(Handler handler) {
104574922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt            super(handler);
104674922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        }
104774922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt
104874922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        @Override
104974922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        public void onChange(boolean selfChange) {
1050db9a77401356fac8b77fbf9f8180863ea4eeb924Phil Weaver            NavigationBarFragment.this.updateAccessibilityServicesState(mAccessibilityManager);
105174922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt        }
105274922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt    }
105374922c63e1dfba074aa9219034e48a161bdfba5bCasey Burkhardt
105449fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private final Stub mRotationWatcher = new Stub() {
105549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        @Override
105690402957beb698799f65aa6756633554d121bc11Mike Digman        public void onRotationChanged(final int rotation) throws RemoteException {
105749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            // We need this to be scheduled as early as possible to beat the redrawing of
105849fa016a98cef9940c883b3f620a0e90537a204eJason Monk            // window in response to the orientation change.
105949fa016a98cef9940c883b3f620a0e90537a204eJason Monk            Handler h = getView().getHandler();
106049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            Message msg = Message.obtain(h, () -> {
106185ff7fa1687658d37c8701f45a534cb5866df077Mike Digman
106285ff7fa1687658d37c8701f45a534cb5866df077Mike Digman                // If the screen rotation changes while locked, potentially update lock to flow with
106390402957beb698799f65aa6756633554d121bc11Mike Digman                // new screen rotation and hide any showing suggestions.
106490402957beb698799f65aa6756633554d121bc11Mike Digman                if (mRotationLockController.isRotationLocked()) {
106585ff7fa1687658d37c8701f45a534cb5866df077Mike Digman                    if (shouldOverrideUserLockPrefs(rotation)) {
106685ff7fa1687658d37c8701f45a534cb5866df077Mike Digman                        mRotationLockController.setRotationLockedAtAngle(true, rotation);
106785ff7fa1687658d37c8701f45a534cb5866df077Mike Digman                    }
10681e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman                    setRotateSuggestionButtonState(false, true);
106990402957beb698799f65aa6756633554d121bc11Mike Digman                }
107090402957beb698799f65aa6756633554d121bc11Mike Digman
107149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                if (mNavigationBarView != null
107249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        && mNavigationBarView.needsReorient(rotation)) {
107349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                    repositionNavigationBar();
107449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                }
107549fa016a98cef9940c883b3f620a0e90537a204eJason Monk            });
107649fa016a98cef9940c883b3f620a0e90537a204eJason Monk            msg.setAsynchronous(true);
107749fa016a98cef9940c883b3f620a0e90537a204eJason Monk            h.sendMessageAtFrontOfQueue(msg);
107849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
107985ff7fa1687658d37c8701f45a534cb5866df077Mike Digman
108085ff7fa1687658d37c8701f45a534cb5866df077Mike Digman        private boolean shouldOverrideUserLockPrefs(final int rotation) {
1081ab65025833344b3b55bd146a86d48cabe254a89dMike Digman            // Only override user prefs when returning to the natural rotation (normally portrait).
108285ff7fa1687658d37c8701f45a534cb5866df077Mike Digman            // Don't let apps that force landscape or 180 alter user lock.
1083ab65025833344b3b55bd146a86d48cabe254a89dMike Digman            return rotation == NATURAL_ROTATION;
108485ff7fa1687658d37c8701f45a534cb5866df077Mike Digman        }
108549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    };
108649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
108749fa016a98cef9940c883b3f620a0e90537a204eJason Monk    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
108849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        @Override
108949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        public void onReceive(Context context, Intent intent) {
109049fa016a98cef9940c883b3f620a0e90537a204eJason Monk            String action = intent.getAction();
1091d002a0a96eb857804b3aafbcd32cf66a378c5b6cSiarhei Vishniakou            if (Intent.ACTION_SCREEN_OFF.equals(action)
1092d002a0a96eb857804b3aafbcd32cf66a378c5b6cSiarhei Vishniakou                    || Intent.ACTION_SCREEN_ON.equals(action)) {
1093d002a0a96eb857804b3aafbcd32cf66a378c5b6cSiarhei Vishniakou                notifyNavigationBarScreenOn();
109449fa016a98cef9940c883b3f620a0e90537a204eJason Monk            }
1095a858c5f60f405621ee9b333c910084ec35150ceaPhil Weaver            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
1096a858c5f60f405621ee9b333c910084ec35150ceaPhil Weaver                // The accessibility settings may be different for the new user
1097a858c5f60f405621ee9b333c910084ec35150ceaPhil Weaver                updateAccessibilityServicesState(mAccessibilityManager);
1098a858c5f60f405621ee9b333c910084ec35150ceaPhil Weaver            };
109949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        }
110049fa016a98cef9940c883b3f620a0e90537a204eJason Monk    };
110149fa016a98cef9940c883b3f620a0e90537a204eJason Monk
11027d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
11037d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        // Invalidate any rotation suggestion on task change or activity orientation change
11047d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        // Note: all callbacks happen on main thread
11057d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
11067d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        @Override
11077d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        public void onTaskStackChanged() {
11081e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            setRotateSuggestionButtonState(false);
11097d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        }
11107d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
11117d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        @Override
11127d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        public void onTaskRemoved(int taskId) {
11131e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            setRotateSuggestionButtonState(false);
11147d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        }
11157d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
11167d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        @Override
11177d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        public void onTaskMovedToFront(int taskId) {
11181e28a5ae5031d1407cd2b55d5140ce336428a38bMike Digman            setRotateSuggestionButtonState(false);
11197d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        }
11207d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
11217d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        @Override
11227d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
112385a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            // Only hide the icon if the top task changes its requestedOrientation
112485a9bea67ad7c4199a95119af690eda5f9a06ce7Mike Digman            // Launcher can alter its requestedOrientation while it's not on top, don't hide on this
1125121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digman            Optional.ofNullable(ActivityManagerWrapper.getInstance())
1126121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digman                    .map(ActivityManagerWrapper::getRunningTask)
1127121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digman                    .ifPresent(a -> {
1128121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digman                        if (a.id == taskId) setRotateSuggestionButtonState(false);
1129121b11ff5b80f1d9e762120f9cd87834b05a5b6aMike Digman                    });
11307d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman        }
11317d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman    }
11327d09277f99ca919db70d45425bd366ff1b1b7e0eMike Digman
11335075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    private class ViewRippler {
11345075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        private static final int RIPPLE_OFFSET_MS = 50;
11355075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        private static final int RIPPLE_INTERVAL_MS = 2000;
11365075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        private View mRoot;
11375075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
11385075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        public void start(View root) {
11395075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            stop(); // Stop any pending ripple animations
11405075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
11415075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            mRoot = root;
11425075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
11435075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            // Schedule pending ripples, offset the 1st to avoid problems with visibility change
11445075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
11455075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
11465075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            mRoot.postOnAnimationDelayed(mRipple, 2*RIPPLE_INTERVAL_MS);
1147c038c32c7c171e004f7cb74a4ab1d469a3b87f18Mike Digman            mRoot.postOnAnimationDelayed(mRipple, 3*RIPPLE_INTERVAL_MS);
1148c038c32c7c171e004f7cb74a4ab1d469a3b87f18Mike Digman            mRoot.postOnAnimationDelayed(mRipple, 4*RIPPLE_INTERVAL_MS);
11495075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        }
11505075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
11515075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        public void stop() {
11525075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            if (mRoot != null) mRoot.removeCallbacks(mRipple);
11535075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        }
11545075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
11555075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        private final Runnable mRipple = new Runnable() {
11565075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            @Override
11575075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            public void run() { // Cause the ripple to fire via false presses
1158f4c989962cd8accf027b1f10d4cbd51249886b33Mike Digman                if (!mRoot.isAttachedToWindow()) return;
11595075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman                mRoot.setPressed(true);
11605075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman                mRoot.setPressed(false);
11615075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman            }
11625075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman        };
11635075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman    }
11645075264b6d0a9b2981713b6f65a4a65d2e9afce8Mike Digman
116549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    public static View create(Context context, FragmentListener listener) {
116649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
116749fa016a98cef9940c883b3f620a0e90537a204eJason Monk                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
116849fa016a98cef9940c883b3f620a0e90537a204eJason Monk                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
116949fa016a98cef9940c883b3f620a0e90537a204eJason Monk                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
117049fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
117149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
117249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
117349fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
117449fa016a98cef9940c883b3f620a0e90537a204eJason Monk                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
117549fa016a98cef9940c883b3f620a0e90537a204eJason Monk                PixelFormat.TRANSLUCENT);
117649fa016a98cef9940c883b3f620a0e90537a204eJason Monk        lp.token = new Binder();
117749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        lp.setTitle("NavigationBar");
11788583ae8a6af11bedbb00a4eb9efd2565da2fecbbPhil Weaver        lp.accessibilityTitle = context.getString(R.string.nav_bar);
117949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        lp.windowAnimations = 0;
118049fa016a98cef9940c883b3f620a0e90537a204eJason Monk
118149fa016a98cef9940c883b3f620a0e90537a204eJason Monk        View navigationBarView = LayoutInflater.from(context).inflate(
118249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                R.layout.navigation_bar_window, null);
118349fa016a98cef9940c883b3f620a0e90537a204eJason Monk
118449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
118549fa016a98cef9940c883b3f620a0e90537a204eJason Monk        if (navigationBarView == null) return null;
118649fa016a98cef9940c883b3f620a0e90537a204eJason Monk
118749fa016a98cef9940c883b3f620a0e90537a204eJason Monk        context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
118849fa016a98cef9940c883b3f620a0e90537a204eJason Monk        FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
118949fa016a98cef9940c883b3f620a0e90537a204eJason Monk        NavigationBarFragment fragment = new NavigationBarFragment();
119049fa016a98cef9940c883b3f620a0e90537a204eJason Monk        fragmentHost.getFragmentManager().beginTransaction()
119149fa016a98cef9940c883b3f620a0e90537a204eJason Monk                .replace(R.id.navigation_bar_frame, fragment, TAG)
119249fa016a98cef9940c883b3f620a0e90537a204eJason Monk                .commit();
119349fa016a98cef9940c883b3f620a0e90537a204eJason Monk        fragmentHost.addTagListener(TAG, listener);
119449fa016a98cef9940c883b3f620a0e90537a204eJason Monk        return navigationBarView;
119549fa016a98cef9940c883b3f620a0e90537a204eJason Monk    }
119649fa016a98cef9940c883b3f620a0e90537a204eJason Monk}
1197