Added a message to the keyguard bouncer

A message can now be shown on the keyguard bouncer
explaining why the bouncer is being shown.

Bug: 21618072
Change-Id: I25aea9cc242abbf6a133fb42cc4407f5c2f3f688
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index aa99a7b..0c6837f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -216,6 +216,19 @@
         return mCallback;
     }
 
+    @Override
+    public void showPromptReason(int reason) {
+        if (reason != PROMPT_REASON_NONE) {
+            int promtReasonStringRes = getPromtReasonStringRes(reason);
+            if (promtReasonStringRes != 0) {
+                mSecurityMessageDisplay.setMessage(promtReasonStringRes,
+                        true /* important */);
+            }
+        }
+    }
+
+    protected abstract int getPromtReasonStringRes(int reason);
+
     // Cause a VIRTUAL_KEY vibration
     public void doHapticKeyClick() {
         if (mEnableHaptics) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index cd4b24a..ff4e815 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -160,6 +160,17 @@
     }
 
     /**
+     * Show a string explaining why the security view needs to be solved.
+     *
+     * @param reason a flag indicating which string should be shown, see
+     *               {@link KeyguardSecurityView#PROMPT_REASON_NONE}
+     *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
+     */
+    public void showPromptReason(int reason) {
+        mSecurityContainer.showPromptReason(reason);
+    }
+
+    /**
      *  Dismisses the keyguard by going to the next screen or making it gone.
      *
      *  @return True if the keyguard is done.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index c9ad728..2db87b3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -111,6 +111,16 @@
     }
 
     @Override
+    protected int getPromtReasonStringRes(int reason) {
+        switch (reason) {
+            case PROMPT_REASON_RESTART:
+                return R.string.kg_prompt_reason_restart_password;
+            default:
+                return 0;
+        }
+    }
+
+    @Override
     public void onPause() {
         super.onPause();
         mImm.hideSoftInputFromWindow(getWindowToken(), 0);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 1bd0bb4..59a8ad5 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -85,10 +85,9 @@
         }
     };
     private Rect mTempRect = new Rect();
-    private SecurityMessageDisplay mSecurityMessageDisplay;
+    private KeyguardMessageArea mSecurityMessageDisplay;
     private View mEcaView;
     private ViewGroup mContainer;
-    private KeyguardMessageArea mHelpMessage;
     private int mDisappearYTranslation;
 
     enum FooterMode {
@@ -141,10 +140,10 @@
         // vibrate mode will be the same for the life of this screen
         mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
 
-        mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
+        mSecurityMessageDisplay =
+                (KeyguardMessageArea) KeyguardMessageArea.findSecurityMessageDisplay(this);
         mEcaView = findViewById(R.id.keyguard_selector_fade_container);
         mContainer = (ViewGroup) findViewById(R.id.container);
-        mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area);
 
         EmergencyButton button = (EmergencyButton) findViewById(R.id.emergency_call_button);
         if (button != null) {
@@ -320,6 +319,17 @@
     }
 
     @Override
+    public void showPromptReason(int reason) {
+        switch (reason) {
+            case PROMPT_REASON_RESTART:
+                mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern,
+                        true /* important */);
+                break;
+            default:
+        }
+    }
+
+    @Override
     public void startAppearAnimation() {
         enableClipping(false);
         setAlpha(1f);
@@ -337,8 +347,8 @@
                     }
                 },
                 this);
-        if (!TextUtils.isEmpty(mHelpMessage.getText())) {
-            mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
+        if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
+            mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
                     AppearAnimationUtils.DEFAULT_APPEAR_DURATION,
                     mAppearAnimationUtils.getStartTranslation(),
                     true /* appearing */,
@@ -366,8 +376,8 @@
                         }
                     }
                 }, KeyguardPatternView.this);
-        if (!TextUtils.isEmpty(mHelpMessage.getText())) {
-            mDisappearAnimationUtils.createAnimation(mHelpMessage, 0,
+        if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
+            mDisappearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
                     200,
                     - mDisappearAnimationUtils.getStartTranslation() * 3,
                     false /* appearing */,
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 23834a3..07947b1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -93,6 +93,16 @@
         return super.onKeyDown(keyCode, event);
     }
 
+    @Override
+    protected int getPromtReasonStringRes(int reason) {
+        switch (reason) {
+            case PROMPT_REASON_RESTART:
+                return R.string.kg_prompt_reason_restart_pin;
+            default:
+                return 0;
+        }
+    }
+
     private void performClick(View view) {
         view.performClick();
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index d17b25a..f529ac0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -509,6 +509,13 @@
     }
 
     @Override
+    public void showPromptReason(int reason) {
+        if (mCurrentSecuritySelection != SecurityMode.None) {
+            getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
+        }
+    }
+
+    @Override
     public void showUsabilityHint() {
         mSecurityViewFlipper.showUsabilityHint();
     }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
index 5b50236..5658a74 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java
@@ -21,6 +21,9 @@
     static public final int SCREEN_ON = 1;
     static public final int VIEW_REVEALED = 2;
 
+    int PROMPT_REASON_NONE = 0;
+    int PROMPT_REASON_RESTART = 1;
+
     /**
      * Interface back to keyguard to tell it when security
      * @param callback
@@ -66,6 +69,14 @@
     KeyguardSecurityCallback getCallback();
 
     /**
+     * Show a string explaining why the security view needs to be solved.
+     *
+     * @param reason a flag indicating which string should be shown, see {@link #PROMPT_REASON_NONE}
+     *               and {@link #PROMPT_REASON_RESTART}
+     */
+    void showPromptReason(int reason);
+
+    /**
      * Instruct the view to show usability hints, if any.
      *
      */
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index 54467f3..a0ff21b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -131,6 +131,14 @@
     }
 
     @Override
