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