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