Introduce AutoHideController to centralize call to WMS (4/N)

AutoHideController is a per-display controller and has following tasks:
1. Control all auto-hide logic in SystemUi
2. Update hide/unhide status to WMS

Bug: 117478341
Test: atest SystemUITests

Change-Id: I5066030c750f72e6e0b0d70cd377109458989c7d
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 6e50429..c9ca972 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -65,6 +65,7 @@
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
@@ -270,6 +271,7 @@
     @Inject
     Lazy<NotificationAlertingManager> mNotificationAlertingManager;
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
+    @Inject Lazy<AutoHideController> mAutoHideController;
     @Inject @Named(BG_LOOPER_NAME) Lazy<Looper> mBgLooper;
     @Inject @Named(BG_HANDLER_NAME) Lazy<Handler> mBgHandler;
     @Inject @Named(MAIN_HANDLER_NAME) Lazy<Handler> mMainHandler;
@@ -443,6 +445,12 @@
         mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
         mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get);
 
+        // TODO(b/118592525): to support multi-display , we start to add something which is
+        //                    per-display, while others may be global. I think it's time to add
+        //                    a new class maybe named DisplayDependency to solve per-display
+        //                    Dependency problem.
+        mProviders.put(AutoHideController.class, mAutoHideController::get);
+
         sDependency = this;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index 5c9b999..dac977a 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -42,6 +42,7 @@
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
 import com.android.systemui.statusbar.NavigationBarController;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -181,4 +182,11 @@
     public ConfigurationController provideConfigurationController(Context context) {
         return new ConfigurationControllerImpl(context);
     }
+
+    @Singleton
+    @Provides
+    public AutoHideController provideAutoHideController(Context context,
+            @Named(MAIN_HANDLER_NAME) Handler mainHandler) {
+        return new AutoHideController(context, mainHandler);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 43eaff4..9740d1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -34,6 +34,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.phone.NavigationBarFragment;
@@ -132,12 +133,21 @@
             // Unfortunately, we still need it because status bar needs LightBarController
             // before notifications creation. We cannot directly use getLightBarController()
             // from NavigationBarFragment directly.
-            LightBarController controller = isOnDefaultDisplay
+            LightBarController lightBarController = isOnDefaultDisplay
                     ? Dependency.get(LightBarController.class)
                     : new LightBarController(context,
                             Dependency.get(DarkIconDispatcher.class),
                             Dependency.get(BatteryController.class));
-            navBar.setLightBarController(controller);
+            navBar.setLightBarController(lightBarController);
+
+            // TODO(b/118592525): to support multi-display, we start to add something which is
+            //                    per-display, while others may be global. I think it's time to add
+            //                    a new class maybe named DisplayDependency to solve per-display
+            //                    Dependency problem.
+            AutoHideController autoHideController = isOnDefaultDisplay
+                    ? Dependency.get(AutoHideController.class)
+                    : new AutoHideController(context, mHandler);
+            navBar.setAutoHideController(autoHideController);
             navBar.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
             mNavigationBars.append(displayId, navBar);
         });
@@ -197,15 +207,6 @@
         }
     }
 
