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