OSDN Git Service

Remove unnecessary casts on calls to findViewById
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / keyguard / KeyguardSecurityContainer.java
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 package com.android.keyguard;
17
18 import android.app.Activity;
19 import android.app.AlertDialog;
20 import android.app.admin.DevicePolicyManager;
21 import android.content.Context;
22 import android.os.UserHandle;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 import android.util.Slog;
26 import android.view.LayoutInflater;
27 import android.view.View;
28 import android.view.WindowManager;
29 import android.widget.FrameLayout;
30
31 import com.android.internal.widget.LockPatternUtils;
32 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
33
34 public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
35     private static final boolean DEBUG = KeyguardConstants.DEBUG;
36     private static final String TAG = "KeyguardSecurityView";
37
38     private static final int USER_TYPE_PRIMARY = 1;
39     private static final int USER_TYPE_WORK_PROFILE = 2;
40     private static final int USER_TYPE_SECONDARY_USER = 3;
41
42     private KeyguardSecurityModel mSecurityModel;
43     private LockPatternUtils mLockPatternUtils;
44
45     private KeyguardSecurityViewFlipper mSecurityViewFlipper;
46     private boolean mIsVerifyUnlockOnly;
47     private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
48     private SecurityCallback mSecurityCallback;
49
50     private final KeyguardUpdateMonitor mUpdateMonitor;
51
52     // Used to notify the container when something interesting happens.
53     public interface SecurityCallback {
54         public boolean dismiss(boolean authenticated, int targetUserId);
55         public void userActivity();
56         public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
57
58         /**
59          * @param strongAuth wheher the user has authenticated with strong authentication like
60          *                   pattern, password or PIN but not by trust agents or fingerprint
61          * @param targetUserId a user that needs to be the foreground user at the finish completion.
62          */
63         public void finish(boolean strongAuth, int targetUserId);
64         public void reset();
65     }
66
67     public KeyguardSecurityContainer(Context context, AttributeSet attrs) {
68         this(context, attrs, 0);
69     }
70
71     public KeyguardSecurityContainer(Context context) {
72         this(context, null, 0);
73     }
74
75     public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
76         super(context, attrs, defStyle);
77         mSecurityModel = new KeyguardSecurityModel(context);
78         mLockPatternUtils = new LockPatternUtils(context);
79         mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
80     }
81
82     public void setSecurityCallback(SecurityCallback callback) {
83         mSecurityCallback = callback;
84     }
85
86     @Override
87     public void onResume(int reason) {
88         if (mCurrentSecuritySelection != SecurityMode.None) {
89             getSecurityView(mCurrentSecuritySelection).onResume(reason);
90         }
91     }
92
93     @Override
94     public void onPause() {
95         if (mCurrentSecuritySelection != SecurityMode.None) {
96             getSecurityView(mCurrentSecuritySelection).onPause();
97         }
98     }
99
100     public void startAppearAnimation() {
101         if (mCurrentSecuritySelection != SecurityMode.None) {
102             getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
103         }
104     }
105
106     public boolean startDisappearAnimation(Runnable onFinishRunnable) {
107         if (mCurrentSecuritySelection != SecurityMode.None) {
108             return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
109                     onFinishRunnable);
110         }
111         return false;
112     }
113
114     public void announceCurrentSecurityMethod() {
115         View v = (View) getSecurityView(mCurrentSecuritySelection);
116         if (v != null) {
117             v.announceForAccessibility(v.getContentDescription());
118         }
119     }
120
121     public CharSequence getCurrentSecurityModeContentDescription() {
122         View v = (View) getSecurityView(mCurrentSecuritySelection);
123         if (v != null) {
124             return v.getContentDescription();
125         }
126         return "";
127     }
128
129     private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
130         final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
131         KeyguardSecurityView view = null;
132         final int children = mSecurityViewFlipper.getChildCount();
133         for (int child = 0; child < children; child++) {
134             if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
135                 view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
136                 break;
137             }
138         }
139         int layoutId = getLayoutIdFor(securityMode);
140         if (view == null && layoutId != 0) {
141             final LayoutInflater inflater = LayoutInflater.from(mContext);
142             if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
143             View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
144             mSecurityViewFlipper.addView(v);
145             updateSecurityView(v);
146             view = (KeyguardSecurityView)v;
147         }
148
149         return view;
150     }
151
152     private void updateSecurityView(View view) {
153         if (view instanceof KeyguardSecurityView) {
154             KeyguardSecurityView ksv = (KeyguardSecurityView) view;
155             ksv.setKeyguardCallback(mCallback);
156             ksv.setLockPatternUtils(mLockPatternUtils);
157         } else {
158             Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
159         }
160     }
161
162     protected void onFinishInflate() {
163         mSecurityViewFlipper = findViewById(R.id.view_flipper);
164         mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
165     }
166
167     public void setLockPatternUtils(LockPatternUtils utils) {
168         mLockPatternUtils = utils;
169         mSecurityModel.setLockPatternUtils(utils);
170         mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
171     }
172
173     private void showDialog(String title, String message) {
174         final AlertDialog dialog = new AlertDialog.Builder(mContext)
175             .setTitle(title)
176             .setMessage(message)
177             .setCancelable(false)
178             .setNeutralButton(R.string.ok, null)
179             .create();
180         if (!(mContext instanceof Activity)) {
181             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
182         }
183         dialog.show();
184     }
185
186     private void showTimeoutDialog(int userId, int timeoutMs) {
187         int timeoutInSeconds = (int) timeoutMs / 1000;
188         int messageId = 0;
189
190         switch (mSecurityModel.getSecurityMode(userId)) {
191             case Pattern:
192                 messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
193                 break;
194             case PIN:
195                 messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
196                 break;
197             case Password:
198                 messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
199                 break;
200             // These don't have timeout dialogs.
201             case Invalid:
202             case None:
203             case SimPin:
204             case SimPuk:
205                 break;
206         }
207
208         if (messageId != 0) {
209             final String message = mContext.getString(messageId,
210                     KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(userId),
211                     timeoutInSeconds);
212             showDialog(null, message);
213         }
214     }
215
216     private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
217         String message = null;
218         switch (userType) {
219             case USER_TYPE_PRIMARY:
220                 message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
221                         attempts, remaining);
222                 break;
223             case USER_TYPE_SECONDARY_USER:
224                 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_user,
225                         attempts, remaining);
226                 break;
227             case USER_TYPE_WORK_PROFILE:
228                 message = mContext.getString(R.string.kg_failed_attempts_almost_at_erase_profile,
229                         attempts, remaining);
230                 break;
231         }
232         showDialog(null, message);
233     }
234
235     private void showWipeDialog(int attempts, int userType) {
236         String message = null;
237         switch (userType) {
238             case USER_TYPE_PRIMARY:
239                 message = mContext.getString(R.string.kg_failed_attempts_now_wiping,
240                         attempts);
241                 break;
242             case USER_TYPE_SECONDARY_USER:
243                 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_user,
244                         attempts);
245                 break;
246             case USER_TYPE_WORK_PROFILE:
247                 message = mContext.getString(R.string.kg_failed_attempts_now_erasing_profile,
248                         attempts);
249                 break;
250         }
251         showDialog(null, message);
252     }
253
254     private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
255         final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
256         final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
257
258         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
259
260         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
261         final int failedAttemptsBeforeWipe =
262                 dpm.getMaximumFailedPasswordsForWipe(null, userId);
263
264         final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
265                 (failedAttemptsBeforeWipe - failedAttempts)
266                 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
267         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
268             // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
269             // N attempts. Once we get below the grace period, we post this dialog every time as a
270             // clear warning until the deletion fires.
271             // Check which profile has the strictest policy for failed password attempts
272             final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
273             int userType = USER_TYPE_PRIMARY;
274             if (expiringUser == userId) {
275                 // TODO: http://b/23522538
276                 if (expiringUser != UserHandle.USER_SYSTEM) {
277                     userType = USER_TYPE_SECONDARY_USER;
278                 }
279             } else if (expiringUser != UserHandle.USER_NULL) {
280                 userType = USER_TYPE_WORK_PROFILE;
281             } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
282             if (remainingBeforeWipe > 0) {
283                 showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
284             } else {
285                 // Too many attempts. The device will be wiped shortly.
286                 Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
287                 showWipeDialog(failedAttempts, userType);
288             }
289         }
290         monitor.reportFailedStrongAuthUnlockAttempt(userId);
291         mLockPatternUtils.reportFailedPasswordAttempt(userId);
292         if (timeoutMs > 0) {
293             mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
294             showTimeoutDialog(userId, timeoutMs);
295         }
296     }
297
298     /**
299      * Shows the primary security screen for the user. This will be either the multi-selector
300      * or the user's security method.
301      * @param turningOff true if the device is being turned off
302      */
303     void showPrimarySecurityScreen(boolean turningOff) {
304         SecurityMode securityMode = mSecurityModel.getSecurityMode(
305                 KeyguardUpdateMonitor.getCurrentUser());
306         if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
307         showSecurityScreen(securityMode);
308     }
309
310     /**
311      * Shows the next security screen if there is one.
312      * @param authenticated true if the user entered the correct authentication
313      * @param targetUserId a user that needs to be the foreground user at the finish (if called)
314      *     completion.
315      * @return true if keyguard is done
316      */
317     boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId) {
318         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
319         boolean finish = false;
320         boolean strongAuth = false;
321         if (mUpdateMonitor.getUserCanSkipBouncer(targetUserId)) {
322             finish = true;
323         } else if (SecurityMode.None == mCurrentSecuritySelection) {
324             SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
325             if (SecurityMode.None == securityMode) {
326                 finish = true; // no security required
327             } else {
328                 showSecurityScreen(securityMode); // switch to the alternate security view
329             }
330         } else if (authenticated) {
331             switch (mCurrentSecuritySelection) {
332                 case Pattern:
333                 case Password:
334                 case PIN:
335                     strongAuth = true;
336                     finish = true;
337                     break;
338
339                 case SimPin:
340                 case SimPuk:
341                     // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
342                     SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
343                     if (securityMode != SecurityMode.None
344                             || !mLockPatternUtils.isLockScreenDisabled(
345                             KeyguardUpdateMonitor.getCurrentUser())) {
346                         showSecurityScreen(securityMode);
347                     } else {
348                         finish = true;
349                     }
350                     break;
351
352                 default:
353                     Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
354                     showPrimarySecurityScreen(false);
355                     break;
356             }
357         }
358         if (finish) {
359             mSecurityCallback.finish(strongAuth, targetUserId);
360         }
361         return finish;
362     }
363
364     /**
365      * Switches to the given security view unless it's already being shown, in which case
366      * this is a no-op.
367      *
368      * @param securityMode
369      */
370     private void showSecurityScreen(SecurityMode securityMode) {
371         if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
372
373         if (securityMode == mCurrentSecuritySelection) return;
374
375         KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
376         KeyguardSecurityView newView = getSecurityView(securityMode);
377
378         // Emulate Activity life cycle
379         if (oldView != null) {
380             oldView.onPause();
381             oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
382         }
383         if (securityMode != SecurityMode.None) {
384             newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
385             newView.setKeyguardCallback(mCallback);
386         }
387
388         // Find and show this child.
389         final int childCount = mSecurityViewFlipper.getChildCount();
390
391         final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
392         for (int i = 0; i < childCount; i++) {
393             if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
394                 mSecurityViewFlipper.setDisplayedChild(i);
395                 break;
396             }
397         }
398
399         mCurrentSecuritySelection = securityMode;
400         mSecurityCallback.onSecurityModeChanged(securityMode,
401                 securityMode != SecurityMode.None && newView.needsInput());
402     }
403
404     private KeyguardSecurityViewFlipper getFlipper() {
405         for (int i = 0; i < getChildCount(); i++) {
406             View child = getChildAt(i);
407             if (child instanceof KeyguardSecurityViewFlipper) {
408                 return (KeyguardSecurityViewFlipper) child;
409             }
410         }
411         return null;
412     }
413
414     private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
415         public void userActivity() {
416             if (mSecurityCallback != null) {
417                 mSecurityCallback.userActivity();
418             }
419         }
420
421         public void dismiss(boolean authenticated, int targetId) {
422             mSecurityCallback.dismiss(authenticated, targetId);
423         }
424
425         public boolean isVerifyUnlockOnly() {
426             return mIsVerifyUnlockOnly;
427         }
428
429         public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
430             KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
431             if (success) {
432                 monitor.clearFailedUnlockAttempts();
433                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
434             } else {
435                 KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
436             }
437         }
438
439         public void reset() {
440             mSecurityCallback.reset();
441         }
442     };
443
444     // The following is used to ignore callbacks from SecurityViews that are no longer current
445     // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
446     // state for the current security method.
447     private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
448         @Override
449         public void userActivity() { }
450         @Override
451         public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
452         @Override
453         public boolean isVerifyUnlockOnly() { return false; }
454         @Override
455         public void dismiss(boolean securityVerified, int targetUserId) { }
456         @Override
457         public void reset() {}
458     };
459
460     private int getSecurityViewIdForMode(SecurityMode securityMode) {
461         switch (securityMode) {
462             case Pattern: return R.id.keyguard_pattern_view;
463             case PIN: return R.id.keyguard_pin_view;
464             case Password: return R.id.keyguard_password_view;
465             case SimPin: return R.id.keyguard_sim_pin_view;
466             case SimPuk: return R.id.keyguard_sim_puk_view;
467         }
468         return 0;
469     }
470
471     protected int getLayoutIdFor(SecurityMode securityMode) {
472         switch (securityMode) {
473             case Pattern: return R.layout.keyguard_pattern_view;
474             case PIN: return R.layout.keyguard_pin_view;
475             case Password: return R.layout.keyguard_password_view;
476             case SimPin: return R.layout.keyguard_sim_pin_view;
477             case SimPuk: return R.layout.keyguard_sim_puk_view;
478             default:
479                 return 0;
480         }
481     }
482
483     public SecurityMode getSecurityMode() {
484         return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
485     }
486
487     public SecurityMode getCurrentSecurityMode() {
488         return mCurrentSecuritySelection;
489     }
490
491     public void verifyUnlock() {
492         mIsVerifyUnlockOnly = true;
493         showSecurityScreen(getSecurityMode());
494     }
495
496     public SecurityMode getCurrentSecuritySelection() {
497         return mCurrentSecuritySelection;
498     }
499
500     public void dismiss(boolean authenticated, int targetUserId) {
501         mCallback.dismiss(authenticated, targetUserId);
502     }
503
504     public boolean needsInput() {
505         return mSecurityViewFlipper.needsInput();
506     }
507
508     @Override
509     public void setKeyguardCallback(KeyguardSecurityCallback callback) {
510         mSecurityViewFlipper.setKeyguardCallback(callback);
511     }
512
513     @Override
514     public void reset() {
515         mSecurityViewFlipper.reset();
516     }
517
518     @Override
519     public KeyguardSecurityCallback getCallback() {
520         return mSecurityViewFlipper.getCallback();
521     }
522
523     @Override
524     public void showPromptReason(int reason) {
525         if (mCurrentSecuritySelection != SecurityMode.None) {
526             if (reason != PROMPT_REASON_NONE) {
527                 Log.i(TAG, "Strong auth required, reason: " + reason);
528             }
529             getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
530         }
531     }
532
533
534     public void showMessage(String message, int color) {
535         if (mCurrentSecuritySelection != SecurityMode.None) {
536             getSecurityView(mCurrentSecuritySelection).showMessage(message, color);
537         }
538     }
539
540     @Override
541     public void showUsabilityHint() {
542         mSecurityViewFlipper.showUsabilityHint();
543     }
544
545 }
546