-    /** @see NavigationBarFragment#isSemiTransparent() */
-    public boolean isSemiTransparent(int displayId) {
-        NavigationBarFragment navBar = mNavigationBars.get(displayId);
-        if (navBar != null) {
-            return navBar.isSemiTransparent();
-        }
-        return false;
-    }
-
     /** @see NavigationBarFragment#disableAnimationsDuringHide(long) */
     public void disableAnimationsDuringHide(int displayId, long delay) {
         NavigationBarFragment navBar = mNavigationBars.get(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
new file mode 100644
index 0000000..b9425d4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/** A controller to control all auto-hide things. */
+public class AutoHideController implements CommandQueue.Callbacks {
+    private static final String TAG = "AutoHideController";
+
+    private final IWindowManager mWindowManagerService;
+
+    private final Handler mHandler;
+    private final NotificationRemoteInputManager mRemoteInputManager;
+    private final CommandQueue mCommandQueue;
+    private StatusBar mStatusBar;
+    private NavigationBarFragment mNavigationBar;
+
+    private int mDisplayId;
+    private int mSystemUiVisibility;
+    // last value sent to window manager
+    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
+
+    private boolean mAutoHideSuspended;
+
+    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
+
+    private final Runnable mAutoHide = () -> {
+        int requested = mSystemUiVisibility & ~getTransientMask();
+        if (mSystemUiVisibility != requested) {
+            notifySystemUiVisibilityChanged(requested);
+        }
+    };
+
+    @Inject
+    public AutoHideController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
+        mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+        mCommandQueue.addCallback(this);
+        mHandler = handler;
+        mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
+        mWindowManagerService = Dependency.get(IWindowManager.class);
+
+        mDisplayId = context.getDisplayId();
+    }
+
+    void setStatusBar(StatusBar statusBar) {
+        mStatusBar = statusBar;
+    }
+
+    void setNavigationBar(NavigationBarFragment navigationBar) {
+        mNavigationBar = navigationBar;
+    }
+
+    @Override
+    public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+            int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        if (displayId != mDisplayId) {
+            return;
+        }
+        int oldVal = mSystemUiVisibility;
+        int newVal = (oldVal & ~mask) | (vis & mask);
+        int diff = newVal ^ oldVal;
+
+        if (diff != 0) {
+            mSystemUiVisibility = newVal;
+
+            // ready to unhide
+            if (hasStatusBar() && (vis & View.STATUS_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
+            }
+
+            if (hasNavigationBar() && (vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
+                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
+            }
+
+            // Re-send setSystemUiVisibility to update un-hide status.
+            if (mSystemUiVisibility != newVal) {
+                mCommandQueue.setSystemUiVisibility(mDisplayId, mSystemUiVisibility,
+                        fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds,
+                        dockedStackBounds);
+            }
+
+            notifySystemUiVisibilityChanged(mSystemUiVisibility);
+        }
+    }
+
+    private void notifySystemUiVisibilityChanged(int vis) {
+        try {
+            if (mLastDispatchedSystemUiVisibility != vis) {
+                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
+                mLastDispatchedSystemUiVisibility = vis;
+            }
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Cannot get WindowManager");
+        }
+    }
+
+    void resumeSuspendedAutoHide() {
+        if (mAutoHideSuspended) {
+            scheduleAutoHide();
+            Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+            if (checkBarModesRunnable != null) {
+                mHandler.postDelayed(checkBarModesRunnable, 500); // longer than home -> launcher
+            }
+        }
+    }
+
+    void suspendAutoHide() {
+        mHandler.removeCallbacks(mAutoHide);
+        Runnable checkBarModesRunnable = getCheckBarModesRunnable();
+        if (checkBarModesRunnable != null) {
+            mHandler.removeCallbacks(checkBarModesRunnable);
+        }
+        mAutoHideSuspended = (mSystemUiVisibility & getTransientMask()) != 0;
+    }
+
+    void touchAutoHide() {
+        // update transient bar auto hide
+        if ((hasStatusBar() && mStatusBar.getStatusBarMode() == MODE_SEMI_TRANSPARENT)
+                || hasNavigationBar() && mNavigationBar.isSemiTransparent()) {
+            scheduleAutoHide();
+        } else {
+            cancelAutoHide();
+        }
+    }
+
+    private Runnable getCheckBarModesRunnable() {
+        if (hasStatusBar()) {
+            return () -> mStatusBar.checkBarModes();
+        } else if (hasNavigationBar()) {
+            return () -> mNavigationBar.checkNavBarModes();
+        } else {
+            return null;
+        }
+    }
+
+    private void cancelAutoHide() {
+        mAutoHideSuspended = false;
+        mHandler.removeCallbacks(mAutoHide);
+    }
+
+    private void scheduleAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
+    }
+
+    void checkUserAutoHide(MotionEvent event) {
+        boolean shouldAutoHide =
+                (mSystemUiVisibility & getTransientMask()) != 0  // a transient bar is revealed.
+                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
+                && event.getX() == 0 && event.getY() == 0;
+        if (hasStatusBar()) {
+            // a touch outside both bars
+            shouldAutoHide &= !mRemoteInputManager.getController().isRemoteInputActive();
+        }
+        if (shouldAutoHide) {
+            userAutoHide();
+        }
+    }
+
+    private void userAutoHide() {
+        cancelAutoHide();
+        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
+    }
+
+    private int getTransientMask() {
+        int mask = 0;
+        if (hasStatusBar()) {
+            mask |= View.STATUS_BAR_TRANSIENT;
+        }
+        if (hasNavigationBar()) {
+            mask |= View.NAVIGATION_BAR_TRANSIENT;
+        }
+        return mask;
+    }
+
+    private boolean hasNavigationBar() {
+        return mNavigationBar != null;
+    }
+
+    private boolean hasStatusBar() {
+        return mStatusBar != null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 9df5684a..6d97d67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -62,7 +62,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Display;
-import android.view.IWindowManager;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -71,7 +70,6 @@
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
-import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
@@ -123,7 +121,7 @@
 
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
-    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
+    private static final long AUTODIM_TIMEOUT_MS = 2250;
 
     private final AccessibilityManagerWrapper mAccessibilityManagerWrapper;
     protected final AssistManager mAssistManager;
@@ -139,7 +137,6 @@
     private AccessibilityManager mAccessibilityManager;
     private MagnificationContentObserver mMagnificationObserver;
     private ContentResolver mContentResolver;
-    private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
@@ -155,6 +152,7 @@
 
     private int mSystemUiVisibility;
     private LightBarController mLightBarController;
+    private AutoHideController mAutoHideController;
 
     private OverviewProxyService mOverviewProxyService;
 
@@ -164,9 +162,6 @@
 
     private Handler mHandler = Dependency.get(Dependency.MAIN_HANDLER);
 
-    // last value sent to window manager
-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
@@ -207,19 +202,12 @@
         if (visible) {
             // If the button will actually become visible and the navbar is about to hide,
             // tell the statusbar to keep it around for longer
-            touchAutoHide();
+            mAutoHideController.touchAutoHide();
         }
     };
 
     private final Runnable mAutoDim = () -> getBarTransitions().setAutoDim(true);
 
-    private final Runnable mAutoHide = () -> {
-        int requested = mSystemUiVisibility & ~View.NAVIGATION_BAR_TRANSIENT;
-        if (mSystemUiVisibility != requested) {
-            notifySystemUiVisibilityChanged(requested);
-        }
-    };
-
     @Inject
     public NavigationBarFragment(AccessibilityManagerWrapper accessibilityManagerWrapper,
             DeviceProvisionedController deviceProvisionedController, MetricsLogger metricsLogger,
@@ -470,10 +458,10 @@
             mNavigationBarMode = barMode;
         }
         checkNavBarModes();
-        touchAutoHide();
+        mAutoHideController.touchAutoHide();
 
         mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
-                    true /* nbModeChanged */, mNavigationBarMode);
+                true /* nbModeChanged */, mNavigationBarMode);
     }
 
     @Override
