• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.navigationbar;
18 
19 import static android.app.StatusBarManager.WINDOW_NAVIGATION_BAR;
20 import static android.app.StatusBarManager.WindowVisibleState;
21 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
22 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
23 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
24 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
25 
26 import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON;
27 import static com.android.systemui.accessibility.SystemActions.SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER;
28 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
30 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
31 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
32 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
33 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
34 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
35 
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.res.Configuration;
39 import android.database.ContentObserver;
40 import android.inputmethodservice.InputMethodService;
41 import android.net.Uri;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.os.Looper;
45 import android.os.Process;
46 import android.os.RemoteException;
47 import android.os.UserHandle;
48 import android.provider.Settings;
49 import android.provider.Settings.Secure;
50 import android.util.Log;
51 import android.view.IRotationWatcher;
52 import android.view.IWallpaperVisibilityListener;
53 import android.view.IWindowManager;
54 import android.view.View;
55 import android.view.WindowInsets;
56 import android.view.accessibility.AccessibilityManager;
57 
58 import androidx.annotation.NonNull;
59 
60 import com.android.internal.accessibility.common.ShortcutConstants;
61 import com.android.systemui.Dumpable;
62 import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
63 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
64 import com.android.systemui.accessibility.SystemActions;
65 import com.android.systemui.assist.AssistManager;
66 import com.android.systemui.dagger.SysUISingleton;
67 import com.android.systemui.dagger.qualifiers.Main;
68 import com.android.systemui.dump.DumpManager;
69 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
70 import com.android.systemui.recents.OverviewProxyService;
71 import com.android.systemui.settings.DisplayTracker;
72 import com.android.systemui.settings.UserTracker;
73 import com.android.systemui.shared.system.QuickStepContract;
74 import com.android.systemui.statusbar.CommandQueue;
75 import com.android.systemui.statusbar.NotificationShadeWindowController;
76 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
77 import com.android.systemui.statusbar.phone.CentralSurfaces;
78 import com.android.systemui.statusbar.policy.ConfigurationController;
79 import com.android.systemui.statusbar.policy.KeyguardStateController;
80 
81 import dagger.Lazy;
82 
83 import java.io.PrintWriter;
84 import java.util.ArrayList;
85 import java.util.List;
86 import java.util.Optional;
87 import java.util.concurrent.Executor;
88 
89 import javax.inject.Inject;
90 
91 /**
92  * Extracts shared elements between navbar and taskbar delegate to de-dupe logic and help them
93  * experience the joys of friendship.
94  * The events are then passed through
95  *
96  * Currently consolidates
97  * * A11y
98  * * Assistant
99  */
100 @SysUISingleton
101 public final class NavBarHelper implements
102         AccessibilityManager.AccessibilityServicesStateChangeListener,
103         AccessibilityButtonModeObserver.ModeChangedListener,
104         AccessibilityButtonTargetsObserver.TargetsChangedListener,
105         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
106         Dumpable, CommandQueue.Callbacks, ConfigurationController.ConfigurationListener {
107     private static final String TAG = NavBarHelper.class.getSimpleName();
108 
109     private final Handler mHandler = new Handler(Looper.getMainLooper());
110     private final Executor mMainExecutor;
111     private final AccessibilityManager mAccessibilityManager;
112     private final Lazy<AssistManager> mAssistManagerLazy;
113     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
114     private final KeyguardStateController mKeyguardStateController;
115     private final UserTracker mUserTracker;
116     private final SystemActions mSystemActions;
117     private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
118     private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
119     private final List<NavbarTaskbarStateUpdater> mStateListeners = new ArrayList<>();
120     private final Context mContext;
121     private final NotificationShadeWindowController mNotificationShadeWindowController;
122     private final CommandQueue mCommandQueue;
123     private final ContentResolver mContentResolver;
124     private final EdgeBackGestureHandler mEdgeBackGestureHandler;
125     private final IWindowManager mWm;
126     private final int mDefaultDisplayId;
127     private boolean mAssistantAvailable;
128     private boolean mLongPressHomeEnabled;
129     private boolean mAssistantTouchGestureEnabled;
130     private int mNavBarMode;
131     private long mA11yButtonState;
132     private int mRotationWatcherRotation;
133     private boolean mTogglingNavbarTaskbar;
134     private boolean mWallpaperVisible;
135 
136     // Attributes used in NavBarHelper.CurrentSysuiState
137     private int mWindowStateDisplayId;
138     private @WindowVisibleState int mWindowState;
139 
140     // Listens for changes to the assistant
141     private final ContentObserver mAssistContentObserver = new ContentObserver(mHandler) {
142         @Override
143         public void onChange(boolean selfChange, Uri uri) {
144             updateAssistantAvailability();
145         }
146     };
147 
148     // Listens for changes to the wallpaper visibility
149     private final IWallpaperVisibilityListener mWallpaperVisibilityListener =
150             new IWallpaperVisibilityListener.Stub() {
151                 @Override
152                 public void onWallpaperVisibilityChanged(boolean visible,
153                         int displayId) throws RemoteException {
154                     mHandler.post(() -> {
155                         mWallpaperVisible = visible;
156                         dispatchWallpaperVisibilityChanged(visible, displayId);
157                     });
158                 }
159             };
160 
161     // Listens for changes to display rotation
162     private final IRotationWatcher mRotationWatcher = new IRotationWatcher.Stub() {
163         @Override
164         public void onRotationChanged(final int rotation) {
165             // We need this to be scheduled as early as possible to beat the redrawing of
166             // window in response to the orientation change.
167             mHandler.postAtFrontOfQueue(() -> {
168                 mRotationWatcherRotation = rotation;
169                 dispatchRotationChanged(rotation);
170             });
171         }
172     };
173 
174     /**
175      * @param context This is not display specific, then again neither is any of the code in
176      *                this class. Once there's display specific code, we may want to create an
177      *                instance of this class per navbar vs having it be a singleton.
178      */
179     @Inject
NavBarHelper(Context context, AccessibilityManager accessibilityManager, AccessibilityButtonModeObserver accessibilityButtonModeObserver, AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, SystemActions systemActions, OverviewProxyService overviewProxyService, Lazy<AssistManager> assistManagerLazy, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, KeyguardStateController keyguardStateController, NavigationModeController navigationModeController, EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory, IWindowManager wm, UserTracker userTracker, DisplayTracker displayTracker, NotificationShadeWindowController notificationShadeWindowController, ConfigurationController configurationController, DumpManager dumpManager, CommandQueue commandQueue, @Main Executor mainExecutor)180     public NavBarHelper(Context context, AccessibilityManager accessibilityManager,
181             AccessibilityButtonModeObserver accessibilityButtonModeObserver,
182             AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver,
183             SystemActions systemActions,
184             OverviewProxyService overviewProxyService,
185             Lazy<AssistManager> assistManagerLazy,
186             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
187             KeyguardStateController keyguardStateController,
188             NavigationModeController navigationModeController,
189             EdgeBackGestureHandler.Factory edgeBackGestureHandlerFactory,
190             IWindowManager wm,
191             UserTracker userTracker,
192             DisplayTracker displayTracker,
193             NotificationShadeWindowController notificationShadeWindowController,
194             ConfigurationController configurationController,
195             DumpManager dumpManager,
196             CommandQueue commandQueue,
197             @Main Executor mainExecutor) {
198         // b/319489709: This component shouldn't be running for a non-primary user
199         if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
200             Log.wtf(TAG, "Unexpected initialization for non-primary user", new Throwable());
201         }
202         mContext = context;
203         mNotificationShadeWindowController = notificationShadeWindowController;
204         mCommandQueue = commandQueue;
205         mContentResolver = mContext.getContentResolver();
206         mAccessibilityManager = accessibilityManager;
207         mAssistManagerLazy = assistManagerLazy;
208         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
209         mKeyguardStateController = keyguardStateController;
210         mUserTracker = userTracker;
211         mSystemActions = systemActions;
212         mAccessibilityButtonModeObserver = accessibilityButtonModeObserver;
213         mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver;
214         mWm = wm;
215         mDefaultDisplayId = displayTracker.getDefaultDisplayId();
216         mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
217         mMainExecutor = mainExecutor;
218 
219         mNavBarMode = navigationModeController.addListener(this);
220         mCommandQueue.addCallback(this);
221         configurationController.addCallback(this);
222         overviewProxyService.addCallback(this);
223         dumpManager.registerDumpable(this);
224     }
225 
226     /**
227      * Hints to the helper that bars are being replaced, which is a signal to potentially suppress
228      * normal setup/cleanup when no bars are present.
229      */
setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar)230     public void setTogglingNavbarTaskbar(boolean togglingNavbarTaskbar) {
231         mTogglingNavbarTaskbar = togglingNavbarTaskbar;
232     }
233 
234     /**
235      * Called when the first (non-replacing) bar is registered.
236      */
setupOnFirstBar()237     private void setupOnFirstBar() {
238         // Setup accessibility listeners
239         mAccessibilityManager.addAccessibilityServicesStateChangeListener(this);
240         mAccessibilityButtonModeObserver.addListener(this);
241         mAccessibilityButtonTargetsObserver.addListener(this);
242 
243         // Setup assistant listener
244         mContentResolver.registerContentObserver(
245                 Settings.Secure.getUriFor(Settings.Secure.ASSISTANT),
246                 false /* notifyForDescendants */, mAssistContentObserver, UserHandle.USER_ALL);
247         mContentResolver.registerContentObserver(
248                 Settings.Secure.getUriFor(Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED),
249                 false, mAssistContentObserver, UserHandle.USER_ALL);
250         mContentResolver.registerContentObserver(
251                 Settings.Secure.getUriFor(Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED),
252                 false, mAssistContentObserver, UserHandle.USER_ALL);
253         mContentResolver.registerContentObserver(
254                 Settings.Secure.getUriFor(Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED),
255                 false, mAssistContentObserver, UserHandle.USER_ALL);
256 
257         // Setup display rotation watcher
258         try {
259             mWm.watchRotation(mRotationWatcher, mDefaultDisplayId);
260         } catch (Exception e) {
261             Log.w(TAG, "Failed to register rotation watcher", e);
262         }
263 
264         // Setup wallpaper visibility listener
265         try {
266             mWallpaperVisible = mWm.registerWallpaperVisibilityListener(
267                     mWallpaperVisibilityListener, mDefaultDisplayId);
268         } catch (Exception e) {
269             Log.w(TAG, "Failed to register wallpaper visibility listener", e);
270         }
271 
272         // Attach the back handler only when the first bar is registered
273         mEdgeBackGestureHandler.onNavBarAttached();
274     }
275 
276     /**
277      * Called after the last (non-replacing) bar is unregistered.
278      */
cleanupAfterLastBar()279     private void cleanupAfterLastBar() {
280         // Clean up accessibility listeners
281         mAccessibilityManager.removeAccessibilityServicesStateChangeListener(this);
282         mAccessibilityButtonModeObserver.removeListener(this);
283         mAccessibilityButtonTargetsObserver.removeListener(this);
284 
285         // Clean up assistant listeners
286         mContentResolver.unregisterContentObserver(mAssistContentObserver);
287 
288         // Clean up display rotation watcher
289         try {
290             mWm.removeRotationWatcher(mRotationWatcher);
291         } catch (Exception e) {
292             Log.w(TAG, "Failed to unregister rotation watcher", e);
293         }
294 
295         // Clean up wallpaper visibility listener
296         try {
297             mWm.unregisterWallpaperVisibilityListener(mWallpaperVisibilityListener,
298                     mDefaultDisplayId);
299         } catch (Exception e) {
300             Log.w(TAG, "Failed to register wallpaper visibility listener", e);
301         }
302 
303         // No more bars, detach the back handler for now
304         mEdgeBackGestureHandler.onNavBarDetached();
305     }
306 
307     /**
308      * Registers a listener for future updates to the shared navbar/taskbar state.
309      * @param listener Will immediately get callbacks based on current state
310      */
registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener)311     public void registerNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
312         mStateListeners.add(listener);
313         if (!mTogglingNavbarTaskbar && mStateListeners.size() == 1) {
314             setupOnFirstBar();
315 
316             // Update the state once the first bar is registered
317             updateAssistantAvailability();
318             updateA11yState();
319             mCommandQueue.recomputeDisableFlags(mContext.getDisplayId(), false /* animate */);
320         } else {
321             listener.updateAccessibilityServicesState();
322             listener.updateAssistantAvailable(mAssistantAvailable, mLongPressHomeEnabled);
323         }
324         listener.updateWallpaperVisibility(mWallpaperVisible, mDefaultDisplayId);
325         listener.updateRotationWatcherState(mRotationWatcherRotation);
326     }
327 
328     /**
329      * Removes a previously registered listener.
330      */
removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener)331     public void removeNavTaskStateUpdater(NavbarTaskbarStateUpdater listener) {
332         mStateListeners.remove(listener);
333         if (!mTogglingNavbarTaskbar && mStateListeners.isEmpty()) {
334             cleanupAfterLastBar();
335         }
336     }
337 
dispatchA11yEventUpdate()338     private void dispatchA11yEventUpdate() {
339         for (NavbarTaskbarStateUpdater listener : mStateListeners) {
340             listener.updateAccessibilityServicesState();
341         }
342     }
343 
dispatchAssistantEventUpdate(boolean assistantAvailable, boolean longPressHomeEnabled)344     private void dispatchAssistantEventUpdate(boolean assistantAvailable,
345             boolean longPressHomeEnabled) {
346         for (NavbarTaskbarStateUpdater listener : mStateListeners) {
347             listener.updateAssistantAvailable(assistantAvailable, longPressHomeEnabled);
348         }
349     }
350 
351     @Override
onAccessibilityServicesStateChanged(AccessibilityManager manager)352     public void onAccessibilityServicesStateChanged(AccessibilityManager manager) {
353         updateA11yState();
354     }
355 
356     @Override
onAccessibilityButtonModeChanged(int mode)357     public void onAccessibilityButtonModeChanged(int mode) {
358         updateA11yState();
359     }
360 
361     @Override
onAccessibilityButtonTargetsChanged(String targets)362     public void onAccessibilityButtonTargetsChanged(String targets) {
363         updateA11yState();
364     }
365 
366     @Override
onConfigChanged(Configuration newConfig)367     public void onConfigChanged(Configuration newConfig) {
368         mEdgeBackGestureHandler.onConfigurationChanged(newConfig);
369     }
370 
371     /**
372      * Updates the current accessibility button state. The accessibility button state is only
373      * used for {@link Secure#ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR} and
374      * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0.
375      */
updateA11yState()376     private void updateA11yState() {
377         final long prevState = mA11yButtonState;
378         final boolean clickable;
379         final boolean longClickable;
380         if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
381                 == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
382             // If accessibility button is floating menu mode, click and long click state should be
383             // disabled.
384             clickable = false;
385             longClickable = false;
386             mA11yButtonState = 0;
387         } else {
388             // AccessibilityManagerService resolves services for the current user since the local
389             // AccessibilityManager is created from a Context with the INTERACT_ACROSS_USERS
390             // permission
391             final List<String> a11yButtonTargets =
392                     mAccessibilityManager.getAccessibilityShortcutTargets(
393                             ShortcutConstants.UserShortcutType.SOFTWARE);
394             final int requestingServices = a11yButtonTargets.size();
395 
396             clickable = requestingServices >= 1;
397 
398             // `longClickable` is used to determine whether to pop up the accessibility chooser
399             // dialog or not, and it’s also only for multiple services.
400             longClickable = requestingServices >= 2;
401             mA11yButtonState = (clickable ? SYSUI_STATE_A11Y_BUTTON_CLICKABLE : 0)
402                     | (longClickable ? SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE : 0);
403         }
404 
405         // Update the system actions if the state has changed
406         if (prevState != mA11yButtonState) {
407             updateSystemAction(clickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON);
408             updateSystemAction(longClickable, SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER);
409         }
410 
411         dispatchA11yEventUpdate();
412     }
413 
414     /**
415      * Registers/unregisters the given system action id.
416      */
updateSystemAction(boolean register, int actionId)417     private void updateSystemAction(boolean register, int actionId) {
418         if (register) {
419             mSystemActions.register(actionId);
420         } else {
421             mSystemActions.unregister(actionId);
422         }
423     }
424 
425     /**
426      * Gets the accessibility button state based on the {@link Secure#ACCESSIBILITY_BUTTON_MODE}.
427      *
428      * @return the accessibility button state:
429      * 0 = disable state
430      * 16 = {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE}
431      * 48 = the combination of {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and
432      * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE}
433      */
getA11yButtonState()434     public long getA11yButtonState() {
435         return mA11yButtonState;
436     }
437 
438     @Override
onConnectionChanged(boolean isConnected)439     public void onConnectionChanged(boolean isConnected) {
440         if (isConnected) {
441             // We add the OPS callback during construction, so if the service is already connected
442             // then we will try to get the AssistManager dependency which itself has an indirect
443             // dependency on NavBarHelper leading to a cycle. For now, we can defer updating the
444             // assistant availability.
445             mMainExecutor.execute(this::updateAssistantAvailability);
446         }
447     }
448 
updateAssistantAvailability()449     private void updateAssistantAvailability() {
450         boolean assistantAvailableForUser = mAssistManagerLazy.get()
451                 .getAssistInfoForUser(mUserTracker.getUserId()) != null;
452 
453         boolean overrideLongPressHome = mAssistManagerLazy.get()
454                 .shouldOverrideAssist(AssistManager.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
455         boolean longPressDefault = mContext.getResources().getBoolean(overrideLongPressHome
456                 ? com.android.internal.R.bool.config_searchAllEntrypointsEnabledDefault
457                 : com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
458         mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
459                 overrideLongPressHome ? Secure.SEARCH_ALL_ENTRYPOINTS_ENABLED
460                         : Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
461                 mUserTracker.getUserId()) != 0;
462 
463         boolean gestureDefault = mContext.getResources().getBoolean(
464                 com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
465         mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
466                 Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
467                 mUserTracker.getUserId()) != 0;
468 
469         mAssistantAvailable = assistantAvailableForUser
470                 && mAssistantTouchGestureEnabled
471                 && QuickStepContract.isGesturalMode(mNavBarMode);
472         dispatchAssistantEventUpdate(mAssistantAvailable, mLongPressHomeEnabled);
473     }
474 
getLongPressHomeEnabled()475     public boolean getLongPressHomeEnabled() {
476         return mLongPressHomeEnabled;
477     }
478 
getEdgeBackGestureHandler()479     public EdgeBackGestureHandler getEdgeBackGestureHandler() {
480         return mEdgeBackGestureHandler;
481     }
482 
483     @Override
startAssistant(Bundle bundle)484     public void startAssistant(Bundle bundle) {
485         mAssistManagerLazy.get().startAssist(bundle);
486     }
487 
488     @Override
setAssistantOverridesRequested(int[] invocationTypes)489     public void setAssistantOverridesRequested(int[] invocationTypes) {
490         mAssistManagerLazy.get().setAssistantOverridesRequested(invocationTypes);
491         updateAssistantAvailability();
492     }
493 
494     @Override
onNavigationModeChanged(int mode)495     public void onNavigationModeChanged(int mode) {
496         mNavBarMode = mode;
497         updateAssistantAvailability();
498     }
499 
500     /**
501      * @return Whether the IME is shown on top of the screen given the {@code vis} flag of
502      * {@link InputMethodService} and the keyguard states.
503      */
isImeShown(int vis)504     public boolean isImeShown(int vis) {
505         View shadeWindowView =  mNotificationShadeWindowController.getWindowRootView();
506         boolean isKeyguardShowing = mKeyguardStateController.isShowing();
507         boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
508                 && shadeWindowView.getRootWindowInsets().isVisible(WindowInsets.Type.ime());
509         return imeVisibleOnShade
510                 || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0);
511     }
512 
513     @Override
setWindowState(int displayId, int window, int state)514     public void setWindowState(int displayId, int window, int state) {
515         CommandQueue.Callbacks.super.setWindowState(displayId, window, state);
516         if (window != WINDOW_NAVIGATION_BAR) {
517             return;
518         }
519         mWindowStateDisplayId = displayId;
520         mWindowState = state;
521     }
522 
dispatchWallpaperVisibilityChanged(boolean visible, int displayId)523     private void dispatchWallpaperVisibilityChanged(boolean visible, int displayId) {
524         for (NavbarTaskbarStateUpdater listener : mStateListeners) {
525             listener.updateWallpaperVisibility(visible, displayId);
526         }
527     }
528 
dispatchRotationChanged(int rotation)529     private void dispatchRotationChanged(int rotation) {
530         for (NavbarTaskbarStateUpdater listener : mStateListeners) {
531             listener.updateRotationWatcherState(rotation);
532         }
533     }
534 
getCurrentSysuiState()535     public CurrentSysuiState getCurrentSysuiState() {
536         return new CurrentSysuiState();
537     }
538 
539     /**
540      * Callbacks will get fired once immediately after registering via
541      * {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)}
542      */
543     public interface NavbarTaskbarStateUpdater {
updateAccessibilityServicesState()544         void updateAccessibilityServicesState();
updateAssistantAvailable(boolean available, boolean longPressHomeEnabled)545         void updateAssistantAvailable(boolean available, boolean longPressHomeEnabled);
updateWallpaperVisibility(boolean visible, int displayId)546         default void updateWallpaperVisibility(boolean visible, int displayId) {}
updateRotationWatcherState(int rotation)547         default void updateRotationWatcherState(int rotation) {}
548     }
549 
550     /** Data class to help Taskbar/Navbar initiate state correctly when switching between the two.*/
551     public class CurrentSysuiState {
552         public final int mWindowStateDisplayId;
553         public final @WindowVisibleState int mWindowState;
554 
CurrentSysuiState()555         public CurrentSysuiState() {
556             mWindowStateDisplayId = NavBarHelper.this.mWindowStateDisplayId;
557             mWindowState = NavBarHelper.this.mWindowState;
558         }
559     }
560 
transitionMode(boolean isTransient, int appearance)561     static @TransitionMode int transitionMode(boolean isTransient, int appearance) {
562         final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS;
563         if (isTransient) {
564             return MODE_SEMI_TRANSPARENT;
565         } else if ((appearance & lightsOutOpaque) == lightsOutOpaque) {
566             return MODE_LIGHTS_OUT;
567         } else if ((appearance & APPEARANCE_LOW_PROFILE_BARS) != 0) {
568             return MODE_LIGHTS_OUT_TRANSPARENT;
569         } else if ((appearance & APPEARANCE_OPAQUE_NAVIGATION_BARS) != 0) {
570             return MODE_OPAQUE;
571         } else if ((appearance & APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS) != 0) {
572             return MODE_SEMI_TRANSPARENT;
573         } else {
574             return MODE_TRANSPARENT;
575         }
576     }
577 
578     @Override
dump(@onNull PrintWriter pw, @NonNull String[] args)579     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
580         pw.println("NavbarTaskbarFriendster");
581         pw.println("  longPressHomeEnabled=" + mLongPressHomeEnabled);
582         pw.println("  mAssistantTouchGestureEnabled=" + mAssistantTouchGestureEnabled);
583         pw.println("  mAssistantAvailable=" + mAssistantAvailable);
584         pw.println("  mNavBarMode=" + mNavBarMode);
585     }
586 }
587