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.view.Choreographer;
     21 import android.view.KeyEvent;
     22 import android.view.LayoutInflater;
     23 import android.view.View;
     24 import android.view.ViewGroup;
     25 import android.view.accessibility.AccessibilityEvent;
     26 
     27 import com.android.internal.widget.LockPatternUtils;
     28 import com.android.keyguard.KeyguardViewBase;
     29 import com.android.keyguard.R;
     30 import com.android.keyguard.ViewMediatorCallback;
     31 import com.android.systemui.keyguard.KeyguardViewMediator;
     32 
     33 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
     34 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
     35 
     36 /**
     37  * A class which manages the bouncer on the lockscreen.
     38  */
     39 public class KeyguardBouncer {
     40 
     41     private Context mContext;
     42     private ViewMediatorCallback mCallback;
     43     private LockPatternUtils mLockPatternUtils;
     44     private ViewGroup mContainer;
     45     private StatusBarWindowManager mWindowManager;
     46     private KeyguardViewBase mKeyguardView;
     47     private ViewGroup mRoot;
     48     private boolean mShowingSoon;
     49     private Choreographer mChoreographer = Choreographer.getInstance();
     50 
     51     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
     52             LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
     53             ViewGroup container) {
     54         mContext = context;
     55         mCallback = callback;
     56         mLockPatternUtils = lockPatternUtils;
     57         mContainer = container;
     58         mWindowManager = windowManager;
     59     }
     60 
     61     public void show(boolean resetSecuritySelection) {
     62         ensureView();
     63         if (resetSecuritySelection) {
     64             // showPrimarySecurityScreen() updates the current security method. This is needed in
     65             // case we are already showing and the current security method changed.
     66             mKeyguardView.showPrimarySecurityScreen();
     67         }
     68         if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
     69             return;
     70         }
     71 
     72         // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
     73         // Keyguard. If we need to authenticate, show the bouncer.
     74         if (!mKeyguardView.dismiss()) {
     75             mShowingSoon = true;
     76 
     77             // Split up the work over multiple frames.
     78             mChoreographer.postCallbackDelayed(Choreographer.CALLBACK_ANIMATION, mShowRunnable,
     79                     null, 16);
     80         }
     81     }
     82 
     83     private final Runnable mShowRunnable = new Runnable() {
     84         @Override
     85         public void run() {
     86             mRoot.setVisibility(View.VISIBLE);
     87             mKeyguardView.onResume();
     88             mKeyguardView.startAppearAnimation();
     89             mShowingSoon = false;
     90             mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
     91         }
     92     };
     93 
     94     private void cancelShowRunnable() {
     95         mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null);
     96         mShowingSoon = false;
     97     }
     98 
     99     public void showWithDismissAction(OnDismissAction r) {
    100         ensureView();
    101         mKeyguardView.setOnDismissAction(r);
    102         show(false /* resetSecuritySelection */);
    103     }
    104 
    105     public void hide(boolean destroyView) {
    106         cancelShowRunnable();
    107          if (mKeyguardView != null) {
    108             mKeyguardView.setOnDismissAction(null);
    109             mKeyguardView.cleanUp();
    110         }
    111         if (destroyView) {
    112             removeView();
    113         } else if (mRoot != null) {
    114             mRoot.setVisibility(View.INVISIBLE);
    115         }
    116     }
    117 
    118     /**
    119      * See {@link StatusBarKeyguardViewManager#startPreHideAnimation}.
    120      */
    121     public void startPreHideAnimation(Runnable runnable) {
    122         if (mKeyguardView != null) {
    123             mKeyguardView.startDisappearAnimation(runnable);
    124         } else if (runnable != null) {
    125             runnable.run();
    126         }
    127     }
    128 
    129     /**
    130      * Reset the state of the view.
    131      */
    132     public void reset() {
    133         cancelShowRunnable();
    134         inflateView();
    135     }
    136 
    137     public void onScreenTurnedOff() {
    138         if (mKeyguardView != null && mRoot != null && mRoot.getVisibility() == View.VISIBLE) {
    139             mKeyguardView.onPause();
    140         }
    141     }
    142 
    143     public long getUserActivityTimeout() {
    144         if (mKeyguardView != null) {
    145             long timeout = mKeyguardView.getUserActivityTimeout();
    146             if (timeout >= 0) {
    147                 return timeout;
    148             }
    149         }
    150         return KeyguardViewMediator.AWAKE_INTERVAL_DEFAULT_MS;
    151     }
    152 
    153     public boolean isShowing() {
    154         return mShowingSoon || (mRoot != null && mRoot.getVisibility() == View.VISIBLE);
    155     }
    156 
    157     public void prepare() {
    158         boolean wasInitialized = mRoot != null;
    159         ensureView();
    160         if (wasInitialized) {
    161             mKeyguardView.showPrimarySecurityScreen();
    162         }
    163     }
    164 
    165     private void ensureView() {
    166         if (mRoot == null) {
    167             inflateView();
    168         }
    169     }
    170 
    171     private void inflateView() {
    172         removeView();
    173         mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
    174         mKeyguardView = (KeyguardViewBase) mRoot.findViewById(R.id.keyguard_host_view);
    175         mKeyguardView.setLockPatternUtils(mLockPatternUtils);
    176         mKeyguardView.setViewMediatorCallback(mCallback);
    177         mContainer.addView(mRoot, mContainer.getChildCount());
    178         mRoot.setVisibility(View.INVISIBLE);
    179         mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
    180     }
    181 
    182     private void removeView() {
    183         if (mRoot != null && mRoot.getParent() == mContainer) {
    184             mContainer.removeView(mRoot);
    185             mRoot = null;
    186         }
    187     }
    188 
    189     public boolean onBackPressed() {
    190         return mKeyguardView != null && mKeyguardView.handleBackKey();
    191     }
    192 
    193     /**
    194      * @return True if and only if the security method should be shown before showing the
    195      * notifications on Keyguard, like SIM PIN/PUK.
    196      */
    197     public boolean needsFullscreenBouncer() {
    198         if (mKeyguardView != null) {
    199             SecurityMode mode = mKeyguardView.getSecurityMode();
    200             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
    201         }
    202         return false;
    203     }
    204 
    205     /**
    206      * Like {@link #needsFullscreenBouncer}, but uses the currently visible security method, which
    207      * makes this method much faster.
    208      */
    209     public boolean isFullscreenBouncer() {
    210         if (mKeyguardView != null) {
    211             SecurityMode mode = mKeyguardView.getCurrentSecurityMode();
    212             return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;
    213         }
    214         return false;
    215     }
    216 
    217     /**
    218      * WARNING: This method might cause Binder calls.
    219      */
    220     public boolean isSecure() {
    221         return mKeyguardView == null || mKeyguardView.getSecurityMode() != SecurityMode.None;
    222     }
    223 
    224     public boolean onMenuPressed() {
    225         ensureView();
    226         if (mKeyguardView.handleMenuKey()) {
    227 
    228             // We need to show it in case it is secure. If not, it will get dismissed in any case.
    229             mRoot.setVisibility(View.VISIBLE);
    230             mKeyguardView.requestFocus();
    231             mKeyguardView.onResume();
    232             return true;
    233         } else {
    234             return false;
    235         }
    236     }
    237 
    238     public boolean interceptMediaKey(KeyEvent event) {
    239         ensureView();
    240         return mKeyguardView.interceptMediaKey(event);
    241     }
    242 }
    243