Phone: Display message to indicate PIN/PUK status changes.

Changes done to display retry counter on wrong entry of PIN1,
and message to indicate Code accepted/PIN1 blocked during
PIN1 verification as per certain carrier requirements.
PhoneApp: Add APIs that report actual error code on PIN/PUK operations
The current APIs that are used to verify the PIN and PUK only convey
whether the operation succeeded or failed. As a result on ANY failure
clients ask the user to re-enter the PIN.
Add 2 new APIs that report the actual error code in case of failure.

Bug: 9928717
Change-Id: I73718c9e6a8aa7244097e0dd4593a6226ff0ac08
diff --git a/src/com/android/phone/EditFdnContactScreen.java b/src/com/android/phone/EditFdnContactScreen.java
index 2992b7d..753ae3f 100644
--- a/src/com/android/phone/EditFdnContactScreen.java
+++ b/src/com/android/phone/EditFdnContactScreen.java
@@ -47,6 +47,9 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+
 /**
  * Activity to let the user add or edit an FDN contact.
  */
@@ -377,9 +380,15 @@
             if (invalidNumber) {
                 showStatus(getResources().getText(R.string.fdn_invalid_number));
             } else {
-                // There's no way to know whether the failure is due to incorrect PIN2 or
-                // an inappropriate phone number.
-                showStatus(getResources().getText(R.string.pin2_or_fdn_invalid));
+               if (PhoneFactory.getDefaultPhone().getIccCard().getIccPin2Blocked()) {
+                    showStatus(getResources().getText(R.string.fdn_enable_puk2_requested));
+                } else if (PhoneFactory.getDefaultPhone().getIccCard().getIccPuk2Blocked()) {
+                    showStatus(getResources().getText(R.string.puk2_blocked));
+                } else {
+                    // There's no way to know whether the failure is due to incorrect PIN2 or
+                    // an inappropriate phone number.
+                    showStatus(getResources().getText(R.string.pin2_or_fdn_invalid));
+                }
             }
         }
 
diff --git a/src/com/android/phone/FdnSetting.java b/src/com/android/phone/FdnSetting.java
index 283d612..a471093 100644
--- a/src/com/android/phone/FdnSetting.java
+++ b/src/com/android/phone/FdnSetting.java
@@ -243,16 +243,25 @@
                 // a toast, or just update the UI.
                 case EVENT_PIN2_ENTRY_COMPLETE: {
                         AsyncResult ar = (AsyncResult) msg.obj;
-                        if (ar.exception != null) {
+                        if (ar.exception != null && ar.exception instanceof CommandException) {
+                            int attemptsRemaining = msg.arg1;
                             // see if PUK2 is requested and alert the user accordingly.
-                            CommandException ce = (CommandException) ar.exception;
-                            if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
-                                // make sure we set the PUK2 state so that we can skip
-                                // some redundant behaviour.
-                                displayMessage(R.string.fdn_enable_puk2_requested);
-                                resetPinChangeStateForPUK2();
-                            } else {
-                                displayMessage(R.string.pin2_invalid);
+                            CommandException.Error e =
+                                    ((CommandException) ar.exception).getCommandError();
+                            switch (e) {
+                                case SIM_PUK2:
+                                    // make sure we set the PUK2 state so that we can skip
+                                    // some redundant behaviour.
+                                    displayMessage(R.string.fdn_enable_puk2_requested,
+                                            attemptsRemaining);
+                                    resetPinChangeStateForPUK2();
+                                    break;
+                                case PASSWORD_INCORRECT:
+                                    displayMessage(R.string.pin2_invalid, attemptsRemaining);
+                                    break;
+                                default:
+                                    displayMessage(R.string.fdn_failed, attemptsRemaining);
+                                    break;
                             }
                         }
                         updateEnableFDN();
@@ -267,6 +276,9 @@
                             log("Handle EVENT_PIN2_CHANGE_COMPLETE");
                         AsyncResult ar = (AsyncResult) msg.obj;
                         if (ar.exception != null) {
+                            int attemptsRemaining = msg.arg1;
+                            log("Handle EVENT_PIN2_CHANGE_COMPLETE attemptsRemaining="
+                                    + attemptsRemaining);
                             CommandException ce = (CommandException) ar.exception;
                             if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
                                 // throw an alert dialog on the screen, displaying the
@@ -284,16 +296,21 @@
                                 // set the correct error message depending upon the state.
                                 // Reset the state depending upon or knowledge of the PUK state.
                                 if (!mIsPuk2Locked) {
-                                    displayMessage(R.string.badPin2);
+                                    displayMessage(R.string.badPin2, attemptsRemaining);
                                     resetPinChangeState();
                                 } else {
-                                    displayMessage(R.string.badPuk2);
+                                    displayMessage(R.string.badPuk2, attemptsRemaining);
                                     resetPinChangeStateForPUK2();
                                 }
                             }
                         } else {
+                            if (mPinChangeState == PIN_CHANGE_PUK) {
+                                displayMessage(R.string.pin2_unblocked);
+                            } else {
+                                displayMessage(R.string.pin2_changed);
+                            }
+
                             // reset to normal behaviour on successful change.
-                            displayMessage(R.string.pin2_changed);
                             resetPinChangeState();
                         }
                     }
