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