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