+    public void showPromptReason(int reason) {
+        KeyguardSecurityView ksv = getSecurityView();
+        if (ksv != null) {
+            ksv.showPromptReason(reason);
+        }
+    }
+
+    @Override
     public void showUsabilityHint() {
         KeyguardSecurityView ksv = getSecurityView();
         if (ksv != null) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index f4acff8..aeac912 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -95,6 +95,12 @@
         }
     }
 
+    @Override
+    protected int getPromtReasonStringRes(int reason) {
+        // No message on SIM Pin
+        return 0;
+    }
+
     private String getPinPasswordErrorMessage(int attemptsRemaining) {
         String displayMessage;
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
index b85d966..af88239 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPukView.java
@@ -140,6 +140,12 @@
         }
     }
 
+    @Override
+    protected int getPromtReasonStringRes(int reason) {
+        // No message on SIM Puk
+        return 0;
+    }
+
     private String getPukPasswordErrorMessage(int attemptsRemaining) {
         String displayMessage;
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 273f166..022338d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -804,8 +804,7 @@
     private void startListeningForFingerprint() {
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
         int userId = ActivityManager.getCurrentUser();
-        if (mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
-                && mFpm.getEnrolledFingerprints(userId).size() > 0) {
+        if (isUnlockWithFingerPrintPossible(userId)) {
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
             }
@@ -815,6 +814,11 @@
         }
     }
 
+    public boolean isUnlockWithFingerPrintPossible(int userId) {
+        return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
+                && mFpm.getEnrolledFingerprints(userId).size() > 0;
+    }
+
     private void stopListeningForFingerprint() {
         if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
         if (isFingerprintDetectionRunning()) {
diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
index f5c809a..ff463c6 100644
--- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java
@@ -81,4 +81,12 @@
      * @return true if the screen is on
      */
     boolean isScreenOn();
+
+    /**
+     * @return one of the reasons why the bouncer needs to be shown right now and the user can't use
+     *         his normal unlock method like fingerprint or trust agents. See
+     *         {@link KeyguardSecurityView#PROMPT_REASON_NONE}
+     *         and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}.
+     */
+    int getBouncerPromptReason();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c06b34f..80761d8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -62,6 +62,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardConstants;
 import com.android.keyguard.KeyguardDisplayManager;
+import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
@@ -526,6 +527,17 @@
         public boolean isScreenOn() {
             return mDeviceInteractive;
         }
+
+        @Override
+        public int getBouncerPromptReason() {
+            int currentUser = ActivityManager.getCurrentUser();
+            if ((mUpdateMonitor.getUserTrustIsManaged(currentUser)
+                    || mUpdateMonitor.isUnlockWithFingerPrintPossible(currentUser))
+                    && !mTrustManager.hasUserAuthenticatedSinceBoot(currentUser)) {
+                return KeyguardSecurityView.PROMPT_REASON_RESTART;
+            }
+            return KeyguardSecurityView.PROMPT_REASON_NONE;
+        }
     };
 
     public void userActivity() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 3737d05..a3bb129 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -26,6 +26,7 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardHostView;
+import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.R;
 import com.android.keyguard.ViewMediatorCallback;
 
@@ -46,6 +47,7 @@
     private ViewGroup mRoot;
     private boolean mShowingSoon;
     private Choreographer mChoreographer = Choreographer.getInstance();
+    private int mBouncerPromptReason;
 
     public KeyguardBouncer(Context context, ViewMediatorCallback callback,
             LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
@@ -68,6 +70,8 @@
             return;
         }
 
+        mBouncerPromptReason = mCallback.getBouncerPromptReason();
+
         // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
         // Keyguard. If we need to authenticate, show the bouncer.
         if (!mKeyguardView.dismiss()) {
@@ -84,12 +88,24 @@
         public void run() {
             mRoot.setVisibility(View.VISIBLE);
             mKeyguardView.onResume();
+            showPromptReason(mBouncerPromptReason);
             mKeyguardView.startAppearAnimation();
             mShowingSoon = false;
             mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
     };
 
+    /**
+     * Show a string explaining why the security view needs to be solved.
+     *
+     * @param reason a flag indicating which string should be shown, see
+     *               {@link KeyguardSecurityView#PROMPT_REASON_NONE}
+     *               and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}
+     */
+    public void showPromptReason(int reason) {
+        mKeyguardView.showPromptReason(reason);
+    }
+
     private void cancelShowRunnable() {
         mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mShowRunnable, null);
         mShowingSoon = false;