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