@@ -502,16 +490,7 @@
                     mNavigationBarMode = nbMode;
                     checkNavBarModes();
                 }
-                touchAutoHide();
-            }
-            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
-            }
-
-
-            // On the default display, just make StatusBar do this job.
-            if (!mIsOnDefaultDisplay) {
-                notifySystemUiVisibilityChanged(mSystemUiVisibility);
+                mAutoHideController.touchAutoHide();
             }
         }
         mLightBarController.onNavigationVisibilityChanged(
@@ -677,7 +656,7 @@
     }
 
     private boolean onNavigationTouch(View v, MotionEvent event) {
-        checkUserAutoHide(event);
+        mAutoHideController.checkUserAutoHide(event);
         return false;
     }
 
@@ -867,77 +846,15 @@
         mNavigationBarView.setAccessibilityButtonState(showAccessibilityButton, targetSelection);
     }
 
-    private void touchAutoHide() {
-        // There is status bar on default display. Thus the hide animations should apply on both
-        // status/navigation bar.
-        if (mIsOnDefaultDisplay) {
-            mStatusBar.touchAutoHide();
-        } else {
-            touchAutoHideInternal();
-        }
-    }
-
-    private void touchAutoHideInternal() {
-        // update transient bar autoHide.
-        if (isSemiTransparent()) {
-            scheduleAutoHide();
-        } else {
-            cancelAutoHide();
-        }
-    }
-
-    private void checkUserAutoHide(MotionEvent event) {
-        // There is status bar on default display. Thus the hide animations should apply on both
-        // status/navigation bar.
-        if (mIsOnDefaultDisplay) {
-            mStatusBar.checkUserAutoHide(event);
-        } else {
-            checkUserAutoHideInternal(event);
-        }
-    }
-
-    private void checkUserAutoHideInternal(MotionEvent event) {
-        if ((mSystemUiVisibility & View.NAVIGATION_BAR_TRANSIENT) != 0
-                // a transient bar is revealed
-                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
-                && event.getX() == 0 && event.getY() == 0) { // a touch outside both bars.
-            userAutoHide();
-        }
-    }
-
-    private void userAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear.
-    }
-
-    private void cancelAutoHide() {
-        mHandler.removeCallbacks(mAutoHide);
-    }
-
-    private void scheduleAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
-    }
-
-    private void notifySystemUiVisibilityChanged(int vis) {
-        try {
-            if (mLastDispatchedSystemUiVisibility != vis) {
-                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
-                mLastDispatchedSystemUiVisibility = vis;
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     // ----- Methods that DisplayNavigationBarController talks to -----
 
-    /** Applys auto dimming animation on navigation bar when touched. */
+    /** Applies auto dimming animation on navigation bar when touched. */
     public void touchAutoDim() {
         getBarTransitions().setAutoDim(false);
         mHandler.removeCallbacks(mAutoDim);
         int state = Dependency.get(StatusBarStateController.class).getState();
         if (state != StatusBarState.KEYGUARD && state != StatusBarState.SHADE_LOCKED) {
-            mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
+            mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
         }
     }
 
@@ -946,6 +863,12 @@
         mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
     }
 
+    /** Sets {@link AutoHideController} to the navigation bar. */
+    public void setAutoHideController(AutoHideController autoHideController) {
+        mAutoHideController = autoHideController;
+        mAutoHideController.setNavigationBar(this);
+    }
+
     public boolean isSemiTransparent() {
         return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7265b77..b233018 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -290,10 +290,6 @@
 
     protected static final boolean CLOSE_PANEL_WHEN_EMPTIED = true;
 
-    private static final int STATUS_OR_NAV_TRANSIENT =
-            View.STATUS_BAR_TRANSIENT | View.NAVIGATION_BAR_TRANSIENT;
-    private static final long AUTOHIDE_TIMEOUT_MS = 2250;
-
     /**
      * The delay to reset the hint text when the hint animation is finished running.
      */
@@ -342,6 +338,8 @@
     protected BiometricUnlockController mBiometricUnlockController;
     private LightBarController mLightBarController;
     protected LockscreenWallpaper mLockscreenWallpaper;
+    @VisibleForTesting
+    protected AutoHideController mAutoHideController;
 
     private int mNaturalBarHeight = -1;
 
@@ -406,9 +404,6 @@
     private final Rect mLastFullscreenStackBounds = new Rect();
     private final Rect mLastDockedStackBounds = new Rect();
 
-    // last value sent to window manager
-    private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
-
     private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
 
     // XXX: gesture research
@@ -448,7 +443,6 @@
     protected final H mHandler = createHandler();
 
     private int mInteractingWindows;
-    private boolean mAutoHideSuspended;
     private @TransitionMode int mStatusBarMode;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
@@ -456,13 +450,6 @@
     protected DozeScrimController mDozeScrimController;
     private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
 
-    private final Runnable mAutoHide = () -> {
-        int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
-        if (mSystemUiVisibility != requested) {
-            notifySystemUiVisibilityChanged(requested);
-        }
-    };
-
     protected boolean mDozing;
     private boolean mDozingRequested;
 
@@ -904,6 +891,9 @@
             }
         });
 
