• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.phone;
18 
19 import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
20 
21 import android.content.Context;
22 import android.os.Handler;
23 import android.os.RemoteException;
24 import android.util.Log;
25 import android.view.IWindowManager;
26 import android.view.MotionEvent;
27 import android.view.accessibility.AccessibilityManager;
28 
29 import androidx.annotation.NonNull;
30 
31 import com.android.systemui.dagger.SysUISingleton;
32 import com.android.systemui.dagger.qualifiers.Main;
33 import com.android.systemui.statusbar.AutoHideUiElement;
34 
35 import java.io.PrintWriter;
36 
37 import javax.inject.Inject;
38 
39 /** A controller to control all auto-hide things. Also see {@link AutoHideUiElement}. */
40 @SysUISingleton
41 public class AutoHideController {
42     private static final String TAG = "AutoHideController";
43     private static final int AUTO_HIDE_TIMEOUT_MS = 2250;
44     private static final int USER_AUTO_HIDE_TIMEOUT_MS = 350;
45 
46     private final AccessibilityManager mAccessibilityManager;
47     private final IWindowManager mWindowManagerService;
48     private final Handler mHandler;
49 
50     private AutoHideUiElement mStatusBar;
51     /** For tablets, this will represent the Taskbar */
52     private AutoHideUiElement mNavigationBar;
53     private int mDisplayId;
54 
55     private boolean mAutoHideSuspended;
56 
57     private final Runnable mAutoHide = () -> {
58         if (isAnyTransientBarShown()) {
59             hideTransientBars();
60         }
61     };
62 
63     @Inject
AutoHideController(Context context, @Main Handler handler, IWindowManager iWindowManager)64     public AutoHideController(Context context,
65             @Main Handler handler,
66             IWindowManager iWindowManager) {
67         mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
68         mHandler = handler;
69         mWindowManagerService = iWindowManager;
70         mDisplayId = context.getDisplayId();
71     }
72 
73     /**
74      * Sets a {@link AutoHideUiElement} status bar that should be controlled by the
75      * {@link AutoHideController}.
76      */
setStatusBar(AutoHideUiElement element)77     public void setStatusBar(AutoHideUiElement element) {
78         mStatusBar = element;
79     }
80 
81     /**
82      * Sets a {@link AutoHideUiElement} navigation bar that should be controlled by the
83      * {@link AutoHideController}.
84      */
setNavigationBar(AutoHideUiElement element)85     public void setNavigationBar(AutoHideUiElement element) {
86         mNavigationBar = element;
87     }
88 
hideTransientBars()89     private void hideTransientBars() {
90         try {
91             mWindowManagerService.hideTransientBars(mDisplayId);
92         } catch (RemoteException ex) {
93             Log.w(TAG, "Cannot get WindowManager");
94         }
95 
96         if (mStatusBar != null) {
97             mStatusBar.hide();
98         }
99 
100         if (mNavigationBar != null) {
101             mNavigationBar.hide();
102         }
103     }
104 
resumeSuspendedAutoHide()105     public void resumeSuspendedAutoHide() {
106         if (mAutoHideSuspended) {
107             scheduleAutoHide();
108             Runnable checkBarModesRunnable = getCheckBarModesRunnable();
109             if (checkBarModesRunnable != null) {
110                 mHandler.postDelayed(checkBarModesRunnable, 500); // longer than home -> launcher
111             }
112         }
113     }
114 
suspendAutoHide()115     public void suspendAutoHide() {
116         mHandler.removeCallbacks(mAutoHide);
117         Runnable checkBarModesRunnable = getCheckBarModesRunnable();
118         if (checkBarModesRunnable != null) {
119             mHandler.removeCallbacks(checkBarModesRunnable);
120         }
121         mAutoHideSuspended = isAnyTransientBarShown();
122     }
123 
124     /** Schedules or cancels auto hide behavior based on current system bar state. */
touchAutoHide()125     public void touchAutoHide() {
126         // update transient bar auto hide
127         if (isAnyTransientBarShown()) {
128             scheduleAutoHide();
129         } else {
130             cancelAutoHide();
131         }
132     }
133 
getCheckBarModesRunnable()134     private Runnable getCheckBarModesRunnable() {
135         if (mStatusBar != null) {
136             return () -> mStatusBar.synchronizeState();
137         } else if (mNavigationBar != null) {
138             return () -> mNavigationBar.synchronizeState();
139         } else {
140             return null;
141         }
142     }
143 
cancelAutoHide()144     private void cancelAutoHide() {
145         mAutoHideSuspended = false;
146         mHandler.removeCallbacks(mAutoHide);
147     }
148 
scheduleAutoHide()149     private void scheduleAutoHide() {
150         cancelAutoHide();
151         mHandler.postDelayed(mAutoHide, getAutoHideTimeout());
152     }
153 
getAutoHideTimeout()154     private int getAutoHideTimeout() {
155         return mAccessibilityManager.getRecommendedTimeoutMillis(AUTO_HIDE_TIMEOUT_MS,
156                 FLAG_CONTENT_CONTROLS);
157     }
158 
checkUserAutoHide(MotionEvent event)159     public void checkUserAutoHide(MotionEvent event) {
160         boolean shouldHide = isAnyTransientBarShown()
161                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar.
162                 && event.getX() == 0 && event.getY() == 0;
163 
164         if (mStatusBar != null) {
165             shouldHide &= mStatusBar.shouldHideOnTouch();
166         }
167         if (mNavigationBar != null) {
168             shouldHide &= mNavigationBar.shouldHideOnTouch();
169         }
170 
171         if (shouldHide) {
172             userAutoHide();
173         }
174     }
175 
userAutoHide()176     private void userAutoHide() {
177         cancelAutoHide();
178         // longer than app gesture -> flag clear
179         mHandler.postDelayed(mAutoHide, getUserAutoHideTimeout());
180     }
181 
getUserAutoHideTimeout()182     private int getUserAutoHideTimeout() {
183         return mAccessibilityManager.getRecommendedTimeoutMillis(USER_AUTO_HIDE_TIMEOUT_MS,
184                 FLAG_CONTENT_CONTROLS);
185     }
186 
isAnyTransientBarShown()187     private boolean isAnyTransientBarShown() {
188         if (mStatusBar != null && mStatusBar.isVisible()) {
189             return true;
190         }
191 
192         if (mNavigationBar != null && mNavigationBar.isVisible()) {
193             return true;
194         }
195 
196         return false;
197     }
198 
dump(@onNull PrintWriter pw)199     public void dump(@NonNull PrintWriter pw) {
200         pw.println("AutoHideController:");
201         pw.println("\tmAutoHideSuspended=" + mAutoHideSuspended);
202         pw.println("\tisAnyTransientBarShown=" + isAnyTransientBarShown());
203         pw.println("\thasPendingAutoHide=" + mHandler.hasCallbacks(mAutoHide));
204         pw.println("\tgetAutoHideTimeout=" + getAutoHideTimeout());
205         pw.println("\tgetUserAutoHideTimeout=" + getUserAutoHideTimeout());
206     }
207 
208     /**
209      * Injectable factory for creating a {@link AutoHideController}.
210      */
211     public static class Factory {
212         private final Handler mHandler;
213         private final IWindowManager mIWindowManager;
214 
215         @Inject
Factory(@ain Handler handler, IWindowManager iWindowManager)216         public Factory(@Main Handler handler, IWindowManager iWindowManager) {
217             mHandler = handler;
218             mIWindowManager = iWindowManager;
219         }
220 
221         /** Create an {@link AutoHideController} */
create(Context context)222         public AutoHideController create(Context context) {
223             return new AutoHideController(context, mHandler, mIWindowManager);
224         }
225     }
226 }
227