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