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