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