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.util.Log; 33 import android.view.Gravity; 34 import android.view.View; 35 import android.view.ViewGroup; 36 import android.view.WindowManager; 37 import android.view.WindowManager.LayoutParams; 38 39 import com.android.keyguard.R; 40 import com.android.systemui.Dumpable; 41 import com.android.systemui.keyguard.KeyguardViewMediator; 42 import com.android.systemui.statusbar.RemoteInputController; 43 import com.android.systemui.statusbar.StatusBarState; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 import java.lang.reflect.Field; 48 49 /** 50 * Encapsulates all logic for the status bar window state management. 51 */ 52 public class StatusBarWindowManager implements RemoteInputController.Callback, Dumpable { 53 54 private static final String TAG = "StatusBarWindowManager"; 55 56 private final Context mContext; 57 private final WindowManager mWindowManager; 58 private final IActivityManager mActivityManager; 59 private final DozeParameters mDozeParameters; 60 private View mStatusBarView; 61 private WindowManager.LayoutParams mLp; 62 private WindowManager.LayoutParams mLpChanged; 63 private boolean mHasTopUi; 64 private boolean mHasTopUiChanged; 65 private int mBarHeight; 66 private final boolean mKeyguardScreenRotation; 67 private float mScreenBrightnessDoze; 68 private final State mCurrentState = new State(); 69 private OtherwisedCollapsedListener mListener; 70 StatusBarWindowManager(Context context)71 public StatusBarWindowManager(Context context) { 72 mContext = context; 73 mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 74 mActivityManager = ActivityManager.getService(); 75 mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation(); 76 mDozeParameters = DozeParameters.getInstance(mContext); 77 mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze(); 78 } 79 shouldEnableKeyguardScreenRotation()80 private boolean shouldEnableKeyguardScreenRotation() { 81 Resources res = mContext.getResources(); 82 return SystemProperties.getBoolean("lockscreen.rot_override", false) 83 || res.getBoolean(R.bool.config_enableLockScreenRotation); 84 } 85 86 /** 87 * Adds the status bar view to the window manager. 88 * 89 * @param statusBarView The view to add. 90 * @param barHeight The height of the status bar in collapsed state. 91 */ add(View statusBarView, int barHeight)92 public void add(View statusBarView, int barHeight) { 93 94 // Now that the status bar window encompasses the sliding panel and its 95 // translucent backdrop, the entire thing is made TRANSLUCENT and is 96 // hardware-accelerated. 97 mLp = new WindowManager.LayoutParams( 98 ViewGroup.LayoutParams.MATCH_PARENT, 99 barHeight, 100 WindowManager.LayoutParams.TYPE_STATUS_BAR, 101 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 102 | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING 103 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 104 | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH 105 | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, 106 PixelFormat.TRANSLUCENT); 107 mLp.token = new Binder(); 108 mLp.gravity = Gravity.TOP; 109 mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 110 mLp.setTitle("StatusBar"); 111 mLp.packageName = mContext.getPackageName(); 112 mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 113 mStatusBarView = statusBarView; 114 mBarHeight = barHeight; 115 mWindowManager.addView(mStatusBarView, mLp); 116 mLpChanged = new WindowManager.LayoutParams(); 117 mLpChanged.copyFrom(mLp); 118 } 119 setDozeScreenBrightness(int value)120 public void setDozeScreenBrightness(int value) { 121 mScreenBrightnessDoze = value / 255f; 122 } 123 setKeyguardDark(boolean dark)124 public void setKeyguardDark(boolean dark) { 125 int vis = mStatusBarView.getSystemUiVisibility(); 126 if (dark) { 127 vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 128 vis = vis | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 129 } else { 130 vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 131 vis = vis & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 132 } 133 mStatusBarView.setSystemUiVisibility(vis); 134 } 135 applyKeyguardFlags(State state)136 private void applyKeyguardFlags(State state) { 137 if (state.keyguardShowing) { 138 mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 139 } else { 140 mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 141 } 142 143 final boolean scrimsOccludingWallpaper = 144 state.scrimsVisibility == ScrimController.VISIBILITY_FULLY_OPAQUE; 145 final boolean keyguardOrAod = state.keyguardShowing 146 || (state.dozing && mDozeParameters.getAlwaysOn()); 147 if (keyguardOrAod && !state.backdropShowing && !scrimsOccludingWallpaper) { 148 mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 149 } else { 150 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 151 } 152 } 153 adjustScreenOrientation(State state)154 private void adjustScreenOrientation(State state) { 155 if (state.isKeyguardShowingAndNotOccluded() || state.dozing) { 156 if (mKeyguardScreenRotation) { 157 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_USER; 158 } else { 159 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 160 } 161 } else { 162 mLpChanged.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 163 } 164 } 165 applyFocusableFlag(State state)166 private void applyFocusableFlag(State state) { 167 boolean panelFocusable = state.statusBarFocusable && state.panelExpanded; 168 if (state.bouncerShowing && (state.keyguardOccluded || state.keyguardNeedsInput) 169 || ENABLE_REMOTE_INPUT && state.remoteInputActive) { 170 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 171 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 172 } else if (state.isKeyguardShowingAndNotOccluded() || panelFocusable) { 173 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 174 mLpChanged.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 175 } else { 176 mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 177 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 178 } 179 180 mLpChanged.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 181 } 182 applyHeight(State state)183 private void applyHeight(State state) { 184 boolean expanded = isExpanded(state); 185 if (state.forcePluginOpen) { 186 mListener.setWouldOtherwiseCollapse(expanded); 187 expanded = true; 188 } 189 if (expanded) { 190 mLpChanged.height = ViewGroup.LayoutParams.MATCH_PARENT; 191 } else { 192 mLpChanged.height = mBarHeight; 193 } 194 } 195 isExpanded(State state)196 private boolean isExpanded(State state) { 197 return !state.forceCollapsed && (state.isKeyguardShowingAndNotOccluded() 198 || state.panelVisible || state.keyguardFadingAway || state.bouncerShowing 199 || state.headsUpShowing 200 || state.scrimsVisibility != ScrimController.VISIBILITY_FULLY_TRANSPARENT); 201 } 202 applyFitsSystemWindows(State state)203 private void applyFitsSystemWindows(State state) { 204 boolean fitsSystemWindows = !state.isKeyguardShowingAndNotOccluded(); 205 if (mStatusBarView.getFitsSystemWindows() != fitsSystemWindows) { 206 mStatusBarView.setFitsSystemWindows(fitsSystemWindows); 207 mStatusBarView.requestApplyInsets(); 208 } 209 } 210 applyUserActivityTimeout(State state)211 private void applyUserActivityTimeout(State state) { 212 if (state.isKeyguardShowingAndNotOccluded() 213 && state.statusBarState == StatusBarState.KEYGUARD 214 && !state.qsExpanded) { 215 mLpChanged.userActivityTimeout = KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS; 216 } else { 217 mLpChanged.userActivityTimeout = -1; 218 } 219 } 220 applyInputFeatures(State state)221 private void applyInputFeatures(State state) { 222 if (state.isKeyguardShowingAndNotOccluded() 223 && state.statusBarState == StatusBarState.KEYGUARD 224 && !state.qsExpanded && !state.forceUserActivity) { 225 mLpChanged.inputFeatures |= 226 WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; 227 } else { 228 mLpChanged.inputFeatures &= 229 ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY; 230 } 231 } 232 apply(State state)233 private void apply(State state) { 234 applyKeyguardFlags(state); 235 applyForceStatusBarVisibleFlag(state); 236 applyFocusableFlag(state); 237 adjustScreenOrientation(state); 238 applyHeight(state); 239 applyUserActivityTimeout(state); 240 applyInputFeatures(state); 241 applyFitsSystemWindows(state); 242 applyModalFlag(state); 243 applyBrightness(state); 244 applyHasTopUi(state); 245 applySleepToken(state); 246 if (mLp.copyFrom(mLpChanged) != 0) { 247 mWindowManager.updateViewLayout(mStatusBarView, mLp); 248 } 249 if (mHasTopUi != mHasTopUiChanged) { 250 try { 251 mActivityManager.setHasTopUi(mHasTopUiChanged); 252 } catch (RemoteException e) { 253 Log.e(TAG, "Failed to call setHasTopUi", e); 254 } 255 mHasTopUi = mHasTopUiChanged; 256 } 257 } 258 applyForceStatusBarVisibleFlag(State state)259 private void applyForceStatusBarVisibleFlag(State state) { 260 if (state.forceStatusBarVisible) { 261 mLpChanged.privateFlags |= WindowManager 262 .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; 263 } else { 264 mLpChanged.privateFlags &= ~WindowManager 265 .LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; 266 } 267 } 268 applyModalFlag(State state)269 private void applyModalFlag(State state) { 270 if (state.headsUpShowing) { 271 mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 272 } else { 273 mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; 274 } 275 } 276 applyBrightness(State state)277 private void applyBrightness(State state) { 278 if (state.forceDozeBrightness) { 279 mLpChanged.screenBrightness = mScreenBrightnessDoze; 280 } else { 281 mLpChanged.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE; 282 } 283 } 284 applyHasTopUi(State state)285 private void applyHasTopUi(State state) { 286 mHasTopUiChanged = isExpanded(state); 287 } 288 applySleepToken(State state)289 private void applySleepToken(State state) { 290 if (state.dozing) { 291 mLpChanged.privateFlags |= LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN; 292 } else { 293 mLpChanged.privateFlags &= ~LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN; 294 } 295 } 296 setKeyguardShowing(boolean showing)297 public void setKeyguardShowing(boolean showing) { 298 mCurrentState.keyguardShowing = showing; 299 apply(mCurrentState); 300 } 301 setKeyguardOccluded(boolean occluded)302 public void setKeyguardOccluded(boolean occluded) { 303 mCurrentState.keyguardOccluded = occluded; 304 apply(mCurrentState); 305 } 306 setKeyguardNeedsInput(boolean needsInput)307 public void setKeyguardNeedsInput(boolean needsInput) { 308 mCurrentState.keyguardNeedsInput = needsInput; 309 apply(mCurrentState); 310 } 311 setPanelVisible(boolean visible)312 public void setPanelVisible(boolean visible) { 313 mCurrentState.panelVisible = visible; 314 mCurrentState.statusBarFocusable = visible; 315 apply(mCurrentState); 316 } 317 setStatusBarFocusable(boolean focusable)318 public void setStatusBarFocusable(boolean focusable) { 319 mCurrentState.statusBarFocusable = focusable; 320 apply(mCurrentState); 321 } 322 setBouncerShowing(boolean showing)323 public void setBouncerShowing(boolean showing) { 324 mCurrentState.bouncerShowing = showing; 325 apply(mCurrentState); 326 } 327 setBackdropShowing(boolean showing)328 public void setBackdropShowing(boolean showing) { 329 mCurrentState.backdropShowing = showing; 330 apply(mCurrentState); 331 } 332 setKeyguardFadingAway(boolean keyguardFadingAway)333 public void setKeyguardFadingAway(boolean keyguardFadingAway) { 334 mCurrentState.keyguardFadingAway = keyguardFadingAway; 335 apply(mCurrentState); 336 } 337 setQsExpanded(boolean expanded)338 public void setQsExpanded(boolean expanded) { 339 mCurrentState.qsExpanded = expanded; 340 apply(mCurrentState); 341 } 342 setForceUserActivity(boolean forceUserActivity)343 public void setForceUserActivity(boolean forceUserActivity) { 344 mCurrentState.forceUserActivity = forceUserActivity; 345 apply(mCurrentState); 346 } 347 setScrimsVisibility(int scrimsVisibility)348 public void setScrimsVisibility(int scrimsVisibility) { 349 mCurrentState.scrimsVisibility = scrimsVisibility; 350 apply(mCurrentState); 351 } 352 setHeadsUpShowing(boolean showing)353 public void setHeadsUpShowing(boolean showing) { 354 mCurrentState.headsUpShowing = showing; 355 apply(mCurrentState); 356 } 357 setWallpaperSupportsAmbientMode(boolean supportsAmbientMode)358 public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) { 359 mCurrentState.wallpaperSupportsAmbientMode = supportsAmbientMode; 360 apply(mCurrentState); 361 } 362 363 /** 364 * @param state The {@link StatusBarState} of the status bar. 365 */ setStatusBarState(int state)366 public void setStatusBarState(int state) { 367 mCurrentState.statusBarState = state; 368 apply(mCurrentState); 369 } 370 setForceStatusBarVisible(boolean forceStatusBarVisible)371 public void setForceStatusBarVisible(boolean forceStatusBarVisible) { 372 mCurrentState.forceStatusBarVisible = forceStatusBarVisible; 373 apply(mCurrentState); 374 } 375 376 /** 377 * Force the window to be collapsed, even if it should theoretically be expanded. 378 * Used for when a heads-up comes in but we still need to wait for the touchable regions to 379 * be computed. 380 */ setForceWindowCollapsed(boolean force)381 public void setForceWindowCollapsed(boolean force) { 382 mCurrentState.forceCollapsed = force; 383 apply(mCurrentState); 384 } 385 setPanelExpanded(boolean isExpanded)386 public void setPanelExpanded(boolean isExpanded) { 387 mCurrentState.panelExpanded = isExpanded; 388 apply(mCurrentState); 389 } 390 391 @Override onRemoteInputActive(boolean remoteInputActive)392 public void onRemoteInputActive(boolean remoteInputActive) { 393 mCurrentState.remoteInputActive = remoteInputActive; 394 apply(mCurrentState); 395 } 396 397 /** 398 * Set whether the screen brightness is forced to the value we use for doze mode by the status 399 * bar window. 400 */ setForceDozeBrightness(boolean forceDozeBrightness)401 public void setForceDozeBrightness(boolean forceDozeBrightness) { 402 mCurrentState.forceDozeBrightness = forceDozeBrightness; 403 apply(mCurrentState); 404 } 405 setDozing(boolean dozing)406 public void setDozing(boolean dozing) { 407 mCurrentState.dozing = dozing; 408 apply(mCurrentState); 409 } 410 setBarHeight(int barHeight)411 public void setBarHeight(int barHeight) { 412 mBarHeight = barHeight; 413 apply(mCurrentState); 414 } 415 setForcePluginOpen(boolean forcePluginOpen)416 public void setForcePluginOpen(boolean forcePluginOpen) { 417 mCurrentState.forcePluginOpen = forcePluginOpen; 418 apply(mCurrentState); 419 } 420 setStateListener(OtherwisedCollapsedListener listener)421 public void setStateListener(OtherwisedCollapsedListener listener) { 422 mListener = listener; 423 } 424 dump(FileDescriptor fd, PrintWriter pw, String[] args)425 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 426 pw.println("StatusBarWindowManager state:"); 427 pw.println(mCurrentState); 428 } 429 isShowingWallpaper()430 public boolean isShowingWallpaper() { 431 return !mCurrentState.backdropShowing; 432 } 433 434 private static class State { 435 boolean keyguardShowing; 436 boolean keyguardOccluded; 437 boolean keyguardNeedsInput; 438 boolean panelVisible; 439 boolean panelExpanded; 440 boolean statusBarFocusable; 441 boolean bouncerShowing; 442 boolean keyguardFadingAway; 443 boolean qsExpanded; 444 boolean headsUpShowing; 445 boolean forceStatusBarVisible; 446 boolean forceCollapsed; 447 boolean forceDozeBrightness; 448 boolean forceUserActivity; 449 boolean backdropShowing; 450 boolean wallpaperSupportsAmbientMode; 451 452 /** 453 * The {@link StatusBar} state from the status bar. 454 */ 455 int statusBarState; 456 457 boolean remoteInputActive; 458 boolean forcePluginOpen; 459 boolean dozing; 460 int scrimsVisibility; 461 isKeyguardShowingAndNotOccluded()462 private boolean isKeyguardShowingAndNotOccluded() { 463 return keyguardShowing && !keyguardOccluded; 464 } 465 466 @Override toString()467 public String toString() { 468 StringBuilder result = new StringBuilder(); 469 String newLine = "\n"; 470 result.append("Window State {"); 471 result.append(newLine); 472 473 Field[] fields = this.getClass().getDeclaredFields(); 474 475 // Print field names paired with their values 476 for (Field field : fields) { 477 result.append(" "); 478 try { 479 result.append(field.getName()); 480 result.append(": "); 481 //requires access to private field: 482 result.append(field.get(this)); 483 } catch (IllegalAccessException ex) { 484 } 485 result.append(newLine); 486 } 487 result.append("}"); 488 489 return result.toString(); 490 } 491 } 492 493 /** 494 * Custom listener to pipe data back to plugins about whether or not the status bar would be 495 * collapsed if not for the plugin. 496 * TODO: Find cleaner way to do this. 497 */ 498 public interface OtherwisedCollapsedListener { setWouldOtherwiseCollapse(boolean otherwiseCollapse)499 void setWouldOtherwiseCollapse(boolean otherwiseCollapse); 500 } 501 } 502