@@ -315,9 +332,22 @@
     /**
      * Display a toast for message, like the rest of the settings.
      */
+    private final void displayMessage(int strId, int attemptsRemaining) {
+        String s = getString(strId);
+        if ((strId == R.string.badPin2) || (strId == R.string.badPuk2) ||
+                (strId == R.string.pin2_invalid)) {
+            if (attemptsRemaining >= 0) {
+                s = getString(strId) + getString(R.string.pin2_attempts, attemptsRemaining);
+            } else {
+                s = getString(strId);
+            }
+        }
+        log("displayMessage: attemptsRemaining=" + attemptsRemaining + " s=" + s);
+        Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
+    }
+
     private final void displayMessage(int strId) {
-        Toast.makeText(this, getString(strId), Toast.LENGTH_SHORT)
-            .show();
+        displayMessage(strId, -1);
     }
 
     /**
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 1ce46b2..82b5e9f 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -43,6 +43,7 @@
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.CallManager;
+import com.android.internal.telephony.CommandException;
 import com.android.internal.telephony.PhoneConstants;
 
 import java.util.List;
@@ -423,13 +424,25 @@
     }
 
     public boolean supplyPin(String pin) {
+        int [] resultArray = supplyPinReportResult(pin);
+        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
+    }
+
+    public boolean supplyPuk(String puk, String pin) {
+        int [] resultArray = supplyPukReportResult(puk, pin);
+        return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
+    }
+
+    /** {@hide} */
+    public int[] supplyPinReportResult(String pin) {
         enforceModifyPermission();
         final UnlockSim checkSimPin = new UnlockSim(mPhone.getIccCard());
         checkSimPin.start();
         return checkSimPin.unlockSim(null, pin);
     }
 
-    public boolean supplyPuk(String puk, String pin) {
+    /** {@hide} */
+    public int[] supplyPukReportResult(String puk, String pin) {
         enforceModifyPermission();
         final UnlockSim checkSimPuk = new UnlockSim(mPhone.getIccCard());
         checkSimPuk.start();
@@ -437,7 +450,7 @@
     }
 
     /**
-     * Helper thread to turn async call to {@link SimCard#supplyPin} into
+     * Helper thread to turn async call to SimCard#supplyPin into
      * a synchronous one.
      */
     private static class UnlockSim extends Thread {
@@ -445,7 +458,8 @@
         private final IccCard mSimCard;
 
         private boolean mDone = false;
-        private boolean mResult = false;
+        private int mResult = PhoneConstants.PIN_GENERAL_FAILURE;
+        private int mRetryCount = -1;
 
         // For replies from SimCard interface
         private Handler mHandler;
@@ -469,7 +483,18 @@
                             case SUPPLY_PIN_COMPLETE:
                                 Log.d(LOG_TAG, "SUPPLY_PIN_COMPLETE");
                                 synchronized (UnlockSim.this) {
-                                    mResult = (ar.exception == null);
+                                    mRetryCount = msg.arg1;
+                                    if (ar.exception != null) {
+                                        if (ar.exception instanceof CommandException &&
+                                                ((CommandException)(ar.exception)).getCommandError()
+                                                == CommandException.Error.PASSWORD_INCORRECT) {
+                                            mResult = PhoneConstants.PIN_PASSWORD_INCORRECT;
+                                        } else {
+                                            mResult = PhoneConstants.PIN_GENERAL_FAILURE;
+                                        }
+                                    } else {
+                                        mResult = PhoneConstants.PIN_RESULT_SUCCESS;
+                                    }
                                     mDone = true;
                                     UnlockSim.this.notifyAll();
                                 }
@@ -489,7 +514,7 @@
          *
          * If PUK is not null, unlock SIM card with PUK and set PIN code
          */
-        synchronized boolean unlockSim(String puk, String pin) {
+        synchronized int[] unlockSim(String puk, String pin) {
 
             while (mHandler == null) {
                 try {
@@ -516,7 +541,10 @@
                 }
             }
             Log.d(LOG_TAG, "done");
-            return mResult;
+            int[] resultArray = new int[2];
+            resultArray[0] = mResult;
+            resultArray[1] = mRetryCount;
+            return resultArray;
         }
     }