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

Commit 8c9a83fe authored by Charles Chen's avatar Charles Chen
Browse files

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
parent f3d295c5
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager;
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 @@ public class Dependency extends SystemUI {
    @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 @@ public class Dependency extends SystemUI {
        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;
    }

+8 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.systemui.plugins.PluginInitializerImpl;
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 class DependencyProvider {
    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);
    }
}
+12 −11
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.view.WindowManagerGlobal;

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 @@ public class NavigationBarController implements DisplayListener {
            // 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 @@ public class NavigationBarController implements DisplayListener {
        }
    }

    /** @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);
+216 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+15 −92
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import android.telecom.TelecomManager;
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.View;
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 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback

    /** 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 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
    private AccessibilityManager mAccessibilityManager;
    private MagnificationContentObserver mMagnificationObserver;
    private ContentResolver mContentResolver;
    private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();

    private int mDisabledFlags1;
    private int mDisabledFlags2;
@@ -155,6 +152,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback

    private int mSystemUiVisibility;
    private LightBarController mLightBarController;
    private AutoHideController mAutoHideController;

    private OverviewProxyService mOverviewProxyService;

@@ -164,9 +162,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback

    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 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        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,7 +458,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
            mNavigationBarMode = barMode;
        }
        checkNavBarModes();
        touchAutoHide();
        mAutoHideController.touchAutoHide();

        mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
                true /* nbModeChanged */, mNavigationBarMode);
@@ -502,16 +490,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
                    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 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
    }

    private boolean onNavigationTouch(View v, MotionEvent event) {
        checkUserAutoHide(event);
        mAutoHideController.checkUserAutoHide(event);
        return false;
    }

@@ -867,77 +846,15 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        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 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
        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;
    }
Loading