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