StatusBarKeyguardViewManager.java revision 31b844ba0cf418b758fbe45023d0202f208c0191
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.ComponentCallbacks2; 20import android.content.Context; 21import android.os.Bundle; 22import android.os.RemoteException; 23import android.os.SystemClock; 24import android.util.Slog; 25import android.view.KeyEvent; 26import android.view.View; 27import android.view.ViewGroup; 28import android.view.WindowManagerGlobal; 29 30import com.android.internal.policy.IKeyguardShowCallback; 31import com.android.internal.widget.LockPatternUtils; 32import com.android.keyguard.KeyguardUpdateMonitor; 33import com.android.keyguard.ViewMediatorCallback; 34 35import static com.android.keyguard.KeyguardHostView.OnDismissAction; 36 37/** 38 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back 39 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, 40 * which is in turn, reported to this class by the current 41 * {@link com.android.keyguard.KeyguardViewBase}. 42 */ 43public class StatusBarKeyguardViewManager { 44 45 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. 46 private static final long HIDE_TIMING_CORRECTION_MS = -3 * 16; 47 48 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync 49 // with the appear animations of the PIN/pattern/password views. 50 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320; 51 52 private static String TAG = "StatusBarKeyguardViewManager"; 53 54 private final Context mContext; 55 56 private LockPatternUtils mLockPatternUtils; 57 private ViewMediatorCallback mViewMediatorCallback; 58 private PhoneStatusBar mPhoneStatusBar; 59 private ScrimController mScrimController; 60 61 private ViewGroup mContainer; 62 private StatusBarWindowManager mStatusBarWindowManager; 63 64 private boolean mScreenOn = false; 65 private KeyguardBouncer mBouncer; 66 private boolean mShowing; 67 private boolean mOccluded; 68 69 private boolean mFirstUpdate = true; 70 private boolean mLastShowing; 71 private boolean mLastOccluded; 72 private boolean mLastBouncerShowing; 73 private boolean mLastBouncerDismissible; 74 private OnDismissAction mAfterKeyguardGoneAction; 75 76 public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback, 77 LockPatternUtils lockPatternUtils) { 78 mContext = context; 79 mViewMediatorCallback = callback; 80 mLockPatternUtils = lockPatternUtils; 81 } 82 83 public void registerStatusBar(PhoneStatusBar phoneStatusBar, 84 ViewGroup container, StatusBarWindowManager statusBarWindowManager, 85 ScrimController scrimController) { 86 mPhoneStatusBar = phoneStatusBar; 87 mContainer = container; 88 mStatusBarWindowManager = statusBarWindowManager; 89 mScrimController = scrimController; 90 mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils, 91 mStatusBarWindowManager, container); 92 } 93 94 /** 95 * Show the keyguard. Will handle creating and attaching to the view manager 96 * lazily. 97 */ 98 public void show(Bundle options) { 99 mShowing = true; 100 mStatusBarWindowManager.setKeyguardShowing(true); 101 reset(); 102 } 103 104 /** 105 * Shows the notification keyguard or the bouncer depending on 106 * {@link KeyguardBouncer#needsFullscreenBouncer()}. 107 */ 108 private void showBouncerOrKeyguard() { 109 if (mBouncer.needsFullscreenBouncer()) { 110 111 // The keyguard might be showing (already). So we need to hide it. 112 mPhoneStatusBar.hideKeyguard(); 113 mBouncer.show(); 114 } else { 115 mPhoneStatusBar.showKeyguard(); 116 mBouncer.hide(false /* destroyView */); 117 mBouncer.prepare(); 118 } 119 } 120 121 private void showBouncer() { 122 if (mShowing) { 123 mBouncer.show(); 124 } 125 updateStates(); 126 } 127 128 public void dismissWithAction(OnDismissAction r, boolean afterKeyguardGone) { 129 if (mShowing) { 130 if (!afterKeyguardGone) { 131 mBouncer.showWithDismissAction(r); 132 } else { 133 mBouncer.show(); 134 mAfterKeyguardGoneAction = r; 135 } 136 } 137 updateStates(); 138 } 139 140 /** 141 * Reset the state of the view. 142 */ 143 public void reset() { 144 if (mShowing) { 145 if (mOccluded) { 146 mPhoneStatusBar.hideKeyguard(); 147 mBouncer.hide(false /* destroyView */); 148 } else { 149 showBouncerOrKeyguard(); 150 } 151 updateStates(); 152 } 153 } 154 155 public void onScreenTurnedOff() { 156 mScreenOn = false; 157 mPhoneStatusBar.onScreenTurnedOff(); 158 mBouncer.onScreenTurnedOff(); 159 } 160 161 public void onScreenTurnedOn(final IKeyguardShowCallback callback) { 162 mScreenOn = true; 163 mPhoneStatusBar.onScreenTurnedOn(); 164 if (callback != null) { 165 callbackAfterDraw(callback); 166 } 167 } 168 169 private void callbackAfterDraw(final IKeyguardShowCallback callback) { 170 mContainer.post(new Runnable() { 171 @Override 172 public void run() { 173 try { 174 callback.onShown(mContainer.getWindowToken()); 175 } catch (RemoteException e) { 176 Slog.w(TAG, "Exception calling onShown():", e); 177 } 178 } 179 }); 180 } 181 182 public void verifyUnlock() { 183 dismiss(); 184 } 185 186 public void setNeedsInput(boolean needsInput) { 187 mStatusBarWindowManager.setKeyguardNeedsInput(needsInput); 188 } 189 190 public void updateUserActivityTimeout() { 191 mStatusBarWindowManager.setKeyguardUserActivityTimeout(mBouncer.getUserActivityTimeout()); 192 } 193 194 public void setOccluded(boolean occluded) { 195 if (occluded && !mOccluded && mShowing) { 196 if (mPhoneStatusBar.isInLaunchTransition()) { 197 mOccluded = true; 198 mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, 199 new Runnable() { 200 @Override 201 public void run() { 202 mStatusBarWindowManager.setKeyguardOccluded(true); 203 reset(); 204 } 205 }); 206 return; 207 } 208 } 209 mOccluded = occluded; 210 mStatusBarWindowManager.setKeyguardOccluded(occluded); 211 reset(); 212 } 213 214 public boolean isOccluded() { 215 return mOccluded; 216 } 217 218 /** 219 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the 220 * security view of the bouncer. 221 * 222 * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if 223 * no action should be run 224 */ 225 public void startPreHideAnimation(Runnable finishRunnable) { 226 if (mBouncer.isShowing()) { 227 mBouncer.startPreHideAnimation(finishRunnable); 228 } else if (finishRunnable != null) { 229 finishRunnable.run(); 230 } 231 } 232 233 /** 234 * Hides the keyguard view 235 */ 236 public void hide(long startTime, final long fadeoutDuration) { 237 mShowing = false; 238 239 long uptimeMillis = SystemClock.uptimeMillis(); 240 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); 241 242 if (mPhoneStatusBar.isInLaunchTransition() ) { 243 mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { 244 @Override 245 public void run() { 246 mStatusBarWindowManager.setKeyguardShowing(false); 247 mStatusBarWindowManager.setKeyguardFadingAway(true); 248 mBouncer.hide(true /* destroyView */); 249 updateStates(); 250 mScrimController.animateKeyguardFadingOut( 251 PhoneStatusBar.FADE_KEYGUARD_START_DELAY, 252 PhoneStatusBar.FADE_KEYGUARD_DURATION, null); 253 } 254 }, new Runnable() { 255 @Override 256 public void run() { 257 mPhoneStatusBar.hideKeyguard(); 258 mStatusBarWindowManager.setKeyguardFadingAway(false); 259 mViewMediatorCallback.keyguardGone(); 260 executeAfterKeyguardGoneAction(); 261 } 262 }); 263 } else { 264 mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration); 265 boolean staying = mPhoneStatusBar.hideKeyguard(); 266 if (!staying) { 267 mStatusBarWindowManager.setKeyguardFadingAway(true); 268 mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { 269 @Override 270 public void run() { 271 mStatusBarWindowManager.setKeyguardFadingAway(false); 272 mPhoneStatusBar.finishKeyguardFadingAway(); 273 WindowManagerGlobal.getInstance().trimMemory( 274 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 275 } 276 }); 277 } else { 278 mScrimController.animateGoingToFullShade(delay, fadeoutDuration); 279 mPhoneStatusBar.finishKeyguardFadingAway(); 280 } 281 mStatusBarWindowManager.setKeyguardShowing(false); 282 mBouncer.hide(true /* destroyView */); 283 mViewMediatorCallback.keyguardGone(); 284 executeAfterKeyguardGoneAction(); 285 updateStates(); 286 } 287 288 } 289 290 private void executeAfterKeyguardGoneAction() { 291 if (mAfterKeyguardGoneAction != null) { 292 mAfterKeyguardGoneAction.onDismiss(); 293 mAfterKeyguardGoneAction = null; 294 } 295 } 296 297 /** 298 * Dismisses the keyguard by going to the next screen or making it gone. 299 */ 300 public void dismiss() { 301 if (mScreenOn) { 302 showBouncer(); 303 } 304 } 305 306 public boolean isSecure() { 307 return mBouncer.isSecure(); 308 } 309 310 /** 311 * @return Whether the keyguard is showing 312 */ 313 public boolean isShowing() { 314 return mShowing; 315 } 316 317 /** 318 * Notifies this manager that the back button has been pressed. 319 * 320 * @return whether the back press has been handled 321 */ 322 public boolean onBackPressed() { 323 if (mBouncer.isShowing()) { 324 reset(); 325 return true; 326 } 327 return false; 328 } 329 330 public boolean isBouncerShowing() { 331 return mBouncer.isShowing(); 332 } 333 334 private long getNavBarShowDelay() { 335 if (mPhoneStatusBar.isKeyguardFadingAway()) { 336 return mPhoneStatusBar.getKeyguardFadingAwayDelay(); 337 } else { 338 339 // Keyguard is not going away, thus we are showing the navigation bar because the 340 // bouncer is appearing. 341 return NAV_BAR_SHOW_DELAY_BOUNCER; 342 } 343 } 344 345 private Runnable mMakeNavigationBarVisibleRunnable = new Runnable() { 346 @Override 347 public void run() { 348 mPhoneStatusBar.getNavigationBarView().setVisibility(View.VISIBLE); 349 } 350 }; 351 352 private void updateStates() { 353 int vis = mContainer.getSystemUiVisibility(); 354 boolean showing = mShowing; 355 boolean occluded = mOccluded; 356 boolean bouncerShowing = mBouncer.isShowing(); 357 boolean bouncerDismissible = !mBouncer.needsFullscreenBouncer(); 358 359 if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing) 360 || mFirstUpdate) { 361 if (bouncerDismissible || !showing) { 362 mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK); 363 } else { 364 mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK); 365 } 366 } 367 if ((!(showing && !occluded) || bouncerShowing) 368 != (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing) || mFirstUpdate) { 369 if (mPhoneStatusBar.getNavigationBarView() != null) { 370 if (!(showing && !occluded) || bouncerShowing) { 371 mContainer.postOnAnimationDelayed(mMakeNavigationBarVisibleRunnable, 372 getNavBarShowDelay()); 373 } else { 374 mContainer.removeCallbacks(mMakeNavigationBarVisibleRunnable); 375 mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE); 376 } 377 } 378 } 379 380 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { 381 mStatusBarWindowManager.setBouncerShowing(bouncerShowing); 382 mPhoneStatusBar.setBouncerShowing(bouncerShowing); 383 mScrimController.setBouncerShowing(bouncerShowing); 384 } 385 386 KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext); 387 if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) { 388 updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded); 389 } 390 if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) { 391 updateMonitor.sendKeyguardBouncerChanged(bouncerShowing); 392 } 393 394 mFirstUpdate = false; 395 mLastShowing = showing; 396 mLastOccluded = occluded; 397 mLastBouncerShowing = bouncerShowing; 398 mLastBouncerDismissible = bouncerDismissible; 399 } 400 401 public boolean onMenuPressed() { 402 return mBouncer.onMenuPressed(); 403 } 404 405 public boolean interceptMediaKey(KeyEvent event) { 406 return mBouncer.interceptMediaKey(event); 407 } 408 409 public void onActivityDrawn() { 410 if (mPhoneStatusBar.isCollapsing()) { 411 mPhoneStatusBar.addPostCollapseAction(new Runnable() { 412 @Override 413 public void run() { 414 mViewMediatorCallback.readyForKeyguardDone(); 415 } 416 }); 417 } else { 418 mViewMediatorCallback.readyForKeyguardDone(); 419 } 420 } 421 422 public boolean shouldDisableWindowAnimationsForUnlock() { 423 return mPhoneStatusBar.isInLaunchTransition(); 424 } 425 426 public boolean isGoingToNotificationShade() { 427 return mPhoneStatusBar.isGoingToNotificationShade(); 428 } 429 430 public boolean isSecure(int userId) { 431 return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId); 432 } 433} 434