+        mAutoHideController = Dependency.get(AutoHideController.class);
+        mAutoHideController.setStatusBar(this);
+
         mLightBarController = Dependency.get(LightBarController.class);
 
         ScrimView scrimBehind = mStatusBarWindow.findViewById(R.id.scrim_behind);
@@ -1102,7 +1092,7 @@
      */
     protected View.OnTouchListener getStatusBarWindowTouchListener() {
         return (v, event) -> {
-            checkUserAutoHide(event);
+            mAutoHideController.checkUserAutoHide(event);
             mRemoteInputManager.checkRemoteInputOutside(event);
             if (event.getAction() == MotionEvent.ACTION_DOWN) {
                 if (mExpandedVisible) {
@@ -2073,7 +2063,6 @@
 
             // ready to unhide
             if ((vis & View.STATUS_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE;
                 mNoAnimationOnNextBarModeChange = true;
             }
 
@@ -2084,17 +2073,9 @@
             if (sbModeChanged && sbMode != mStatusBarMode) {
                 mStatusBarMode = sbMode;
                 checkBarModes();
-                touchAutoHide();
+                mAutoHideController.touchAutoHide();
             }
-
-            if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
-                mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE;
-            }
-
-            // send updated sysui visibility to window manager
-            notifySystemUiVisibilityChanged(mSystemUiVisibility);
         }
-
         mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
                 mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
     }
@@ -2122,16 +2103,6 @@
         }
     }
 
