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