KeyguardHostView.java revision 105beddcb98efc24f37259881d9b4c267aa0d198
1/*
2 * Copyright (C) 2012 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.keyguard;
18
19import com.android.internal.widget.LockPatternUtils;
20import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
21
22import android.app.Activity;
23import android.app.ActivityManager;
24import android.app.ActivityOptions;
25import android.app.AlertDialog;
26import android.app.SearchManager;
27import android.app.admin.DevicePolicyManager;
28import android.appwidget.AppWidgetHost;
29import android.appwidget.AppWidgetHostView;
30import android.appwidget.AppWidgetManager;
31import android.appwidget.AppWidgetProviderInfo;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentSender;
36import android.content.pm.PackageManager.NameNotFoundException;
37import android.content.pm.UserInfo;
38import android.content.res.Resources;
39import android.graphics.Canvas;
40import android.graphics.Rect;
41import android.os.Looper;
42import android.os.Parcel;
43import android.os.Parcelable;
44import android.os.SystemClock;
45import android.os.UserHandle;
46import android.os.UserManager;
47import android.provider.Settings;
48import android.util.AttributeSet;
49import android.util.Log;
50import android.util.Slog;
51import android.view.KeyEvent;
52import android.view.LayoutInflater;
53import android.view.MotionEvent;
54import android.view.View;
55import android.view.WindowManager;
56import android.view.animation.AnimationUtils;
57import android.widget.RemoteViews.OnClickHandler;
58
59import java.io.File;
60import java.util.List;
61
62public class KeyguardHostView extends KeyguardViewBase {
63    private static final String TAG = "KeyguardHostView";
64
65    // Use this to debug all of keyguard
66    public static boolean DEBUG = KeyguardViewMediator.DEBUG;
67
68    // Found in KeyguardAppWidgetPickActivity.java
69    static final int APPWIDGET_HOST_ID = 0x4B455947;
70
71    private final int MAX_WIDGETS = 5;
72
73    private AppWidgetHost mAppWidgetHost;
74    private AppWidgetManager mAppWidgetManager;
75    private KeyguardWidgetPager mAppWidgetContainer;
76    private KeyguardSecurityViewFlipper mSecurityViewContainer;
77    private KeyguardSelectorView mKeyguardSelectorView;
78    private KeyguardTransportControlView mTransportControl;
79    private boolean mIsVerifyUnlockOnly;
80    private boolean mEnableFallback; // TODO: This should get the value from KeyguardPatternView
81    private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
82    private int mAppWidgetToShow;
83
84    private boolean mCheckAppWidgetConsistencyOnBootCompleted = false;
85    private boolean mCleanupAppWidgetsOnBootCompleted = false;
86
87    protected OnDismissAction mDismissAction;
88
89    protected int mFailedAttempts;
90    private LockPatternUtils mLockPatternUtils;
91
92    private KeyguardSecurityModel mSecurityModel;
93    private KeyguardViewStateManager mViewStateManager;
94
95    private Rect mTempRect = new Rect();
96
97    private int mDisabledFeatures;
98
99    private boolean mCameraDisabled;
100
101    private boolean mSafeModeEnabled;
102
103    private boolean mUserSetupCompleted;
104
105    // User for whom this host view was created.  Final because we should never change the
106    // id without reconstructing an instance of KeyguardHostView. See note below...
107    private final int mUserId;
108
109    private KeyguardMultiUserSelectorView mKeyguardMultiUserSelectorView;
110
111    /*package*/ interface TransportCallback {
112        void onListenerDetached();
113        void onListenerAttached();
114        void onPlayStateChanged();
115    }
116
117    /*package*/ interface UserSwitcherCallback {
118        void hideSecurityView(int duration);
119        void showSecurityView();
120        void showUnlockHint();
121        void userActivity();
122    }
123
124    /*package*/ interface OnDismissAction {
125        /* returns true if the dismiss should be deferred */
126        boolean onDismiss();
127    }
128
129    public KeyguardHostView(Context context) {
130        this(context, null);
131    }
132
133    public KeyguardHostView(Context context, AttributeSet attrs) {
134        super(context, attrs);
135        mLockPatternUtils = new LockPatternUtils(context);
136
137        // Note: This depends on KeyguardHostView getting reconstructed every time the
138        // user switches, since mUserId will be used for the entire session.
139        // Once created, keyguard should *never* re-use this instance with another user.
140        // In other words, mUserId should never change - hence it's marked final.
141        mUserId = mLockPatternUtils.getCurrentUser();
142
143        DevicePolicyManager dpm =
144                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
145        if (dpm != null) {
146            mDisabledFeatures = getDisabledFeatures(dpm);
147            mCameraDisabled = dpm.getCameraDisabled(null);
148        }
149
150        mSafeModeEnabled = LockPatternUtils.isSafeModeEnabled();
151
152        // These need to be created with the user context...
153        Context userContext = null;
154        try {
155            final String packageName = "system";
156            userContext = mContext.createPackageContextAsUser(packageName, 0,
157                    new UserHandle(mUserId));
158
159        } catch (NameNotFoundException e) {
160            e.printStackTrace();
161            // This should never happen, but it's better to have no widgets than to crash.
162            userContext = context;
163        }
164
165        mAppWidgetHost = new AppWidgetHost(userContext, APPWIDGET_HOST_ID, mOnClickHandler,
166                Looper.myLooper());
167
168        cleanupAppWidgetIds();
169
170        mAppWidgetManager = AppWidgetManager.getInstance(userContext);
171
172        mSecurityModel = new KeyguardSecurityModel(context);
173
174        mViewStateManager = new KeyguardViewStateManager(this);
175
176        mUserSetupCompleted = Settings.Secure.getIntForUser(mContext.getContentResolver(),
177                Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
178
179        if (mSafeModeEnabled) {
180            Log.v(TAG, "Keyguard widgets disabled by safe mode");
181        }
182        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0) {
183            Log.v(TAG, "Keyguard widgets disabled by DPM");
184        }
185        if ((mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0) {
186            Log.v(TAG, "Keyguard secure camera disabled by DPM");
187        }
188    }
189
190    private void cleanupAppWidgetIds() {
191        // Since this method may delete a widget (which we can't do until boot completed) we
192        // may have to defer it until after boot complete.
193        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
194            mCleanupAppWidgetsOnBootCompleted = true;
195            return;
196        }
197        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
198            // Clean up appWidgetIds that are bound to lockscreen, but not actually used
199            // This is only to clean up after another bug: we used to not call
200            // deleteAppWidgetId when a user manually deleted a widget in keyguard. This code
201            // shouldn't have to run more than once per user. AppWidgetProviders rely on callbacks
202            // that are triggered by deleteAppWidgetId, which is why we're doing this
203            int[] appWidgetIdsInKeyguardSettings = mLockPatternUtils.getAppWidgets();
204            int[] appWidgetIdsBoundToHost = mAppWidgetHost.getAppWidgetIds();
205            for (int i = 0; i < appWidgetIdsBoundToHost.length; i++) {
206                int appWidgetId = appWidgetIdsBoundToHost[i];
207                if (!contains(appWidgetIdsInKeyguardSettings, appWidgetId)) {
208                    Log.d(TAG, "Found a appWidgetId that's not being used by keyguard, deleting id "
209                            + appWidgetId);
210                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
211                }
212            }
213        }
214    }
215
216    private static boolean contains(int[] array, int target) {
217        for (int value : array) {
218            if (value == target) {
219                return true;
220            }
221        }
222        return false;
223    }
224
225    private KeyguardUpdateMonitorCallback mUpdateMonitorCallbacks =
226            new KeyguardUpdateMonitorCallback() {
227        @Override
228        public void onBootCompleted() {
229            if (mCheckAppWidgetConsistencyOnBootCompleted) {
230                checkAppWidgetConsistency();
231                mSwitchPageRunnable.run();
232                mCheckAppWidgetConsistencyOnBootCompleted = false;
233            }
234            if (mCleanupAppWidgetsOnBootCompleted) {
235                cleanupAppWidgetIds();
236                mCleanupAppWidgetsOnBootCompleted = false;
237            }
238        }
239        @Override
240        public void onUserSwitchComplete(int userId) {
241            if (mKeyguardMultiUserSelectorView != null) {
242                mKeyguardMultiUserSelectorView.finalizeActiveUserView(true);
243            }
244        }
245    };
246
247    private SlidingChallengeLayout mSlidingChallengeLayout;
248
249    @Override
250    public boolean onTouchEvent(MotionEvent ev) {
251        boolean result = super.onTouchEvent(ev);
252        mTempRect.set(0, 0, 0, 0);
253        offsetRectIntoDescendantCoords(mSecurityViewContainer, mTempRect);
254        ev.offsetLocation(mTempRect.left, mTempRect.top);
255        result = mSecurityViewContainer.dispatchTouchEvent(ev) || result;
256        ev.offsetLocation(-mTempRect.left, -mTempRect.top);
257        return result;
258    }
259
260    @Override
261    protected void dispatchDraw(Canvas canvas) {
262        super.dispatchDraw(canvas);
263        if (mViewMediatorCallback != null) {
264            mViewMediatorCallback.keyguardDoneDrawing();
265        }
266    }
267
268    private int getWidgetPosition(int id) {
269        final int children = mAppWidgetContainer.getChildCount();
270        for (int i = 0; i < children; i++) {
271            if (mAppWidgetContainer.getWidgetPageAt(i).getContent().getId() == id) {
272                return i;
273            }
274        }
275        return -1;
276    }
277
278    @Override
279    protected void onFinishInflate() {
280        // Grab instances of and make any necessary changes to the main layouts. Create
281        // view state manager and wire up necessary listeners / callbacks.
282        View deleteDropTarget = findViewById(R.id.keyguard_widget_pager_delete_target);
283        mAppWidgetContainer = (KeyguardWidgetPager) findViewById(R.id.app_widget_container);
284        mAppWidgetContainer.setVisibility(VISIBLE);
285        mAppWidgetContainer.setCallbacks(mWidgetCallbacks);
286        mAppWidgetContainer.setDeleteDropTarget(deleteDropTarget);
287        mAppWidgetContainer.setMinScale(0.5f);
288
289        mSlidingChallengeLayout = (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
290        if (mSlidingChallengeLayout != null) {
291            mSlidingChallengeLayout.setOnChallengeScrolledListener(mViewStateManager);
292        }
293        mAppWidgetContainer.setViewStateManager(mViewStateManager);
294        mAppWidgetContainer.setLockPatternUtils(mLockPatternUtils);
295
296        ChallengeLayout challenge = mSlidingChallengeLayout != null ? mSlidingChallengeLayout :
297            (ChallengeLayout) findViewById(R.id.multi_pane_challenge);
298        challenge.setOnBouncerStateChangedListener(mViewStateManager);
299        mAppWidgetContainer.setBouncerAnimationDuration(challenge.getBouncerAnimationDuration());
300        mViewStateManager.setPagedView(mAppWidgetContainer);
301        mViewStateManager.setChallengeLayout(challenge);
302        mSecurityViewContainer = (KeyguardSecurityViewFlipper) findViewById(R.id.view_flipper);
303        mKeyguardSelectorView = (KeyguardSelectorView) findViewById(R.id.keyguard_selector_view);
304        mViewStateManager.setSecurityViewContainer(mSecurityViewContainer);
305
306        if (!(mContext instanceof Activity)) {
307            setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_BACK);
308        }
309
310        addDefaultWidgets();
311
312        addWidgetsFromSettings();
313        if (!shouldEnableAddWidget()) {
314            mAppWidgetContainer.setAddWidgetEnabled(false);
315        }
316        checkAppWidgetConsistency();
317        mSwitchPageRunnable.run();
318        // This needs to be called after the pages are all added.
319        mViewStateManager.showUsabilityHints();
320
321        showPrimarySecurityScreen(false);
322        updateSecurityViews();
323    }
324
325    private boolean shouldEnableAddWidget() {
326        return numWidgets() < MAX_WIDGETS && mUserSetupCompleted;
327    }
328
329    private int getDisabledFeatures(DevicePolicyManager dpm) {
330        int disabledFeatures = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
331        if (dpm != null) {
332            final int currentUser = mLockPatternUtils.getCurrentUser();
333            disabledFeatures = dpm.getKeyguardDisabledFeatures(null, currentUser);
334        }
335        return disabledFeatures;
336    }
337
338    private boolean widgetsDisabledByDpm() {
339        return (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL) != 0;
340    }
341
342    private boolean cameraDisabledByDpm() {
343        return mCameraDisabled
344                || (mDisabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) != 0;
345    }
346
347    private void updateSecurityViews() {
348        int children = mSecurityViewContainer.getChildCount();
349        for (int i = 0; i < children; i++) {
350            updateSecurityView(mSecurityViewContainer.getChildAt(i));
351        }
352    }
353
354    private void updateSecurityView(View view) {
355        if (view instanceof KeyguardSecurityView) {
356            KeyguardSecurityView ksv = (KeyguardSecurityView) view;
357            ksv.setKeyguardCallback(mCallback);
358            ksv.setLockPatternUtils(mLockPatternUtils);
359            if (mViewStateManager.isBouncing()) {
360                ksv.showBouncer(0);
361            } else {
362                ksv.hideBouncer(0);
363            }
364        } else {
365            Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
366        }
367    }
368
369    void setLockPatternUtils(LockPatternUtils utils) {
370        mSecurityModel.setLockPatternUtils(utils);
371        mLockPatternUtils = utils;
372        updateSecurityViews();
373    }
374
375    @Override
376    protected void onAttachedToWindow() {
377        super.onAttachedToWindow();
378        mAppWidgetHost.startListening();
379        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallbacks);
380    }
381
382    @Override
383    protected void onDetachedFromWindow() {
384        super.onDetachedFromWindow();
385        mAppWidgetHost.stopListening();
386        KeyguardUpdateMonitor.getInstance(mContext).removeCallback(mUpdateMonitorCallbacks);
387    }
388
389    void addWidget(AppWidgetHostView view, int pageIndex) {
390        mAppWidgetContainer.addWidget(view, pageIndex);
391    }
392
393    private KeyguardWidgetPager.Callbacks mWidgetCallbacks
394            = new KeyguardWidgetPager.Callbacks() {
395        @Override
396        public void userActivity() {
397            KeyguardHostView.this.userActivity();
398        }
399
400        @Override
401        public void onUserActivityTimeoutChanged() {
402            KeyguardHostView.this.onUserActivityTimeoutChanged();
403        }
404
405        @Override
406        public void onAddView(View v) {
407            if (!shouldEnableAddWidget()) {
408                mAppWidgetContainer.setAddWidgetEnabled(false);
409            }
410        }
411
412        @Override
413        public void onRemoveView(View v, boolean deletePermanently) {
414            if (deletePermanently) {
415                final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
416                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID &&
417                        appWidgetId != LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
418                    mAppWidgetHost.deleteAppWidgetId(appWidgetId);
419                }
420            }
421        }
422
423        @Override
424        public void onRemoveViewAnimationCompleted() {
425            if (shouldEnableAddWidget()) {
426                mAppWidgetContainer.setAddWidgetEnabled(true);
427            }
428        }
429    };
430
431    public void initializeSwitchingUserState(boolean switching) {
432        if (!switching && mKeyguardMultiUserSelectorView != null) {
433            mKeyguardMultiUserSelectorView.finalizeActiveUserView(false);
434        }
435    }
436
437    public void userActivity() {
438        if (mViewMediatorCallback != null) {
439            mViewMediatorCallback.userActivity();
440        }
441    }
442
443    public void onUserActivityTimeoutChanged() {
444        if (mViewMediatorCallback != null) {
445            mViewMediatorCallback.onUserActivityTimeoutChanged();
446        }
447    }
448
449    @Override
450    public long getUserActivityTimeout() {
451        // Currently only considering user activity timeouts needed by widgets.
452        // Could also take into account longer timeouts for certain security views.
453        if (mAppWidgetContainer != null) {
454            return mAppWidgetContainer.getUserActivityTimeout();
455        }
456        return -1;
457    }
458
459    private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
460
461        public void userActivity(long timeout) {
462            if (mViewMediatorCallback != null) {
463                mViewMediatorCallback.userActivity(timeout);
464            }
465        }
466
467        public void dismiss(boolean authenticated) {
468            showNextSecurityScreenOrFinish(authenticated);
469        }
470
471        public boolean isVerifyUnlockOnly() {
472            return mIsVerifyUnlockOnly;
473        }
474
475        public void reportSuccessfulUnlockAttempt() {
476            KeyguardUpdateMonitor.getInstance(mContext).clearFailedUnlockAttempts();
477            mLockPatternUtils.reportSuccessfulPasswordAttempt();
478        }
479
480        public void reportFailedUnlockAttempt() {
481            if (mCurrentSecuritySelection == SecurityMode.Biometric) {
482                KeyguardUpdateMonitor.getInstance(mContext).reportFailedBiometricUnlockAttempt();
483            } else {
484                KeyguardHostView.this.reportFailedUnlockAttempt();
485            }
486        }
487
488        public int getFailedAttempts() {
489            return KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
490        }
491
492        @Override
493        public void showBackupSecurity() {
494            KeyguardHostView.this.showBackupSecurityScreen();
495        }
496
497        @Override
498        public void setOnDismissAction(OnDismissAction action) {
499            KeyguardHostView.this.setOnDismissAction(action);
500        }
501
502    };
503
504    private void showDialog(String title, String message) {
505        final AlertDialog dialog = new AlertDialog.Builder(mContext)
506            .setTitle(title)
507            .setMessage(message)
508            .setNeutralButton(R.string.ok, null)
509            .create();
510        if (!(mContext instanceof Activity)) {
511            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
512        }
513        dialog.show();
514    }
515
516    private void showTimeoutDialog() {
517        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
518        int messageId = 0;
519
520        switch (mSecurityModel.getSecurityMode()) {
521            case Pattern:
522                messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
523                break;
524            case PIN:
525                messageId = R.string.kg_too_many_failed_pin_attempts_dialog_message;
526                break;
527            case Password:
528                messageId = R.string.kg_too_many_failed_password_attempts_dialog_message;
529                break;
530        }
531
532        if (messageId != 0) {
533            final String message = mContext.getString(messageId,
534                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(),
535                    timeoutInSeconds);
536            showDialog(null, message);
537        }
538    }
539
540    private void showAlmostAtWipeDialog(int attempts, int remaining) {
541        int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
542        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_wipe,
543                attempts, remaining);
544        showDialog(null, message);
545    }
546
547    private void showWipeDialog(int attempts) {
548        String message = mContext.getString(R.string.kg_failed_attempts_now_wiping, attempts);
549        showDialog(null, message);
550    }
551
552    private void showAlmostAtAccountLoginDialog() {
553        final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
554        final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
555                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
556        String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login,
557                count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
558        showDialog(null, message);
559    }
560
561    private void reportFailedUnlockAttempt() {
562        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
563        final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
564
565        if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
566
567        SecurityMode mode = mSecurityModel.getSecurityMode();
568        final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern;
569
570        final int failedAttemptsBeforeWipe = mLockPatternUtils.getDevicePolicyManager()
571                .getMaximumFailedPasswordsForWipe(null, mLockPatternUtils.getCurrentUser());
572
573        final int failedAttemptWarning = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
574                - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
575
576        final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
577                (failedAttemptsBeforeWipe - failedAttempts)
578                : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
579
580        boolean showTimeout = false;
581        if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
582            // If we reach this code, it means the user has installed a DevicePolicyManager
583            // that requests device wipe after N attempts.  Once we get below the grace
584            // period, we'll post this dialog every time as a clear warning until the
585            // bombshell hits and the device is wiped.
586            if (remainingBeforeWipe > 0) {
587                showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe);
588            } else {
589                // Too many attempts. The device will be wiped shortly.
590                Slog.i(TAG, "Too many unlock attempts; device will be wiped!");
591                showWipeDialog(failedAttempts);
592            }
593        } else {
594            showTimeout =
595                (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
596            if (usingPattern && mEnableFallback) {
597                if (failedAttempts == failedAttemptWarning) {
598                    showAlmostAtAccountLoginDialog();
599                    showTimeout = false; // don't show both dialogs
600                } else if (failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
601                    mLockPatternUtils.setPermanentlyLocked(true);
602                    showSecurityScreen(SecurityMode.Account);
603                    // don't show timeout dialog because we show account unlock screen next
604                    showTimeout = false;
605                }
606            }
607        }
608        monitor.reportFailedUnlockAttempt();
609        mLockPatternUtils.reportFailedPasswordAttempt();
610        if (showTimeout) {
611            showTimeoutDialog();
612        }
613    }
614
615    /**
616     * Shows the primary security screen for the user. This will be either the multi-selector
617     * or the user's security method.
618     * @param turningOff true if the device is being turned off
619     */
620    void showPrimarySecurityScreen(boolean turningOff) {
621        SecurityMode securityMode = mSecurityModel.getSecurityMode();
622        if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
623        if (!turningOff &&
624                KeyguardUpdateMonitor.getInstance(mContext).isAlternateUnlockEnabled()) {
625            // If we're not turning off, then allow biometric alternate.
626            // We'll reload it when the device comes back on.
627            securityMode = mSecurityModel.getAlternateFor(securityMode);
628        }
629        showSecurityScreen(securityMode);
630    }
631
632    /**
633     * Shows the backup security screen for the current security mode.  This could be used for
634     * password recovery screens but is currently only used for pattern unlock to show the
635     * account unlock screen and biometric unlock to show the user's normal unlock.
636     */
637    private void showBackupSecurityScreen() {
638        if (DEBUG) Log.d(TAG, "showBackupSecurity()");
639        SecurityMode backup = mSecurityModel.getBackupSecurityMode(mCurrentSecuritySelection);
640        showSecurityScreen(backup);
641    }
642
643    public boolean showNextSecurityScreenIfPresent() {
644        SecurityMode securityMode = mSecurityModel.getSecurityMode();
645        // Allow an alternate, such as biometric unlock
646        securityMode = mSecurityModel.getAlternateFor(securityMode);
647        if (SecurityMode.None == securityMode) {
648            return false;
649        } else {
650            showSecurityScreen(securityMode); // switch to the alternate security view
651            return true;
652        }
653    }
654
655    private void showNextSecurityScreenOrFinish(boolean authenticated) {
656        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
657        boolean finish = false;
658        if (SecurityMode.None == mCurrentSecuritySelection) {
659            SecurityMode securityMode = mSecurityModel.getSecurityMode();
660            // Allow an alternate, such as biometric unlock
661            securityMode = mSecurityModel.getAlternateFor(securityMode);
662            if (SecurityMode.None == securityMode) {
663                finish = true; // no security required
664            } else {
665                showSecurityScreen(securityMode); // switch to the alternate security view
666            }
667        } else if (authenticated) {
668            switch (mCurrentSecuritySelection) {
669                case Pattern:
670                case Password:
671                case PIN:
672                case Account:
673                case Biometric:
674                    finish = true;
675                    break;
676
677                case SimPin:
678                case SimPuk:
679                    // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
680                    SecurityMode securityMode = mSecurityModel.getSecurityMode();
681                    if (securityMode != SecurityMode.None) {
682                        showSecurityScreen(securityMode);
683                    } else {
684                        finish = true;
685                    }
686                    break;
687
688                default:
689                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
690                    showPrimarySecurityScreen(false);
691                    break;
692            }
693        } else {
694            showPrimarySecurityScreen(false);
695        }
696        if (finish) {
697            // If the alternate unlock was suppressed, it can now be safely
698            // enabled because the user has left keyguard.
699            KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
700
701            // If there's a pending runnable because the user interacted with a widget
702            // and we're leaving keyguard, then run it.
703            boolean deferKeyguardDone = false;
704            if (mDismissAction != null) {
705                deferKeyguardDone = mDismissAction.onDismiss();
706                mDismissAction = null;
707            }
708            if (mViewMediatorCallback != null) {
709                if (deferKeyguardDone) {
710                    mViewMediatorCallback.keyguardDonePending();
711                } else {
712                    mViewMediatorCallback.keyguardDone(true);
713                }
714            }
715        } else {
716            mViewStateManager.showBouncer(true);
717        }
718    }
719
720    private OnClickHandler mOnClickHandler = new OnClickHandler() {
721        @Override
722        public boolean onClickHandler(final View view,
723                final android.app.PendingIntent pendingIntent,
724                final Intent fillInIntent) {
725            if (pendingIntent.isActivity()) {
726                setOnDismissAction(new OnDismissAction() {
727                    public boolean onDismiss() {
728                        try {
729                              // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
730                              Context context = view.getContext();
731                              ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
732                                      0, 0,
733                                      view.getMeasuredWidth(), view.getMeasuredHeight());
734                              context.startIntentSender(
735                                      pendingIntent.getIntentSender(), fillInIntent,
736                                      Intent.FLAG_ACTIVITY_NEW_TASK,
737                                      Intent.FLAG_ACTIVITY_NEW_TASK, 0, opts.toBundle());
738                        } catch (IntentSender.SendIntentException e) {
739                            android.util.Log.e(TAG, "Cannot send pending intent: ", e);
740                        } catch (Exception e) {
741                            android.util.Log.e(TAG, "Cannot send pending intent due to " +
742                                    "unknown exception: ", e);
743                        }
744                        return false;
745                    }
746                });
747
748                if (mViewStateManager.isChallengeShowing()) {
749                    mViewStateManager.showBouncer(true);
750                } else {
751                    mCallback.dismiss(false);
752                }
753                return true;
754            } else {
755                return super.onClickHandler(view, pendingIntent, fillInIntent);
756            }
757        };
758    };
759
760    // Used to ignore callbacks from methods that are no longer current (e.g. face unlock).
761    // This avoids unwanted asynchronous events from messing with the state.
762    private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
763
764        @Override
765        public void userActivity(long timeout) {
766        }
767
768        @Override
769        public void showBackupSecurity() {
770        }
771
772        @Override
773        public void setOnDismissAction(OnDismissAction action) {
774        }
775
776        @Override
777        public void reportSuccessfulUnlockAttempt() {
778        }
779
780        @Override
781        public void reportFailedUnlockAttempt() {
782        }
783
784        @Override
785        public boolean isVerifyUnlockOnly() {
786            return false;
787        }
788
789        @Override
790        public int getFailedAttempts() {
791            return 0;
792        }
793
794        @Override
795        public void dismiss(boolean securityVerified) {
796        }
797    };
798
799    protected boolean mShowSecurityWhenReturn;
800
801    @Override
802    public void reset() {
803        mIsVerifyUnlockOnly = false;
804        mAppWidgetContainer.setCurrentPage(getWidgetPosition(R.id.keyguard_status_view));
805    }
806
807    /**
808     * Sets an action to perform when keyguard is dismissed.
809     * @param action
810     */
811    protected void setOnDismissAction(OnDismissAction action) {
812        mDismissAction = action;
813    }
814
815    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
816        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
817        KeyguardSecurityView view = null;
818        final int children = mSecurityViewContainer.getChildCount();
819        for (int child = 0; child < children; child++) {
820            if (mSecurityViewContainer.getChildAt(child).getId() == securityViewIdForMode) {
821                view = ((KeyguardSecurityView)mSecurityViewContainer.getChildAt(child));
822                break;
823            }
824        }
825        int layoutId = getLayoutIdFor(securityMode);
826        if (view == null && layoutId != 0) {
827            final LayoutInflater inflater = LayoutInflater.from(mContext);
828            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
829            View v = inflater.inflate(layoutId, mSecurityViewContainer, false);
830            mSecurityViewContainer.addView(v);
831            updateSecurityView(v);
832            view = (KeyguardSecurityView)v;
833        }
834
835        if (view instanceof KeyguardSelectorView) {
836            KeyguardSelectorView selectorView = (KeyguardSelectorView) view;
837            View carrierText = selectorView.findViewById(R.id.keyguard_selector_fade_container);
838            selectorView.setCarrierArea(carrierText);
839        }
840
841        return view;
842    }
843
844    /**
845     * Switches to the given security view unless it's already being shown, in which case
846     * this is a no-op.
847     *
848     * @param securityMode
849     */
850    private void showSecurityScreen(SecurityMode securityMode) {
851        if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
852
853        if (securityMode == mCurrentSecuritySelection) return;
854
855        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
856        KeyguardSecurityView newView = getSecurityView(securityMode);
857
858        // Enter full screen mode if we're in SIM or Account screen
859        boolean fullScreenEnabled = getResources().getBoolean(R.bool.kg_sim_puk_account_full_screen);
860        boolean isSimOrAccount = securityMode == SecurityMode.SimPin
861                || securityMode == SecurityMode.SimPuk
862                || securityMode == SecurityMode.Account;
863        mAppWidgetContainer.setVisibility(
864                isSimOrAccount && fullScreenEnabled ? View.GONE : View.VISIBLE);
865
866        if (mSlidingChallengeLayout != null) {
867            mSlidingChallengeLayout.setChallengeInteractive(!fullScreenEnabled);
868        }
869
870        // Emulate Activity life cycle
871        if (oldView != null) {
872            oldView.onPause();
873            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
874        }
875        newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
876        newView.setKeyguardCallback(mCallback);
877
878        final boolean needsInput = newView.needsInput();
879        if (mViewMediatorCallback != null) {
880            mViewMediatorCallback.setNeedsInput(needsInput);
881        }
882
883        // Find and show this child.
884        final int childCount = mSecurityViewContainer.getChildCount();
885
886        mSecurityViewContainer.setInAnimation(
887                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_in));
888        mSecurityViewContainer.setOutAnimation(
889                AnimationUtils.loadAnimation(mContext, R.anim.keyguard_security_fade_out));
890        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
891        for (int i = 0; i < childCount; i++) {
892            if (mSecurityViewContainer.getChildAt(i).getId() == securityViewIdForMode) {
893                mSecurityViewContainer.setDisplayedChild(i);
894                break;
895            }
896        }
897
898        if (securityMode == SecurityMode.None) {
899            // Discard current runnable if we're switching back to the selector view
900            setOnDismissAction(null);
901        }
902        mCurrentSecuritySelection = securityMode;
903    }
904
905    @Override
906    public void onScreenTurnedOn() {
907        if (DEBUG) Log.d(TAG, "screen on, instance " + Integer.toHexString(hashCode()));
908        showPrimarySecurityScreen(false);
909        getSecurityView(mCurrentSecuritySelection).onResume(KeyguardSecurityView.SCREEN_ON);
910
911        // This is a an attempt to fix bug 7137389 where the device comes back on but the entire
912        // layout is blank but forcing a layout causes it to reappear (e.g. with with
913        // hierarchyviewer).
914        requestLayout();
915
916        if (mViewStateManager != null) {
917            mViewStateManager.showUsabilityHints();
918        }
919        requestFocus();
920    }
921
922    @Override
923    public void onScreenTurnedOff() {
924        if (DEBUG) Log.d(TAG, String.format("screen off, instance %s at %s",
925                Integer.toHexString(hashCode()), SystemClock.uptimeMillis()));
926        // Once the screen turns off, we no longer consider this to be first boot and we want the
927        // biometric unlock to start next time keyguard is shown.
928        KeyguardUpdateMonitor.getInstance(mContext).setAlternateUnlockEnabled(true);
929        // We use mAppWidgetToShow to show a particular widget after you add it-- once the screen
930        // turns off we reset that behavior
931        clearAppWidgetToShow();
932        checkAppWidgetConsistency();
933        showPrimarySecurityScreen(true);
934        getSecurityView(mCurrentSecuritySelection).onPause();
935        CameraWidgetFrame cameraPage = findCameraPage();
936        if (cameraPage != null) {
937            cameraPage.onScreenTurnedOff();
938        }
939        clearFocus();
940    }
941
942    public void clearAppWidgetToShow() {
943        mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
944    }
945
946    @Override
947    public void show() {
948        if (DEBUG) Log.d(TAG, "show()");
949        showPrimarySecurityScreen(false);
950    }
951
952    private boolean isSecure() {
953        SecurityMode mode = mSecurityModel.getSecurityMode();
954        switch (mode) {
955            case Pattern:
956                return mLockPatternUtils.isLockPatternEnabled();
957            case Password:
958            case PIN:
959                return mLockPatternUtils.isLockPasswordEnabled();
960            case SimPin:
961            case SimPuk:
962            case Account:
963                return true;
964            case None:
965                return false;
966            default:
967                throw new IllegalStateException("Unknown security mode " + mode);
968        }
969    }
970
971    @Override
972    public void wakeWhenReadyTq(int keyCode) {
973        if (DEBUG) Log.d(TAG, "onWakeKey");
974        if (keyCode == KeyEvent.KEYCODE_MENU && isSecure()) {
975            if (DEBUG) Log.d(TAG, "switching screens to unlock screen because wake key was MENU");
976            showSecurityScreen(SecurityMode.None);
977        } else {
978            if (DEBUG) Log.d(TAG, "poking wake lock immediately");
979        }
980        if (mViewMediatorCallback != null) {
981            mViewMediatorCallback.wakeUp();
982        }
983    }
984
985    @Override
986    public void verifyUnlock() {
987        SecurityMode securityMode = mSecurityModel.getSecurityMode();
988        if (securityMode == KeyguardSecurityModel.SecurityMode.None) {
989            if (mViewMediatorCallback != null) {
990                mViewMediatorCallback.keyguardDone(true);
991            }
992        } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern
993                && securityMode != KeyguardSecurityModel.SecurityMode.PIN
994                && securityMode != KeyguardSecurityModel.SecurityMode.Password) {
995            // can only verify unlock when in pattern/password mode
996            if (mViewMediatorCallback != null) {
997                mViewMediatorCallback.keyguardDone(false);
998            }
999        } else {
1000            // otherwise, go to the unlock screen, see if they can verify it
1001            mIsVerifyUnlockOnly = true;
1002            showSecurityScreen(securityMode);
1003        }
1004    }
1005
1006    private int getSecurityViewIdForMode(SecurityMode securityMode) {
1007        switch (securityMode) {
1008            case None: return R.id.keyguard_selector_view;
1009            case Pattern: return R.id.keyguard_pattern_view;
1010            case PIN: return R.id.keyguard_pin_view;
1011            case Password: return R.id.keyguard_password_view;
1012            case Biometric: return R.id.keyguard_face_unlock_view;
1013            case Account: return R.id.keyguard_account_view;
1014            case SimPin: return R.id.keyguard_sim_pin_view;
1015            case SimPuk: return R.id.keyguard_sim_puk_view;
1016        }
1017        return 0;
1018    }
1019
1020    private int getLayoutIdFor(SecurityMode securityMode) {
1021        switch (securityMode) {
1022            case None: return R.layout.keyguard_selector_view;
1023            case Pattern: return R.layout.keyguard_pattern_view;
1024            case PIN: return R.layout.keyguard_pin_view;
1025            case Password: return R.layout.keyguard_password_view;
1026            case Biometric: return R.layout.keyguard_face_unlock_view;
1027            case Account: return R.layout.keyguard_account_view;
1028            case SimPin: return R.layout.keyguard_sim_pin_view;
1029            case SimPuk: return R.layout.keyguard_sim_puk_view;
1030            default:
1031                return 0;
1032        }
1033    }
1034
1035    private boolean addWidget(int appId, int pageIndex, boolean updateDbIfFailed) {
1036        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appId);
1037        if (appWidgetInfo != null) {
1038            AppWidgetHostView view = mAppWidgetHost.createView(mContext, appId, appWidgetInfo);
1039            addWidget(view, pageIndex);
1040            return true;
1041        } else {
1042            if (updateDbIfFailed) {
1043                Log.w(TAG, "*** AppWidgetInfo for app widget id " + appId + "  was null for user"
1044                        + mUserId + ", deleting");
1045                mAppWidgetHost.deleteAppWidgetId(appId);
1046                mLockPatternUtils.removeAppWidget(appId);
1047            }
1048            return false;
1049        }
1050    }
1051
1052    private final CameraWidgetFrame.Callbacks mCameraWidgetCallbacks =
1053        new CameraWidgetFrame.Callbacks() {
1054            @Override
1055            public void onLaunchingCamera() {
1056                setSliderHandleAlpha(0);
1057            }
1058
1059            @Override
1060            public void onCameraLaunchedSuccessfully() {
1061                if (mAppWidgetContainer.isCameraPage(mAppWidgetContainer.getCurrentPage())) {
1062                    mAppWidgetContainer.scrollLeft();
1063                }
1064                setSliderHandleAlpha(1);
1065                mShowSecurityWhenReturn = true;
1066            }
1067
1068            @Override
1069            public void onCameraLaunchedUnsuccessfully() {
1070                setSliderHandleAlpha(1);
1071            }
1072
1073            private void setSliderHandleAlpha(float alpha) {
1074                SlidingChallengeLayout slider =
1075                        (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
1076                if (slider != null) {
1077                    slider.setHandleAlpha(alpha);
1078                }
1079            }
1080        };
1081
1082    private final KeyguardActivityLauncher mActivityLauncher = new KeyguardActivityLauncher() {
1083        @Override
1084        Context getContext() {
1085            return mContext;
1086        }
1087
1088        @Override
1089        KeyguardSecurityCallback getCallback() {
1090            return mCallback;
1091        }
1092
1093        @Override
1094        LockPatternUtils getLockPatternUtils() {
1095            return mLockPatternUtils;
1096        }
1097    };
1098
1099    private int numWidgets() {
1100        final int childCount = mAppWidgetContainer.getChildCount();
1101        int widgetCount = 0;
1102        for (int i = 0; i < childCount; i++) {
1103            if (mAppWidgetContainer.isWidgetPage(i)) {
1104                widgetCount++;
1105            }
1106        }
1107        return widgetCount;
1108    }
1109
1110    private void addDefaultWidgets() {
1111        LayoutInflater inflater = LayoutInflater.from(mContext);
1112        inflater.inflate(R.layout.keyguard_transport_control_view, this, true);
1113
1114        if (!mSafeModeEnabled && !widgetsDisabledByDpm()) {
1115            View addWidget = inflater.inflate(R.layout.keyguard_add_widget, this, false);
1116            mAppWidgetContainer.addWidget(addWidget, 0);
1117            View addWidgetButton = addWidget.findViewById(R.id.keyguard_add_widget_view);
1118            addWidgetButton.setOnClickListener(new OnClickListener() {
1119                @Override
1120                public void onClick(View v) {
1121                    // Pass in an invalid widget id... the picker will allocate an ID for us
1122                    mActivityLauncher.launchWidgetPicker(AppWidgetManager.INVALID_APPWIDGET_ID);
1123                }
1124            });
1125        }
1126
1127        // We currently disable cameras in safe mode because we support loading 3rd party
1128        // cameras we can't trust.  TODO: plumb safe mode into camera creation code and only
1129        // inflate system-provided camera?
1130        if (!mSafeModeEnabled && !cameraDisabledByDpm() && mUserSetupCompleted
1131                && mContext.getResources().getBoolean(R.bool.kg_enable_camera_default_widget)) {
1132            View cameraWidget =
1133                    CameraWidgetFrame.create(mContext, mCameraWidgetCallbacks, mActivityLauncher);
1134            if (cameraWidget != null) {
1135                mAppWidgetContainer.addWidget(cameraWidget);
1136            }
1137        }
1138
1139        enableUserSelectorIfNecessary();
1140        initializeTransportControl();
1141    }
1142
1143    private boolean removeTransportFromWidgetPager() {
1144        int page = getWidgetPosition(R.id.keyguard_transport_control);
1145        if (page != -1) {
1146            mAppWidgetContainer.removeWidget(mTransportControl);
1147
1148            // XXX keep view attached so we still get show/hide events from AudioManager
1149            KeyguardHostView.this.addView(mTransportControl);
1150            mTransportControl.setVisibility(View.GONE);
1151            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_GONE);
1152            return true;
1153        }
1154        return false;
1155    }
1156
1157    private void addTransportToWidgetPager() {
1158        if (getWidgetPosition(R.id.keyguard_transport_control) == -1) {
1159            KeyguardHostView.this.removeView(mTransportControl);
1160            // insert to left of camera if it exists, otherwise after right-most widget
1161            int lastWidget = mAppWidgetContainer.getChildCount() - 1;
1162            int position = 0; // handle no widget case
1163            if (lastWidget >= 0) {
1164                position = mAppWidgetContainer.isCameraPage(lastWidget) ?
1165                        lastWidget : lastWidget + 1;
1166            }
1167            mAppWidgetContainer.addWidget(mTransportControl, position);
1168            mTransportControl.setVisibility(View.VISIBLE);
1169        }
1170    }
1171
1172    private void initializeTransportControl() {
1173        mTransportControl =
1174            (KeyguardTransportControlView) findViewById(R.id.keyguard_transport_control);
1175        mTransportControl.setVisibility(View.GONE);
1176
1177        // This code manages showing/hiding the transport control. We keep it around and only
1178        // add it to the hierarchy if it needs to be present.
1179        if (mTransportControl != null) {
1180            mTransportControl.setKeyguardCallback(new TransportCallback() {
1181                @Override
1182                public void onListenerDetached() {
1183                    if (removeTransportFromWidgetPager()) {
1184                        mTransportControl.post(mSwitchPageRunnable);
1185                    }
1186                }
1187
1188                @Override
1189                public void onListenerAttached() {
1190                    // Transport will be added when playstate changes...
1191                    mTransportControl.post(mSwitchPageRunnable);
1192                }
1193
1194                @Override
1195                public void onPlayStateChanged() {
1196                    mTransportControl.post(mSwitchPageRunnable);
1197                }
1198            });
1199        }
1200    }
1201
1202    private int getInsertPageIndex() {
1203        View addWidget = mAppWidgetContainer.findViewById(R.id.keyguard_add_widget);
1204        int insertionIndex = mAppWidgetContainer.indexOfChild(addWidget);
1205        if (insertionIndex < 0) {
1206            insertionIndex = 0; // no add widget page found
1207        } else {
1208            insertionIndex++; // place after add widget
1209        }
1210        return insertionIndex;
1211    }
1212
1213    private void addDefaultStatusWidget(int index) {
1214        LayoutInflater inflater = LayoutInflater.from(mContext);
1215        View statusWidget = inflater.inflate(R.layout.keyguard_status_view, null, true);
1216        mAppWidgetContainer.addWidget(statusWidget, index);
1217    }
1218
1219    private void addWidgetsFromSettings() {
1220        if (mSafeModeEnabled || widgetsDisabledByDpm()) {
1221            return;
1222        }
1223
1224        int insertionIndex = getInsertPageIndex();
1225
1226        // Add user-selected widget
1227        final int[] widgets = mLockPatternUtils.getAppWidgets();
1228
1229        if (widgets == null) {
1230            Log.d(TAG, "Problem reading widgets");
1231        } else {
1232            for (int i = widgets.length -1; i >= 0; i--) {
1233                if (widgets[i] == LockPatternUtils.ID_DEFAULT_STATUS_WIDGET) {
1234                    addDefaultStatusWidget(insertionIndex);
1235                } else {
1236                    // We add the widgets from left to right, starting after the first page after
1237                    // the add page. We count down, since the order will be persisted from right
1238                    // to left, starting after camera.
1239                    addWidget(widgets[i], insertionIndex, true);
1240                }
1241            }
1242        }
1243    }
1244
1245    private int allocateIdForDefaultAppWidget() {
1246        int appWidgetId;
1247        Resources res = getContext().getResources();
1248        ComponentName defaultAppWidget = new ComponentName(
1249                res.getString(R.string.widget_default_package_name),
1250                res.getString(R.string.widget_default_class_name));
1251
1252        // Note: we don't support configuring the widget
1253        appWidgetId = mAppWidgetHost.allocateAppWidgetId();
1254
1255        try {
1256            mAppWidgetManager.bindAppWidgetId(appWidgetId, defaultAppWidget);
1257
1258        } catch (IllegalArgumentException e) {
1259            Log.e(TAG, "Error when trying to bind default AppWidget: " + e);
1260            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
1261            appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
1262        }
1263        return appWidgetId;
1264    }
1265    public void checkAppWidgetConsistency() {
1266        // Since this method may bind a widget (which we can't do until boot completed) we
1267        // may have to defer it until after boot complete.
1268        if (!KeyguardUpdateMonitor.getInstance(mContext).hasBootCompleted()) {
1269            mCheckAppWidgetConsistencyOnBootCompleted = true;
1270            return;
1271        }
1272        final int childCount = mAppWidgetContainer.getChildCount();
1273        boolean widgetPageExists = false;
1274        for (int i = 0; i < childCount; i++) {
1275            if (mAppWidgetContainer.isWidgetPage(i)) {
1276                widgetPageExists = true;
1277                break;
1278            }
1279        }
1280        if (!widgetPageExists) {
1281            final int insertPageIndex = getInsertPageIndex();
1282
1283            final boolean userAddedWidgetsEnabled = !widgetsDisabledByDpm();
1284            boolean addedDefaultAppWidget = false;
1285
1286            if (!mSafeModeEnabled) {
1287                if (userAddedWidgetsEnabled) {
1288                    int appWidgetId = allocateIdForDefaultAppWidget();
1289                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1290                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, true);
1291                    }
1292                } else {
1293                    // note: even if widgetsDisabledByDpm() returns true, we still bind/create
1294                    // the default appwidget if possible
1295                    int appWidgetId = mLockPatternUtils.getFallbackAppWidgetId();
1296                    if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
1297                        appWidgetId = allocateIdForDefaultAppWidget();
1298                        if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1299                            mLockPatternUtils.writeFallbackAppWidgetId(appWidgetId);
1300                        }
1301                    }
1302                    if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
1303                        addedDefaultAppWidget = addWidget(appWidgetId, insertPageIndex, false);
1304                        if (!addedDefaultAppWidget) {
1305                            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
1306                            mLockPatternUtils.writeFallbackAppWidgetId(
1307                                    AppWidgetManager.INVALID_APPWIDGET_ID);
1308                        }
1309                    }
1310                }
1311            }
1312
1313            // Use the built-in status/clock view if we can't inflate the default widget
1314            if (!addedDefaultAppWidget) {
1315                addDefaultStatusWidget(insertPageIndex);
1316            }
1317
1318            // trigger DB updates only if user-added widgets are enabled
1319            if (!mSafeModeEnabled && userAddedWidgetsEnabled) {
1320                mAppWidgetContainer.onAddView(
1321                        mAppWidgetContainer.getChildAt(insertPageIndex), insertPageIndex);
1322            }
1323        }
1324    }
1325
1326    Runnable mSwitchPageRunnable = new Runnable() {
1327        @Override
1328        public void run() {
1329           showAppropriateWidgetPage();
1330        }
1331    };
1332
1333    static class SavedState extends BaseSavedState {
1334        int transportState;
1335        int appWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
1336
1337        SavedState(Parcelable superState) {
1338            super(superState);
1339        }
1340
1341        private SavedState(Parcel in) {
1342            super(in);
1343            this.transportState = in.readInt();
1344            this.appWidgetToShow = in.readInt();
1345        }
1346
1347        @Override
1348        public void writeToParcel(Parcel out, int flags) {
1349            super.writeToParcel(out, flags);
1350            out.writeInt(this.transportState);
1351            out.writeInt(this.appWidgetToShow);
1352        }
1353
1354        public static final Parcelable.Creator<SavedState> CREATOR
1355                = new Parcelable.Creator<SavedState>() {
1356            public SavedState createFromParcel(Parcel in) {
1357                return new SavedState(in);
1358            }
1359
1360            public SavedState[] newArray(int size) {
1361                return new SavedState[size];
1362            }
1363        };
1364    }
1365
1366    @Override
1367    public Parcelable onSaveInstanceState() {
1368        if (DEBUG) Log.d(TAG, "onSaveInstanceState");
1369        Parcelable superState = super.onSaveInstanceState();
1370        SavedState ss = new SavedState(superState);
1371        ss.transportState = mViewStateManager.getTransportState();
1372        ss.appWidgetToShow = mAppWidgetToShow;
1373        return ss;
1374    }
1375
1376    @Override
1377    public void onRestoreInstanceState(Parcelable state) {
1378        if (DEBUG) Log.d(TAG, "onRestoreInstanceState");
1379        if (!(state instanceof SavedState)) {
1380            super.onRestoreInstanceState(state);
1381            return;
1382        }
1383        SavedState ss = (SavedState) state;
1384        super.onRestoreInstanceState(ss.getSuperState());
1385        mViewStateManager.setTransportState(ss.transportState);
1386        mAppWidgetToShow = ss.appWidgetToShow;
1387        post(mSwitchPageRunnable);
1388    }
1389
1390    @Override
1391    public void onWindowFocusChanged(boolean hasWindowFocus) {
1392        super.onWindowFocusChanged(hasWindowFocus);
1393        if (DEBUG) Log.d(TAG, "Window is " + (hasWindowFocus ? "focused" : "unfocused"));
1394        if (hasWindowFocus && mShowSecurityWhenReturn) {
1395            SlidingChallengeLayout slider =
1396                (SlidingChallengeLayout) findViewById(R.id.sliding_layout);
1397            if (slider != null) {
1398                slider.setHandleAlpha(1);
1399                slider.showChallenge(true);
1400            }
1401            mShowSecurityWhenReturn = false;
1402        }
1403    }
1404
1405    private void showAppropriateWidgetPage() {
1406        int state = mViewStateManager.getTransportState();
1407        boolean isMusicPlaying = mTransportControl.isMusicPlaying()
1408                || state == KeyguardViewStateManager.TRANSPORT_VISIBLE;
1409        if (isMusicPlaying) {
1410            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_VISIBLE);
1411            addTransportToWidgetPager();
1412        } else if (state == KeyguardViewStateManager.TRANSPORT_VISIBLE) {
1413            mViewStateManager.setTransportState(KeyguardViewStateManager.TRANSPORT_INVISIBLE);
1414        }
1415        int pageToShow = getAppropriateWidgetPage(isMusicPlaying);
1416        mAppWidgetContainer.setCurrentPage(pageToShow);
1417    }
1418
1419    private CameraWidgetFrame findCameraPage() {
1420        for (int i = mAppWidgetContainer.getChildCount() - 1; i >= 0; i--) {
1421            if (mAppWidgetContainer.isCameraPage(i)) {
1422                return (CameraWidgetFrame) mAppWidgetContainer.getChildAt(i);
1423            }
1424        }
1425        return null;
1426    }
1427
1428    boolean isMusicPage(int pageIndex) {
1429        return pageIndex >= 0 && pageIndex == getWidgetPosition(R.id.keyguard_transport_control);
1430    }
1431
1432    private int getAppropriateWidgetPage(boolean isMusicPlaying) {
1433        // assumes at least one widget (besides camera + add)
1434        if (mAppWidgetToShow != AppWidgetManager.INVALID_APPWIDGET_ID) {
1435            final int childCount = mAppWidgetContainer.getChildCount();
1436            for (int i = 0; i < childCount; i++) {
1437                if (mAppWidgetContainer.getWidgetPageAt(i).getContentAppWidgetId()
1438                        == mAppWidgetToShow) {
1439                    return i;
1440                }
1441            }
1442            mAppWidgetToShow = AppWidgetManager.INVALID_APPWIDGET_ID;
1443        }
1444        // if music playing, show transport
1445        if (isMusicPlaying) {
1446            if (DEBUG) Log.d(TAG, "Music playing, show transport");
1447            return mAppWidgetContainer.getWidgetPageIndex(mTransportControl);
1448        }
1449
1450        // else show the right-most widget (except for camera)
1451        int rightMost = mAppWidgetContainer.getChildCount() - 1;
1452        if (mAppWidgetContainer.isCameraPage(rightMost)) {
1453            rightMost--;
1454        }
1455        if (DEBUG) Log.d(TAG, "Show right-most page " + rightMost);
1456        return rightMost;
1457    }
1458
1459    private void enableUserSelectorIfNecessary() {
1460        if (!UserManager.supportsMultipleUsers()) {
1461            return; // device doesn't support multi-user mode
1462        }
1463        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1464        if (um == null) {
1465            Throwable t = new Throwable();
1466            t.fillInStackTrace();
1467            Log.e(TAG, "user service is null.", t);
1468            return;
1469        }
1470
1471        // if there are multiple users, we need to enable to multi-user switcher
1472        final List<UserInfo> users = um.getUsers(true);
1473        if (users == null) {
1474            Throwable t = new Throwable();
1475            t.fillInStackTrace();
1476            Log.e(TAG, "list of users is null.", t);
1477            return;
1478        }
1479
1480        final View multiUserView = findViewById(R.id.keyguard_user_selector);
1481        if (multiUserView == null) {
1482            Throwable t = new Throwable();
1483            t.fillInStackTrace();
1484            Log.e(TAG, "can't find user_selector in layout.", t);
1485            return;
1486        }
1487
1488        if (users.size() > 1) {
1489            if (multiUserView instanceof KeyguardMultiUserSelectorView) {
1490                mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
1491                mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
1492                mKeyguardMultiUserSelectorView.addUsers(users);
1493                UserSwitcherCallback callback = new UserSwitcherCallback() {
1494                    @Override
1495                    public void hideSecurityView(int duration) {
1496                        mSecurityViewContainer.animate().alpha(0).setDuration(duration);
1497                    }
1498
1499                    @Override
1500                    public void showSecurityView() {
1501                        mSecurityViewContainer.setAlpha(1.0f);
1502                    }
1503
1504                    @Override
1505                    public void showUnlockHint() {
1506                        if (mKeyguardSelectorView != null) {
1507                            mKeyguardSelectorView.showUsabilityHint();
1508                        }
1509                    }
1510
1511                    @Override
1512                    public void userActivity() {
1513                        if (mViewMediatorCallback != null) {
1514                            mViewMediatorCallback.userActivity();
1515                        }
1516                    }
1517                };
1518                mKeyguardMultiUserSelectorView.setCallback(callback);
1519            } else {
1520                Throwable t = new Throwable();
1521                t.fillInStackTrace();
1522                if (multiUserView == null) {
1523                    Log.e(TAG, "could not find the user_selector.", t);
1524                } else {
1525                    Log.e(TAG, "user_selector is the wrong type.", t);
1526                }
1527            }
1528        }
1529    }
1530
1531    @Override
1532    public void cleanUp() {
1533
1534    }
1535
1536    /**
1537     * In general, we enable unlocking the insecure keyguard with the menu key. However, there are
1538     * some cases where we wish to disable it, notably when the menu button placement or technology
1539     * is prone to false positives.
1540     *
1541     * @return true if the menu key should be enabled
1542     */
1543    private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
1544    private boolean shouldEnableMenuKey() {
1545        final Resources res = getResources();
1546        final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
1547        final boolean isTestHarness = ActivityManager.isRunningInTestHarness();
1548        final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
1549        return !configDisabled || isTestHarness || fileOverride;
1550    }
1551
1552    public void goToWidget(int appWidgetId) {
1553        mAppWidgetToShow = appWidgetId;
1554        mSwitchPageRunnable.run();
1555    }
1556
1557    public boolean handleMenuKey() {
1558        // The following enables the MENU key to work for testing automation
1559        if (shouldEnableMenuKey()) {
1560            showNextSecurityScreenOrFinish(false);
1561            return true;
1562        }
1563        return false;
1564    }
1565
1566    public boolean handleBackKey() {
1567        if (mCurrentSecuritySelection != SecurityMode.None) {
1568            mCallback.dismiss(false);
1569            return true;
1570        }
1571        return false;
1572    }
1573
1574    /**
1575     *  Dismisses the keyguard by going to the next screen or making it gone.
1576     */
1577    public void dismiss() {
1578        showNextSecurityScreenOrFinish(false);
1579    }
1580
1581    public void showAssistant() {
1582        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
1583          .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
1584
1585        if (intent == null) return;
1586
1587        final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
1588                R.anim.keyguard_action_assist_enter, R.anim.keyguard_action_assist_exit,
1589                getHandler(), null);
1590
1591        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1592
1593        mActivityLauncher.launchActivityWithAnimation(
1594                intent, false, opts.toBundle(), null, null);
1595    }
1596}
1597