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