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