StatusBarKeyguardViewManager.java revision 25d7e51a10828e4433fcca90410d13a4b2342c34
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; 34import com.android.systemui.statusbar.CommandQueue; 35 36import static com.android.keyguard.KeyguardHostView.OnDismissAction; 37 38/** 39 * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back 40 * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, 41 * which is in turn, reported to this class by the current 42 * {@link com.android.keyguard.KeyguardViewBase}. 43 */ 44public class StatusBarKeyguardViewManager { 45 46 // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. 47 private static final long HIDE_TIMING_CORRECTION_MS = -3 * 16; 48 49 // Delay for showing the navigation bar when the bouncer appears. This should be kept in sync 50 // with the appear animations of the PIN/pattern/password views. 51 private static final long NAV_BAR_SHOW_DELAY_BOUNCER = 320; 52 53 private static String TAG = "StatusBarKeyguardViewManager"; 54 55 private final Context mContext; 56 57 private LockPatternUtils mLockPatternUtils; 58 private ViewMediatorCallback mViewMediatorCallback; 59 private PhoneStatusBar mPhoneStatusBar; 60 private ScrimController mScrimController; 61 62 private ViewGroup mContainer; 63 private StatusBarWindowManager mStatusBarWindowManager; 64 65 private boolean mScreenOn = false; 66 private KeyguardBouncer mBouncer; 67 private boolean mShowing; 68 private boolean mOccluded; 69 70 private boolean mFirstUpdate = true; 71 private boolean mLastShowing; 72 private boolean mLastOccluded; 73 private boolean mLastBouncerShowing; 74 private boolean mLastBouncerDismissible; 75 private OnDismissAction mAfterKeyguardGoneAction; 76 77 public StatusBarKeyguardViewManager(Context context, ViewMediatorCallback callback, 78 LockPatternUtils lockPatternUtils) { 79 mContext = context; 80 mViewMediatorCallback = callback; 81 mLockPatternUtils = lockPatternUtils; 82 } 83 84 public void registerStatusBar(PhoneStatusBar phoneStatusBar, 85 ViewGroup container, StatusBarWindowManager statusBarWindowManager, 86 ScrimController scrimController) { 87 mPhoneStatusBar = phoneStatusBar; 88 mContainer = container; 89 mStatusBarWindowManager = statusBarWindowManager; 90 mScrimController = scrimController; 91 mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils, 92 mStatusBarWindowManager, container); 93 } 94 95 /** 96 * Show the keyguard. Will handle creating and attaching to the view manager 97 * lazily. 98 */ 99 public void show(Bundle options) { 100 mShowing = true; 101 mStatusBarWindowManager.setKeyguardShowing(true); 102 reset(); 103 } 104 105 /** 106 * Shows the notification keyguard or the bouncer depending on 107 * {@link KeyguardBouncer#needsFullscreenBouncer()}. 108 */ 109 private void showBouncerOrKeyguard() { 110 if (mBouncer.needsFullscreenBouncer()) { 111 112 // The keyguard might be showing (already). So we need to hide it. 113 mPhoneStatusBar.hideKeyguard(); 114 mBouncer.show(true /* resetSecuritySelection */); 115 } else { 116 mPhoneStatusBar.showKeyguard(); 117 mBouncer.hide(false /* destroyView */); 118 mBouncer.prepare(); 119 } 120 } 121 122 private void showBouncer() { 123 if (mShowing) { 124 mBouncer.show(false /* resetSecuritySelection */); 125 } 126 updateStates(); 127 } 128 129 public void dismissWithAction(OnDismissAction r, boolean afterKeyguardGone) { 130 if (mShowing) { 131 if (!afterKeyguardGone) { 132 mBouncer.showWithDismissAction(r); 133 } else { 134 mBouncer.show(false /* resetSecuritySelection */); 135 mAfterKeyguardGoneAction = r; 136 } 137 } 138 updateStates(); 139 } 140 141 /** 142 * Reset the state of the view. 143 */ 144 public void reset() { 145 if (mShowing) { 146 if (mOccluded) { 147 mPhoneStatusBar.hideKeyguard(); 148 mBouncer.hide(false /* destroyView */); 149 } else { 150 showBouncerOrKeyguard(); 151 } 152 updateStates(); 153 } 154 } 155 156 public void onScreenTurnedOff() { 157 mScreenOn = false; 158 mPhoneStatusBar.onScreenTurnedOff(); 159 mBouncer.onScreenTurnedOff(); 160 } 161 162 public void onScreenTurnedOn(final IKeyguardShowCallback callback) { 163 mScreenOn = true; 164 mPhoneStatusBar.onScreenTurnedOn(); 165 if (callback != null) { 166 callbackAfterDraw(callback); 167 } 168 } 169 170 private void callbackAfterDraw(final IKeyguardShowCallback callback) { 171 mContainer.post(new Runnable() { 172 @Override 173 public void run() { 174 try { 175 callback.onShown(mContainer.getWindowToken()); 176 } catch (RemoteException e) { 177 Slog.w(TAG, "Exception calling onShown():", e); 178 } 179 } 180 }); 181 } 182 183 public void verifyUnlock() { 184 dismiss(); 185 } 186 187 public void setNeedsInput(boolean needsInput) { 188 mStatusBarWindowManager.setKeyguardNeedsInput(needsInput); 189 } 190 191 public void setOccluded(boolean occluded) { 192 if (occluded && !mOccluded && mShowing) { 193 if (mPhoneStatusBar.isInLaunchTransition()) { 194 mOccluded = true; 195 mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, 196 new Runnable() { 197 @Override 198 public void run() { 199 mStatusBarWindowManager.setKeyguardOccluded(mOccluded); 200 reset(); 201 } 202 }); 203 return; 204 } 205 } 206 mOccluded = occluded; 207 mStatusBarWindowManager.setKeyguardOccluded(occluded); 208 reset(); 209 } 210 211 public boolean isOccluded() { 212 return mOccluded; 213 } 214 215 /** 216 * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the 217 * security view of the bouncer. 218 * 219 * @param finishRunnable the runnable to be run after the animation finished, or {@code null} if 220 * no action should be run 221 */ 222 public void startPreHideAnimation(Runnable finishRunnable) { 223 if (mBouncer.isShowing()) { 224 mBouncer.startPreHideAnimation(finishRunnable); 225 } else if (finishRunnable != null) { 226 finishRunnable.run(); 227 } 228 } 229 230 /** 231 * Hides the keyguard view 232 */ 233 public void hide(long startTime, final long fadeoutDuration) { 234 mShowing = false; 235 236 long uptimeMillis = SystemClock.uptimeMillis(); 237 long delay = Math.max(0, startTime + HIDE_TIMING_CORRECTION_MS - uptimeMillis); 238 239 if (mPhoneStatusBar.isInLaunchTransition() ) { 240 mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() { 241 @Override 242 public void run() { 243 mStatusBarWindowManager.setKeyguardShowing(false); 244 mStatusBarWindowManager.setKeyguardFadingAway(true); 245 mBouncer.hide(true /* destroyView */); 246 updateStates(); 247 mScrimController.animateKeyguardFadingOut( 248 PhoneStatusBar.FADE_KEYGUARD_START_DELAY, 249 PhoneStatusBar.FADE_KEYGUARD_DURATION, null); 250 } 251 }, new Runnable() { 252 @Override 253 public void run() { 254 mPhoneStatusBar.hideKeyguard(); 255 mStatusBarWindowManager.setKeyguardFadingAway(false); 256 mViewMediatorCallback.keyguardGone(); 257 executeAfterKeyguardGoneAction(); 258 } 259 }); 260 } else { 261 mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration); 262 boolean staying = mPhoneStatusBar.hideKeyguard(); 263 if (!staying) { 264 mStatusBarWindowManager.setKeyguardFadingAway(true); 265 mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() { 266 @Override 267 public void run() { 268 mStatusBarWindowManager.setKeyguardFadingAway(false); 269 mPhoneStatusBar.finishKeyguardFadingAway(); 270 WindowManagerGlobal.getInstance().trimMemory( 271 ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); 272 } 273 }); 274 } else { 275 mScrimController.animateGoingToFullShade(delay, fadeoutDuration); 276 mPhoneStatusBar.finishKeyguardFadingAway(); 277 } 278 mStatusBarWindowManager.setKeyguardShowing(false); 279 mBouncer.hide(true /* destroyView */); 280 mViewMediatorCallback.keyguardGone(); 281 executeAfterKeyguardGoneAction(); 282 updateStates(); 283 } 284 285 } 286 287 private void executeAfterKeyguardGoneAction() { 288 if (mAfterKeyguardGoneAction != null) { 289 mAfterKeyguardGoneAction.onDismiss(); 290 mAfterKeyguardGoneAction = null; 291 } 292 } 293 294 /** 295 * Dismisses the keyguard by going to the next screen or making it gone. 296 */ 297 public void dismiss() { 298 if (mScreenOn) { 299 showBouncer(); 300 } 301 } 302 303 /** 304 * WARNING: This method might cause Binder calls. 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.isFullscreenBouncer(); 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 mPhoneStatusBar.onKeyguardViewManagerStatesUpdated(); 401 } 402 403 public boolean onMenuPressed() { 404 return mBouncer.onMenuPressed(); 405 } 406 407 public boolean interceptMediaKey(KeyEvent event) { 408 return mBouncer.interceptMediaKey(event); 409 } 410 411 public void onActivityDrawn() { 412 if (mPhoneStatusBar.isCollapsing()) { 413 mPhoneStatusBar.addPostCollapseAction(new Runnable() { 414 @Override 415 public void run() { 416 mViewMediatorCallback.readyForKeyguardDone(); 417 } 418 }); 419 } else { 420 mViewMediatorCallback.readyForKeyguardDone(); 421 } 422 } 423 424 public boolean shouldDisableWindowAnimationsForUnlock() { 425 return mPhoneStatusBar.isInLaunchTransition(); 426 } 427 428 public boolean isGoingToNotificationShade() { 429 return mPhoneStatusBar.isGoingToNotificationShade(); 430 } 431 432 public boolean isSecure(int userId) { 433 return mBouncer.isSecure() || mLockPatternUtils.isSecure(userId); 434 } 435 436 public boolean isInputRestricted() { 437 return mViewMediatorCallback.isInputRestricted(); 438 } 439 440 public void keyguardGoingAway() { 441 mPhoneStatusBar.keyguardGoingAway(); 442 } 443 444 public void animateCollapsePanels() { 445 mPhoneStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); 446 } 447} 448