• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
20 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
21 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
22 
23 import static com.android.systemui.DejankUtils.whitelistIpcs;
24 import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
25 
26 import android.app.IActivityManager;
27 import android.content.Context;
28 import android.content.pm.ActivityInfo;
29 import android.content.res.Resources;
30 import android.graphics.PixelFormat;
31 import android.os.Binder;
32 import android.os.RemoteException;
33 import android.os.SystemProperties;
34 import android.os.Trace;
35 import android.util.Log;
36 import android.view.Display;
37 import android.view.Gravity;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.WindowManager;
41 import android.view.WindowManager.LayoutParams;
42 
43 import com.android.systemui.Dumpable;
44 import com.android.systemui.R;
45 import com.android.systemui.colorextraction.SysuiColorExtractor;
46 import com.android.systemui.dump.DumpManager;
47 import com.android.systemui.keyguard.KeyguardViewMediator;
48 import com.android.systemui.plugins.statusbar.StatusBarStateController;
49 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
50 import com.android.systemui.statusbar.RemoteInputController.Callback;
51 import com.android.systemui.statusbar.StatusBarState;
52 import com.android.systemui.statusbar.SysuiStatusBarStateController;
53 import com.android.systemui.statusbar.policy.ConfigurationController;
54 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
55 
56 import com.google.android.collect.Lists;
57 
58 import java.io.FileDescriptor;
59 import java.io.PrintWriter;
60 import java.lang.ref.WeakReference;
61 import java.lang.reflect.Field;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.HashSet;
65 import java.util.Set;
66 import java.util.function.Consumer;
67 
68 import javax.inject.Inject;
69 import javax.inject.Singleton;
70 
71 /**
72  * Encapsulates all logic for the notification shade window state management.
73  */
74 @Singleton
75 public class NotificationShadeWindowController implements Callback, Dumpable,
76         ConfigurationListener {
77 
78     private static final String TAG = "NotificationShadeWindowController";
79     private static final boolean DEBUG = false;
80 
81     private final Context mContext;
82     private final WindowManager mWindowManager;
83     private final IActivityManager mActivityManager;
84     private final DozeParameters mDozeParameters;
85     private final LayoutParams mLpChanged;
86     private final boolean mKeyguardScreenRotation;
87     private final long mLockScreenDisplayTimeout;
88     private final Display.Mode mKeyguardDisplayMode;
89     private final KeyguardViewMediator mKeyguardViewMediator;
90     private final KeyguardBypassController mKeyguardBypassController;
91     private ViewGroup mNotificationShadeView;
92     private LayoutParams mLp;
93     private boolean mHasTopUi;
94     private boolean mHasTopUiChanged;
95     private float mScreenBrightnessDoze;
96     private final State mCurrentState = new State();
97     private OtherwisedCollapsedListener mListener;
98     private ForcePluginOpenListener mForcePluginOpenListener;
99     private Consumer<Integer> mScrimsVisibilityListener;
100     private final ArrayList<WeakReference<StatusBarWindowCallback>>
101             mCallbacks = Lists.newArrayList();
102 
103     private final SysuiColorExtractor mColorExtractor;
104 
105     @Inject
NotificationShadeWindowController(Context context, WindowManager windowManager, IActivityManager activityManager, DozeParameters dozeParameters, StatusBarStateController statusBarStateController, ConfigurationController configurationController, KeyguardViewMediator keyguardViewMediator, KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor, DumpManager dumpManager)106     public NotificationShadeWindowController(Context context, WindowManager windowManager,
107             IActivityManager activityManager, DozeParameters dozeParameters,
108             StatusBarStateController statusBarStateController,
109             ConfigurationController configurationController,
110             KeyguardViewMediator keyguardViewMediator,
111             KeyguardBypassController keyguardBypassController, SysuiColorExtractor colorExtractor,
112             DumpManager dumpManager) {
113         mContext = context;
114         mWindowManager = windowManager;
115         mActivityManager = activityManager;
116         mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
117         mDozeParameters = dozeParameters;
118         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
119         mLpChanged = new LayoutParams();
120         mKeyguardViewMediator = keyguardViewMediator;
121         mKeyguardBypassController = keyguardBypassController;
122         mColorExtractor = colorExtractor;
123         dumpManager.registerDumpable(getClass().getName(), this);
124 
125         mLockScreenDisplayTimeout = context.getResources()
126                 .getInteger(R.integer.config_lockScreenDisplayTimeout);
127         ((SysuiStatusBarStateController) statusBarStateController)
128                 .addCallback(mStateListener,
129                         SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
130         configurationController.addCallback(this);
131 
132         Display.Mode[] supportedModes = context.getDisplay().getSupportedModes();
133         Display.Mode currentMode = context.getDisplay().getMode();
134         // Running on the highest frame rate available can be expensive.
135         // Let's specify a preferred refresh rate, and allow higher FPS only when we
136         // know that we're not falsing (because we unlocked.)
137         int keyguardRefreshRate = context.getResources()
138                 .getInteger(R.integer.config_keyguardRefreshRate);
139         // Find supported display mode with the same resolution and requested refresh rate.
140         mKeyguardDisplayMode = Arrays.stream(supportedModes).filter(mode ->
141                 (int) mode.getRefreshRate() == keyguardRefreshRate
142                         && mode.getPhysicalWidth() == currentMode.getPhysicalWidth()
143                         && mode.getPhysicalHeight() == currentMode.getPhysicalHeight())
144                 .findFirst().orElse(null);
145     }
146 
147     /**
148      * Register to receive notifications about status bar window state changes.
149      */
registerCallback(StatusBarWindowCallback callback)150     public void registerCallback(StatusBarWindowCallback callback) {
151         // Prevent adding duplicate callbacks
152         for (int i = 0; i < mCallbacks.size(); i++) {
153             if (mCallbacks.get(i).get() == callback) {
154                 return;
155             }
156         }
157         mCallbacks.add(new WeakReference<StatusBarWindowCallback>(callback));
158     }
159 
160     /**
161      * Register a listener to monitor scrims visibility
162      * @param listener A listener to monitor scrims visibility
163      */
setScrimsVisibilityListener(Consumer<Integer> listener)164     public void setScrimsVisibilityListener(Consumer<Integer> listener) {
165         if (listener != null && mScrimsVisibilityListener != listener) {
166             mScrimsVisibilityListener = listener;
167         }
168     }
169 
shouldEnableKeyguardScreenRotation()170     private boolean shouldEnableKeyguardScreenRotation() {
171         Resources res = mContext.getResources();
172         return SystemProperties.getBoolean("lockscreen.rot_override", false)
173                 || res.getBoolean(R.bool.config_enableLockScreenRotation);
174     }
175 
176     /**
177      * Adds the notification shade view to the window manager.
178      */
attach()179     public void attach() {
180         // Now that the notification shade encompasses the sliding panel and its
181         // translucent backdrop, the entire thing is made TRANSLUCENT and is
182         // hardware-accelerated.
183         mLp = new LayoutParams(
184                 ViewGroup.LayoutParams.MATCH_PARENT,
185                 ViewGroup.LayoutParams.MATCH_PARENT,
186                 LayoutParams.TYPE_NOTIFICATION_SHADE,
187                 LayoutParams.FLAG_NOT_FOCUSABLE
188                         | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
189                         | LayoutParams.FLAG_SPLIT_TOUCH
190                         | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
191                         | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
192                 PixelFormat.TRANSLUCENT);
193         mLp.token = new Binder();
194         mLp.gravity = Gravity.TOP;
195         mLp.setFitInsetsTypes(0 /* types */);
196         mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
197         mLp.setTitle("NotificationShade");
198         mLp.packageName = mContext.getPackageName();
199         mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
200 
201         // We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in
202         // window manager which disables the transient show behavior.
203         // TODO: Clean this up once that behavior moves into the Shell.
204         mLp.privateFlags |= PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
205         mLp.insetsFlags.behavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
206 
207         mWindowManager.addView(mNotificationShadeView, mLp);
208         mLpChanged.copyFrom(mLp);
209         onThemeChanged();
210 
211         // Make the state consistent with KeyguardViewMediator#setupLocked during initialization.
212         if (mKeyguardViewMediator.isShowingAndNotOccluded()) {
213             setKeyguardShowing(true);
214         }
215     }
216 
setNotificationShadeView(ViewGroup view)217     public void setNotificationShadeView(ViewGroup view) {
218         mNotificationShadeView = view;
219     }
220 
getNotificationShadeView()221     public ViewGroup getNotificationShadeView() {
222         return mNotificationShadeView;
223     }
224 
setDozeScreenBrightness(int value)225     public void setDozeScreenBrightness(int value) {
226         mScreenBrightnessDoze = value / 255f;
227     }
228 
setKeyguardDark(boolean dark)229     private void setKeyguardDark(boolean dark) {
230         int vis = mNotificationShadeView.getSystemUiVisibility();
231         if (dark) {
232             vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
233             vis = vis | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
234         } else {
235             vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
236             vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
237         }
238         mNotificationShadeView.setSystemUiVisibility(vis);
239     }
240 
applyKeyguardFlags(State state)241     private void applyKeyguardFlags(State state) {
242         final boolean scrimsOccludingWallpaper =
243                 state.mScrimsVisibility == ScrimController.OPAQUE;
244         final boolean keyguardOrAod = state.mKeyguardShowing
245                 || (state.mDozing && mDozeParameters.getAlwaysOn());
246         if (keyguardOrAod && !state.mBackdropShowing && !scrimsOccludingWallpaper) {
247             mLpChanged.flags |= LayoutParams.FLAG_SHOW_WALLPAPER;
248         } else {
249             mLpChanged.flags &= ~LayoutParams.FLAG_SHOW_WALLPAPER;
250         }
251 
252         if (state.mDozing) {
253             mLpChanged.privateFlags |= LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
254         } else {
255             mLpChanged.privateFlags &= ~LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
256         }
257 
258         if (mKeyguardDisplayMode != null) {
259             boolean bypassOnKeyguard = mKeyguardBypassController.getBypassEnabled()
260                     && state.mStatusBarState == StatusBarState.KEYGUARD
261                     && !state.mKeyguardFadingAway && !state.mKeyguardGoingAway;
262             if (state.mDozing || bypassOnKeyguard) {
263                 mLpChanged.preferredDisplayModeId = mKeyguardDisplayMode.getModeId();
264             } else {
265                 mLpChanged.preferredDisplayModeId = 0;
266             }
267             Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
268         }
269     }
270 
adjustScreenOrientation(State state)271     private void adjustScreenOrientation(State state) {
272         if (state.isKeyguardShowingAndNotOccluded() || state.mDozing) {
273             if (mKeyguardScreenRotation) {
274                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;
275             } else {
276                 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
277             }
278         } else {
279             mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
280         }
281     }
282 
applyFocusableFlag(State state)283     private void applyFocusableFlag(State state) {
284         boolean panelFocusable = state.mNotificationShadeFocusable && state.mPanelExpanded;
285         if (state.mBouncerShowing && (state.mKeyguardOccluded || state.mKeyguardNeedsInput)
286                 || ENABLE_REMOTE_INPUT && state.mRemoteInputActive) {
287             mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
288             mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
289         } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) {
290             mLpChanged.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
291             // Make sure to remove FLAG_ALT_FOCUSABLE_IM when keyguard needs input.
292             if (state.mKeyguardNeedsInput && state.isKeyguardShowingAndNotOccluded()) {
293                 mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
294             } else {
295                 mLpChanged.flags |= LayoutParams.FLAG_ALT_FOCUSABLE_IM;
296             }
297         } else {
298             mLpChanged.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
299             mLpChanged.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
300         }
301 
302         mLpChanged.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
303     }
304 
applyForceShowNavigationFlag(State state)305     private void applyForceShowNavigationFlag(State state) {
306         if (state.mPanelExpanded || state.mBouncerShowing
307                 || ENABLE_REMOTE_INPUT && state.mRemoteInputActive) {
308             mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
309         } else {
310             mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
311         }
312     }
313 
applyVisibility(State state)314     private void applyVisibility(State state) {
315         boolean visible = isExpanded(state);
316         if (state.mForcePluginOpen) {
317             if (mListener != null) {
318                 mListener.setWouldOtherwiseCollapse(visible);
319             }
320             visible = true;
321         }
322         if (visible) {
323             mNotificationShadeView.setVisibility(View.VISIBLE);
324         } else {
325             mNotificationShadeView.setVisibility(View.INVISIBLE);
326         }
327     }
328 
isExpanded(State state)329     private boolean isExpanded(State state) {
330         return !state.mForceCollapsed && (state.isKeyguardShowingAndNotOccluded()
331                 || state.mPanelVisible || state.mKeyguardFadingAway || state.mBouncerShowing
332                 || state.mHeadsUpShowing
333                 || state.mScrimsVisibility != ScrimController.TRANSPARENT)
334                 || state.mBackgroundBlurRadius > 0
335                 || state.mLaunchingActivity;
336     }
337 
applyFitsSystemWindows(State state)338     private void applyFitsSystemWindows(State state) {
339         boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded();
340         if (mNotificationShadeView != null
341                 && mNotificationShadeView.getFitsSystemWindows() != fitsSystemWindows) {
342             mNotificationShadeView.setFitsSystemWindows(fitsSystemWindows);
343             mNotificationShadeView.requestApplyInsets();
344         }
345     }
346 
applyUserActivityTimeout(State state)347     private void applyUserActivityTimeout(State state) {
348         if (state.isKeyguardShowingAndNotOccluded()
349                 && state.mStatusBarState == StatusBarState.KEYGUARD
350                 && !state.mQsExpanded) {
351             mLpChanged.userActivityTimeout = state.mBouncerShowing
352                     ? KeyguardViewMediator.AWAKE_INTERVAL_BOUNCER_MS : mLockScreenDisplayTimeout;
353         } else {
354             mLpChanged.userActivityTimeout = -1;
355         }
356     }
357 
applyInputFeatures(State state)358     private void applyInputFeatures(State state) {
359         if (state.isKeyguardShowingAndNotOccluded()
360                 && state.mStatusBarState == StatusBarState.KEYGUARD
361                 && !state.mQsExpanded && !state.mForceUserActivity) {
362             mLpChanged.inputFeatures |=
363                     LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
364         } else {
365             mLpChanged.inputFeatures &=
366                     ~LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
367         }
368     }
369 
applyStatusBarColorSpaceAgnosticFlag(State state)370     private void applyStatusBarColorSpaceAgnosticFlag(State state) {
371         if (!isExpanded(state)) {
372             mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
373         } else {
374             mLpChanged.privateFlags &=
375                     ~LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
376         }
377     }
378 
apply(State state)379     private void apply(State state) {
380         applyKeyguardFlags(state);
381         applyFocusableFlag(state);
382         applyForceShowNavigationFlag(state);
383         adjustScreenOrientation(state);
384         applyVisibility(state);
385         applyUserActivityTimeout(state);
386         applyInputFeatures(state);
387         applyFitsSystemWindows(state);
388         applyModalFlag(state);
389         applyBrightness(state);
390         applyHasTopUi(state);
391         applyNotTouchable(state);
392         applyStatusBarColorSpaceAgnosticFlag(state);
393         if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
394             mWindowManager.updateViewLayout(mNotificationShadeView, mLp);
395         }
396         if (mHasTopUi != mHasTopUiChanged) {
397             whitelistIpcs(() -> {
398                 try {
399                     mActivityManager.setHasTopUi(mHasTopUiChanged);
400                 } catch (RemoteException e) {
401                     Log.e(TAG, "Failed to call setHasTopUi", e);
402                 }
403                 mHasTopUi = mHasTopUiChanged;
404             });
405         }
406         notifyStateChangedCallbacks();
407     }
408 
notifyStateChangedCallbacks()409     public void notifyStateChangedCallbacks() {
410         for (int i = 0; i < mCallbacks.size(); i++) {
411             StatusBarWindowCallback cb = mCallbacks.get(i).get();
412             if (cb != null) {
413                 cb.onStateChanged(mCurrentState.mKeyguardShowing,
414                         mCurrentState.mKeyguardOccluded,
415                         mCurrentState.mBouncerShowing);
416             }
417         }
418     }
419 
applyModalFlag(State state)420     private void applyModalFlag(State state) {
421         if (state.mHeadsUpShowing) {
422             mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCH_MODAL;
423         } else {
424             mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCH_MODAL;
425         }
426     }
427 
applyBrightness(State state)428     private void applyBrightness(State state) {
429         if (state.mForceDozeBrightness) {
430             mLpChanged.screenBrightness = mScreenBrightnessDoze;
431         } else {
432             mLpChanged.screenBrightness = LayoutParams.BRIGHTNESS_OVERRIDE_NONE;
433         }
434     }
435 
applyHasTopUi(State state)436     private void applyHasTopUi(State state) {
437         mHasTopUiChanged = !state.mComponentsForcingTopUi.isEmpty() || isExpanded(state);
438     }
439 
applyNotTouchable(State state)440     private void applyNotTouchable(State state) {
441         if (state.mNotTouchable) {
442             mLpChanged.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
443         } else {
444             mLpChanged.flags &= ~LayoutParams.FLAG_NOT_TOUCHABLE;
445         }
446     }
447 
setKeyguardShowing(boolean showing)448     public void setKeyguardShowing(boolean showing) {
449         mCurrentState.mKeyguardShowing = showing;
450         apply(mCurrentState);
451     }
452 
setKeyguardOccluded(boolean occluded)453     public void setKeyguardOccluded(boolean occluded) {
454         mCurrentState.mKeyguardOccluded = occluded;
455         apply(mCurrentState);
456     }
457 
setKeyguardNeedsInput(boolean needsInput)458     public void setKeyguardNeedsInput(boolean needsInput) {
459         mCurrentState.mKeyguardNeedsInput = needsInput;
460         apply(mCurrentState);
461     }
462 
setPanelVisible(boolean visible)463     public void setPanelVisible(boolean visible) {
464         mCurrentState.mPanelVisible = visible;
465         mCurrentState.mNotificationShadeFocusable = visible;
466         apply(mCurrentState);
467     }
468 
setNotificationShadeFocusable(boolean focusable)469     public void setNotificationShadeFocusable(boolean focusable) {
470         mCurrentState.mNotificationShadeFocusable = focusable;
471         apply(mCurrentState);
472     }
473 
setBouncerShowing(boolean showing)474     public void setBouncerShowing(boolean showing) {
475         mCurrentState.mBouncerShowing = showing;
476         apply(mCurrentState);
477     }
478 
setBackdropShowing(boolean showing)479     public void setBackdropShowing(boolean showing) {
480         mCurrentState.mBackdropShowing = showing;
481         apply(mCurrentState);
482     }
483 
setKeyguardFadingAway(boolean keyguardFadingAway)484     public void setKeyguardFadingAway(boolean keyguardFadingAway) {
485         mCurrentState.mKeyguardFadingAway = keyguardFadingAway;
486         apply(mCurrentState);
487     }
488 
setQsExpanded(boolean expanded)489     public void setQsExpanded(boolean expanded) {
490         mCurrentState.mQsExpanded = expanded;
491         apply(mCurrentState);
492     }
493 
setForceUserActivity(boolean forceUserActivity)494     public void setForceUserActivity(boolean forceUserActivity) {
495         mCurrentState.mForceUserActivity = forceUserActivity;
496         apply(mCurrentState);
497     }
498 
setLaunchingActivity(boolean launching)499     void setLaunchingActivity(boolean launching) {
500         mCurrentState.mLaunchingActivity = launching;
501         apply(mCurrentState);
502     }
503 
setScrimsVisibility(int scrimsVisibility)504     public void setScrimsVisibility(int scrimsVisibility) {
505         mCurrentState.mScrimsVisibility = scrimsVisibility;
506         apply(mCurrentState);
507         mScrimsVisibilityListener.accept(scrimsVisibility);
508     }
509 
510     /**
511      * Current blur level, controller by
512      * {@link com.android.systemui.statusbar.NotificationShadeDepthController}.
513      * @param backgroundBlurRadius Radius in pixels.
514      */
setBackgroundBlurRadius(int backgroundBlurRadius)515     public void setBackgroundBlurRadius(int backgroundBlurRadius) {
516         if (mCurrentState.mBackgroundBlurRadius == backgroundBlurRadius) {
517             return;
518         }
519         mCurrentState.mBackgroundBlurRadius = backgroundBlurRadius;
520         apply(mCurrentState);
521     }
522 
setHeadsUpShowing(boolean showing)523     public void setHeadsUpShowing(boolean showing) {
524         mCurrentState.mHeadsUpShowing = showing;
525         apply(mCurrentState);
526     }
527 
setWallpaperSupportsAmbientMode(boolean supportsAmbientMode)528     public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {
529         mCurrentState.mWallpaperSupportsAmbientMode = supportsAmbientMode;
530         apply(mCurrentState);
531     }
532 
533     /**
534      * @param state The {@link StatusBarStateController} of the status bar.
535      */
setStatusBarState(int state)536     private void setStatusBarState(int state) {
537         mCurrentState.mStatusBarState = state;
538         apply(mCurrentState);
539     }
540 
541     /**
542      * Force the window to be collapsed, even if it should theoretically be expanded.
543      * Used for when a heads-up comes in but we still need to wait for the touchable regions to
544      * be computed.
545      */
setForceWindowCollapsed(boolean force)546     public void setForceWindowCollapsed(boolean force) {
547         mCurrentState.mForceCollapsed = force;
548         apply(mCurrentState);
549     }
550 
setPanelExpanded(boolean isExpanded)551     public void setPanelExpanded(boolean isExpanded) {
552         mCurrentState.mPanelExpanded = isExpanded;
553         apply(mCurrentState);
554     }
555 
556     @Override
onRemoteInputActive(boolean remoteInputActive)557     public void onRemoteInputActive(boolean remoteInputActive) {
558         mCurrentState.mRemoteInputActive = remoteInputActive;
559         apply(mCurrentState);
560     }
561 
562     /**
563      * Set whether the screen brightness is forced to the value we use for doze mode by the status
564      * bar window.
565      */
setForceDozeBrightness(boolean forceDozeBrightness)566     public void setForceDozeBrightness(boolean forceDozeBrightness) {
567         mCurrentState.mForceDozeBrightness = forceDozeBrightness;
568         apply(mCurrentState);
569     }
570 
setDozing(boolean dozing)571     public void setDozing(boolean dozing) {
572         mCurrentState.mDozing = dozing;
573         apply(mCurrentState);
574     }
575 
setForcePluginOpen(boolean forcePluginOpen)576     public void setForcePluginOpen(boolean forcePluginOpen) {
577         mCurrentState.mForcePluginOpen = forcePluginOpen;
578         apply(mCurrentState);
579         if (mForcePluginOpenListener != null) {
580             mForcePluginOpenListener.onChange(forcePluginOpen);
581         }
582     }
583 
584     /**
585      * The forcePluginOpen state for the status bar.
586      */
getForcePluginOpen()587     public boolean getForcePluginOpen() {
588         return mCurrentState.mForcePluginOpen;
589     }
590 
setNotTouchable(boolean notTouchable)591     public void setNotTouchable(boolean notTouchable) {
592         mCurrentState.mNotTouchable = notTouchable;
593         apply(mCurrentState);
594     }
595 
596     /**
597      * Whether the status bar panel is expanded or not.
598      */
getPanelExpanded()599     public boolean getPanelExpanded() {
600         return mCurrentState.mPanelExpanded;
601     }
602 
setStateListener(OtherwisedCollapsedListener listener)603     public void setStateListener(OtherwisedCollapsedListener listener) {
604         mListener = listener;
605     }
606 
setForcePluginOpenListener(ForcePluginOpenListener listener)607     public void setForcePluginOpenListener(ForcePluginOpenListener listener) {
608         mForcePluginOpenListener = listener;
609     }
610 
dump(FileDescriptor fd, PrintWriter pw, String[] args)611     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
612         pw.println(TAG + ":");
613         pw.println("  mKeyguardDisplayMode=" + mKeyguardDisplayMode);
614         pw.println(mCurrentState);
615     }
616 
isShowingWallpaper()617     public boolean isShowingWallpaper() {
618         return !mCurrentState.mBackdropShowing;
619     }
620 
621     @Override
onThemeChanged()622     public void onThemeChanged() {
623         if (mNotificationShadeView == null) {
624             return;
625         }
626 
627         final boolean useDarkText = mColorExtractor.getNeutralColors().supportsDarkText();
628         // Make sure we have the correct navbar/statusbar colors.
629         setKeyguardDark(useDarkText);
630     }
631 
632     /**
633      * When keyguard will be dismissed but didn't start animation yet.
634      */
setKeyguardGoingAway(boolean goingAway)635     public void setKeyguardGoingAway(boolean goingAway) {
636         mCurrentState.mKeyguardGoingAway = goingAway;
637         apply(mCurrentState);
638     }
639 
640     /**
641      * SystemUI may need top-ui to avoid jank when performing animations.  After the
642      * animation is performed, the component should remove itself from the list of features that
643      * are forcing SystemUI to be top-ui.
644      */
setRequestTopUi(boolean requestTopUi, String componentTag)645     public void setRequestTopUi(boolean requestTopUi, String componentTag) {
646         if (requestTopUi) {
647             mCurrentState.mComponentsForcingTopUi.add(componentTag);
648         } else {
649             mCurrentState.mComponentsForcingTopUi.remove(componentTag);
650         }
651         apply(mCurrentState);
652     }
653 
654     private static class State {
655         boolean mKeyguardShowing;
656         boolean mKeyguardOccluded;
657         boolean mKeyguardNeedsInput;
658         boolean mPanelVisible;
659         boolean mPanelExpanded;
660         boolean mNotificationShadeFocusable;
661         boolean mBouncerShowing;
662         boolean mKeyguardFadingAway;
663         boolean mKeyguardGoingAway;
664         boolean mQsExpanded;
665         boolean mHeadsUpShowing;
666         boolean mForceCollapsed;
667         boolean mForceDozeBrightness;
668         boolean mForceUserActivity;
669         boolean mLaunchingActivity;
670         boolean mBackdropShowing;
671         boolean mWallpaperSupportsAmbientMode;
672         boolean mNotTouchable;
673         Set<String> mComponentsForcingTopUi = new HashSet<>();
674 
675         /**
676          * The {@link StatusBar} state from the status bar.
677          */
678         int mStatusBarState;
679 
680         boolean mRemoteInputActive;
681         boolean mForcePluginOpen;
682         boolean mDozing;
683         int mScrimsVisibility;
684         int mBackgroundBlurRadius;
685 
isKeyguardShowingAndNotOccluded()686         private boolean isKeyguardShowingAndNotOccluded() {
687             return mKeyguardShowing && !mKeyguardOccluded;
688         }
689 
690         @Override
toString()691         public String toString() {
692             StringBuilder result = new StringBuilder();
693             String newLine = "\n";
694             result.append("Window State {");
695             result.append(newLine);
696 
697             Field[] fields = this.getClass().getDeclaredFields();
698 
699             // Print field names paired with their values
700             for (Field field : fields) {
701                 result.append("  ");
702                 try {
703                     result.append(field.getName());
704                     result.append(": ");
705                     //requires access to private field:
706                     result.append(field.get(this));
707                 } catch (IllegalAccessException ex) {
708                 }
709                 result.append(newLine);
710             }
711             result.append("}");
712 
713             return result.toString();
714         }
715     }
716 
717     private final StateListener mStateListener = new StateListener() {
718         @Override
719         public void onStateChanged(int newState) {
720             setStatusBarState(newState);
721         }
722 
723         @Override
724         public void onDozingChanged(boolean isDozing) {
725             setDozing(isDozing);
726         }
727     };
728 
729     /**
730      * Custom listener to pipe data back to plugins about whether or not the status bar would be
731      * collapsed if not for the plugin.
732      * TODO: Find cleaner way to do this.
733      */
734     public interface OtherwisedCollapsedListener {
setWouldOtherwiseCollapse(boolean otherwiseCollapse)735         void setWouldOtherwiseCollapse(boolean otherwiseCollapse);
736     }
737 
738     /**
739      * Listener to indicate forcePluginOpen has changed
740      */
741     public interface ForcePluginOpenListener {
742         /**
743          * Called when mState.forcePluginOpen is changed
744          */
onChange(boolean forceOpen)745         void onChange(boolean forceOpen);
746     }
747 }
748