-    void touchAutoHide() {
-        // update transient bar auto hide
-        if (mStatusBarMode == MODE_SEMI_TRANSPARENT
-                || mNavigationBarController.isSemiTransparent(mDisplayId)) {
-            scheduleAutoHide();
-        } else {
-            cancelAutoHide();
-        }
-    }
-
     protected @TransitionMode int computeStatusBarMode(int oldVal, int newVal) {
         return computeBarMode(oldVal, newVal);
     }
@@ -2201,9 +2172,9 @@
                 ? (mInteractingWindows | barWindow)
                 : (mInteractingWindows & ~barWindow);
         if (mInteractingWindows != 0) {
-            suspendAutoHide();
+            mAutoHideController.suspendAutoHide();
         } else {
-            resumeSuspendedAutoHide();
+            mAutoHideController.resumeSuspendedAutoHide();
         }
         // manually dismiss the volume panel when interacting with the nav bar
         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
@@ -2219,44 +2190,6 @@
         }
     }
 
-    private void resumeSuspendedAutoHide() {
-        if (mAutoHideSuspended) {
-            scheduleAutoHide();
-            mHandler.postDelayed(mCheckBarModes, 500); // longer than home -> launcher
-        }
-    }
-
-    private void suspendAutoHide() {
-        mHandler.removeCallbacks(mAutoHide);
-        mHandler.removeCallbacks(mCheckBarModes);
-        mAutoHideSuspended = (mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0;
-    }
-
-    private void cancelAutoHide() {
-        mAutoHideSuspended = false;
-        mHandler.removeCallbacks(mAutoHide);
-    }
-
-    private void scheduleAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, AUTOHIDE_TIMEOUT_MS);
-    }
-
-    void checkUserAutoHide(MotionEvent event) {
-        if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
-                && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
-                && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
-                && !mRemoteInputManager.getController()
-                        .isRemoteInputActive()) { // not due to typing in IME
-            userAutoHide();
-        }
-    }
-
-    private void userAutoHide() {
-        cancelAutoHide();
-        mHandler.postDelayed(mAutoHide, 350); // longer than app gesture -> flag clear
-    }
-
     private boolean areLightsOn() {
         return 0 == (mSystemUiVisibility & View.SYSTEM_UI_FLAG_LOW_PROFILE);
     }
@@ -2273,16 +2206,6 @@
         }
     }
 
-    private void notifySystemUiVisibilityChanged(int vis) {
-        try {
-            if (mLastDispatchedSystemUiVisibility != vis) {
-                mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
-                mLastDispatchedSystemUiVisibility = vis;
-            }
-        } catch (RemoteException ex) {
-        }
-    }
-
     @Override
     public void topAppWindowChanged(int displayId, boolean showMenu) {
         if (mDisplayId != displayId) return;
@@ -4479,4 +4402,8 @@
     public interface StatusBarInjector {
         void createStatusBar(StatusBar statusbar);
     }
+
+    public @TransitionMode int getStatusBarMode() {
+        return mStatusBarMode;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 56a196d..d57d565 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -248,7 +248,8 @@
                 mock(StatusBarWindowController.class), mock(NotificationIconAreaController.class),
                 mDozeScrimController, mock(NotificationShelf.class),
                 mLockscreenUserManager, mCommandQueue, mNotificationPresenter,
-                mock(BubbleController.class), mock(NavigationBarController.class));
+                mock(BubbleController.class), mock(NavigationBarController.class),
+                mock(AutoHideController.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         SystemUIFactory.getInstance().getRootComponent()
@@ -700,7 +701,8 @@
                 CommandQueue commandQueue,
                 NotificationPresenter notificationPresenter,
                 BubbleController bubbleController,
-                NavigationBarController navBarController) {
+                NavigationBarController navBarController,
+                AutoHideController autoHideController) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -732,6 +734,7 @@
             mGestureWakeLock = mock(PowerManager.WakeLock.class);
             mBubbleController = bubbleController;
             mNavigationBarController = navBarController;
+            mAutoHideController = autoHideController;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {