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