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