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.app.ActivityManager;
     20 import android.content.Context;
     21 import android.os.UserHandle;
     22 import android.os.UserManager;
     23 import android.util.Slog;
     24 import android.view.KeyEvent;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.view.ViewTreeObserver;
     29 import android.view.accessibility.AccessibilityEvent;
     30 
     31 import com.android.internal.widget.LockPatternUtils;
     32 import com.android.keyguard.KeyguardHostView;
     33 import com.android.keyguard.KeyguardSecurityView;
     34 import com.android.keyguard.KeyguardUpdateMonitor;
     35 import com.android.keyguard.KeyguardUpdateMonitorCallback;
     36 import com.android.keyguard.R;
     37 import com.android.keyguard.ViewMediatorCallback;
     38 import com.android.systemui.DejankUtils;
     39 import com.android.systemui.classifier.FalsingManager;
     40 
     41 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
     42 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
     43 
     44 /**
     45  * A class which manages the bouncer on the lockscreen.
     46  */
     47 public class KeyguardBouncer {
     48 
     49     final static private String TAG = "KeyguardBouncer";
     50 
     51     protected Context mContext;
     52     protected ViewMediatorCallback mCallback;
     53     protected LockPatternUtils mLockPatternUtils;
     54     protected ViewGroup mContainer;
     55     private StatusBarWindowManager mWindowManager;
     56     protected KeyguardHostView mKeyguardView;
     57     protected ViewGroup mRoot;
     58     private boolean mShowingSoon;
     59     private int mBouncerPromptReason;
     60     private FalsingManager mFalsingManager;
     61     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
     62             new KeyguardUpdateMonitorCallback() {
     63                 @Override
     64                 public void onStrongAuthStateChanged(int userId) {
     65                     mBouncerPromptReason = mCallback.getBouncerPromptReason();
     66                 }
     67             };
     68 
     69     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
     70             LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
     71             ViewGroup container) {
     72         mContext = context;
     73         mCallback = callback;
     74         mLockPatternUtils = lockPatternUtils;
     75         mContainer = container;
     76         mWindowManager = windowManager;
     77         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
     78         mFalsingManager = FalsingManager.getInstance(mContext);
     79     }
     80 
     81     public void show(boolean resetSecuritySelection) {
     82         final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
     83         if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
     84             // In split system user mode, we never unlock system user.
     85             return;
     86         }
     87         mFalsingManager.onBouncerShown();
     88         ensureView();
     89         if (resetSecuritySelection) {
     90             // showPrimarySecurityScreen() updates the current security method. This is needed in
     91             // case we are already showing and the current security method changed.
     92             mKeyguardView.showPrimarySecurityScreen();
     93         }
     94         if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
     95             return;
     96         }
     97 
     98         final int activeUserId = ActivityManager.getCurrentUser();
     99         final boolean allowDismissKeyguard =
    100                 !(UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM)
    101                 && activeUserId == keyguardUserId;
    102         // If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
    103         // set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
    104         if (allowDismissKeyguard && mKeyguardView.dismiss()) {
    105             return;
    106         }
    107 
    108         // This condition may indicate an error on Android, so log it.
    109         if (!allowDismissKeyguard) {
    110             Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
    111         }
    112 
    113         mShowingSoon = true;
    114 
    115         // Split up the work over multiple frames.
    116         DejankUtils.postAfterTraversal(mShowRunnable);
    117     }
    118 
    119     private final Runnable mShowRunnable = new Runnable() {
    120         @Override
    121         public void run() {
    122             mRoot.setVisibility(View.VISIBLE);
    123             mKeyguardView.onResume();
    124             showPromptReason(mBouncerPromptReason);
    125             if (mKeyguardView.getHeight() != 0) {
    126                 mKeyguardView.startAppearAnimation();
    127             } else {
    128                 mKeyguardView.getViewTreeObserver().addOnPreDrawListener(
    129                         new ViewTreeObserver.OnPreDrawListener() {
    130                             @Override
    131                             public boolean onPreDraw() {
    132                                 mKeyguardView.getViewTreeObserver().removeOnPreDrawListener(this);
    133                                 mKeyguardView.startAppearAnimation();
    134                                 return true;
    135                             }
    136                         });
    137                 mKeyguardView.requestLayout();
    138             }
    139             mShowingSoon = false;
    140             mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
    141         }
    142     };
    143 
    144     /**
    145      * Show a string explaining why the security view needs to be solved.
    146      *
    147      * @param reason a flag indicating which string should be shown, see
    148      *               {@link KeyguardSecurityView#PROMPT_REASON_NONE}
    149      *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
    150      */
    151     public void showPromptReason(int reason) {
    152         mKeyguardView.showPromptReason(reason);
    153     }
    154 
    155     public void showMessage(String message, int color) {
    156         mKeyguardView.showMessage(message, color);
    157     }
    158 
    159     private void cancelShowRunnable() {
    160         DejankUtils.removeCallbacks(mShowRunnable);
    161         mShowingSoon = false;
    162     }
    163 
    164     public void showWithDismissAction(OnDismissAction r, Runnable cancelAction) {
    165         ensureView();
    166         mKeyguardView.setOnDismissAction(r, cancelAction);
    167         show(false /* resetSecuritySelection */);
    168     }
    169 
    170     public void hide(boolean destroyView) {
    171         mFalsingManager.onBouncerHidden();
    172         cancelShowRunnable();
    173         if (mKeyguardView != null) {
    174             mKeyguardView.cancelDismissAction();
    175             mKeyguardView.cleanUp();
    176         }
    177         if (destroyView) {
    178             removeView();
    179         } else if (mRoot != null) {
    180             mRoot.setVisibility(View.INVISIBLE);
    181         }
    182     }
    183 
    184     /**
    185      * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
    186      */
    187     public void startPreHideAnimation(Runnable runnable) {
    188         if (mKeyguardView != null) {
    189             mKeyguardView.startDisappearAnimation(runnable);
    190         } else if (runnable != null) {
    191             runnable.run();
    192         }
    193     }
    194 
    195     /**
    196      * Reset the state of the view.
    197      */
    198     public void reset() {
    199         cancelShowRunnable();
    200         inflateView();
    201         mFalsingManager.onBouncerHidden();
    202     }
    203 
    204     public void onScreenTurnedOff() {
    205         if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
    206             mKeyguardView.onPause();
    207         }
    208     }
    209 
    210     public boolean isShowing() {
    211         return mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE);
    212     }
    213 
    214     public void prepare() {
    215         boolean wasInitialized = mRoot != null;
    216         ensureView();
    217         if (wasInitialized) {
    218             mKeyguardView.showPrimarySecurityScreen();
    219         }
    220         mBouncerPromptReason = mCallback.getBouncerPromptReason();
    221     }
    222 
    223     protected void ensureView() {
    224         if (mRoot == null) {
    225             inflateView();
    226         }
    227     }
    228 
    229     protected void inflateView() {
    230         removeView();
    231         mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
    232         mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
    233         mKeyguardView.setLockPatternUtils(mLockPatternUtils);
    234         mKeyguardView.setViewMediatorCallback(mCallback);
    235         mContainer.addView(mRoot, mContainer.getChildCount());
    236         mRoot.setVisibility(View.INVISIBLE);
    237     }
    238 
    239     protected void removeView() {
    240         if (mRoot != null && mRoot.getParent() == mContainer) {
    241             mContainer.removeView(mRoot);
    242             mRoot = null;
    243         }
    244     }
    245 
    246     public boolean onBackPressed() {
    247         return mKeyguardView != null && mKeyguardView.handleBackKey();
    248     }
    249 
    250     /**
    251      * @return True if and only if the security method should be shown before showing the
    252      * notifications on Keyguard, like SIM PIN/PUK.
    253      */
    254     public boolean needsFullscreenBouncer() {
    255         ensureView();
    256         if (mKeyguardView != null) {
    257             SecurityMode mode = mKeyguardView.getSecurityMode();
    258             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
    259         }
    260         return false;
    261     }
    262 
    263     /**
    264      * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
    265      * makes this method much faster.
    266      */
    267     public boolean isFullscreenBouncer() {
    268         if (mKeyguardView != null) {
    269             SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
    270             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
    271         }
    272         return false;
    273     }
    274 
    275     /**
    276      * WARNING: This method might cause Binder calls.
    277      */
    278     public boolean isSecure() {
    279         return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
    280     }
    281 
    282     public boolean shouldDismissOnMenuPressed() {
    283         return mKeyguardView.shouldEnableMenuKey();
    284     }
    285 
    286     public boolean interceptMediaKey(KeyEvent event) {
    287         ensureView();
    288         return mKeyguardView.interceptMediaKey(event);
    289     }
    290 
    291     public void notifyKeyguardAuthenticated(boolean strongAuth) {
    292         ensureView();
    293         mKeyguardView.finish(strongAuth);
    294     }
    295 }
    296