Blanket copy of PhoneApp to services/Telephony.

First phase of splitting out InCallUI from PhoneApp.

Change-Id: I237341c4ff00e96c677caa4580b251ef3432931b
diff --git a/src/com/android/phone/ChangeIccPinScreen.java b/src/com/android/phone/ChangeIccPinScreen.java
new file mode 100644
index 0000000..70bf431
--- /dev/null
+++ b/src/com/android/phone/ChangeIccPinScreen.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.text.method.DigitsKeyListener;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.Phone;
+
+/**
+ * "Change ICC PIN" UI for the Phone app.
+ */
+public class ChangeIccPinScreen extends Activity {
+    private static final String LOG_TAG = PhoneGlobals.LOG_TAG;
+    private static final boolean DBG = false;
+
+    private static final int EVENT_PIN_CHANGED = 100;
+    
+    private enum EntryState {
+        ES_PIN,
+        ES_PUK
+    }
+    
+    private EntryState mState;
+
+    private static final int NO_ERROR = 0;
+    private static final int PIN_MISMATCH = 1;
+    private static final int PIN_INVALID_LENGTH = 2;
+
+    private static final int MIN_PIN_LENGTH = 4;
+    private static final int MAX_PIN_LENGTH = 8;
+
+    private Phone mPhone;
+    private boolean mChangePin2;
+    private TextView mBadPinError;
+    private TextView mMismatchError;
+    private EditText mOldPin;
+    private EditText mNewPin1;
+    private EditText mNewPin2;
+    private EditText mPUKCode;
+    private Button mButton;
+    private Button mPUKSubmit;
+    private ScrollView mScrollView;
+
+    private LinearLayout mIccPUKPanel;
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_PIN_CHANGED:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    handleResult(ar);
+                    break;
+            }
+
+            return;
+        }
+    };
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mPhone = PhoneGlobals.getPhone();
+
+        resolveIntent();
+
+        setContentView(R.layout.change_sim_pin_screen);
+
+        mOldPin = (EditText) findViewById(R.id.old_pin);
+        mOldPin.setKeyListener(DigitsKeyListener.getInstance());
+        mOldPin.setMovementMethod(null);
+        mOldPin.setOnClickListener(mClicked);
+
+        mNewPin1 = (EditText) findViewById(R.id.new_pin1);
+        mNewPin1.setKeyListener(DigitsKeyListener.getInstance());
+        mNewPin1.setMovementMethod(null);
+        mNewPin1.setOnClickListener(mClicked);
+
+        mNewPin2 = (EditText) findViewById(R.id.new_pin2);
+        mNewPin2.setKeyListener(DigitsKeyListener.getInstance());
+        mNewPin2.setMovementMethod(null);
+        mNewPin2.setOnClickListener(mClicked);
+
+        mBadPinError = (TextView) findViewById(R.id.bad_pin);
+        mMismatchError = (TextView) findViewById(R.id.mismatch);
+
+        mButton = (Button) findViewById(R.id.button);
+        mButton.setOnClickListener(mClicked);
+
+        mScrollView = (ScrollView) findViewById(R.id.scroll);
+        
+        mPUKCode = (EditText) findViewById(R.id.puk_code);
+        mPUKCode.setKeyListener(DigitsKeyListener.getInstance());
+        mPUKCode.setMovementMethod(null);
+        mPUKCode.setOnClickListener(mClicked);
+        
+        mPUKSubmit = (Button) findViewById(R.id.puk_submit);
+        mPUKSubmit.setOnClickListener(mClicked);
+
+        mIccPUKPanel = (LinearLayout) findViewById(R.id.puk_panel);
+
+        int id = mChangePin2 ? R.string.change_pin2 : R.string.change_pin;
+        setTitle(getResources().getText(id));
+        
+        mState = EntryState.ES_PIN;
+    }
+
+    private void resolveIntent() {
+        Intent intent = getIntent();
+        mChangePin2 = intent.getBooleanExtra("pin2", mChangePin2);
+    }
+
+    private void reset() {
+        mScrollView.scrollTo(0, 0);
+        mBadPinError.setVisibility(View.GONE);
+        mMismatchError.setVisibility(View.GONE);
+    }
+
+    private int validateNewPin(String p1, String p2) {
+        if (p1 == null) {
+            return PIN_INVALID_LENGTH;
+        }
+
+        if (!p1.equals(p2)) {
+            return PIN_MISMATCH;
+        }
+
+        int len1 = p1.length();
+
+        if (len1 < MIN_PIN_LENGTH || len1 > MAX_PIN_LENGTH) {
+            return PIN_INVALID_LENGTH;
+        }
+
+        return NO_ERROR;
+    }
+
+    private View.OnClickListener mClicked = new View.OnClickListener() {
+        public void onClick(View v) {
+            if (v == mOldPin) {
+                mNewPin1.requestFocus();
+            } else if (v == mNewPin1) {
+                mNewPin2.requestFocus();
+            } else if (v == mNewPin2) {
+                mButton.requestFocus();
+            } else if (v == mButton) {
+                IccCard iccCardInterface = mPhone.getIccCard();
+                if (iccCardInterface != null) {
+                    String oldPin = mOldPin.getText().toString();
+                    String newPin1 = mNewPin1.getText().toString();
+                    String newPin2 = mNewPin2.getText().toString();
+
+                    int error = validateNewPin(newPin1, newPin2);
+
+                    switch (error) {
+                        case PIN_INVALID_LENGTH:
+                        case PIN_MISMATCH:
+                            mNewPin1.getText().clear();
+                            mNewPin2.getText().clear();
+                            mMismatchError.setVisibility(View.VISIBLE);
+
+                            Resources r = getResources();
+                            CharSequence text;
+
+                            if (error == PIN_MISMATCH) {
+                                text = r.getString(R.string.mismatchPin);
+                            } else {
+                                text = r.getString(R.string.invalidPin);
+                            }
+
+                            mMismatchError.setText(text);
+                            break;
+
+                        default:
+                            Message callBack = Message.obtain(mHandler,
+                                    EVENT_PIN_CHANGED);
+
+                            if (DBG) log("change pin attempt: old=" + oldPin +
+                                    ", newPin=" + newPin1);
+
+                            reset();
+
+                            if (mChangePin2) {
+                                iccCardInterface.changeIccFdnPassword(oldPin,
+                                        newPin1, callBack);
+                            } else {
+                                iccCardInterface.changeIccLockPassword(oldPin,
+                                        newPin1, callBack);
+                            }
+
+                            // TODO: show progress panel
+                    }
+                }
+            } else if (v == mPUKCode) {
+                mPUKSubmit.requestFocus();
+            } else if (v == mPUKSubmit) {
+                mPhone.getIccCard().supplyPuk2(mPUKCode.getText().toString(), 
+                        mNewPin1.getText().toString(), 
+                        Message.obtain(mHandler, EVENT_PIN_CHANGED));
+            }
+        }
+    };
+
+    private void handleResult(AsyncResult ar) {
+        if (ar.exception == null) {
+            if (DBG) log("handleResult: success!");
+
+            if (mState == EntryState.ES_PUK) {
+                mScrollView.setVisibility(View.VISIBLE);
+                mIccPUKPanel.setVisibility(View.GONE);
+            }            
+            // TODO: show success feedback
+            showConfirmation();
+
+            mHandler.postDelayed(new Runnable() {
+                public void run() {
+                    finish();
+                }
+            }, 3000);
+
+        } else if (ar.exception instanceof CommandException
+           /*  && ((CommandException)ar.exception).getCommandError() ==
+           CommandException.Error.PASSWORD_INCORRECT */ ) {
+            if (mState == EntryState.ES_PIN) {
+                if (DBG) log("handleResult: pin failed!");
+                mOldPin.getText().clear();
+                mBadPinError.setVisibility(View.VISIBLE);
+                CommandException ce = (CommandException) ar.exception;
+                if (ce.getCommandError() == CommandException.Error.SIM_PUK2) {
+                    if (DBG) log("handleResult: puk requested!");
+                    mState = EntryState.ES_PUK;
+                    displayPUKAlert();
+                    mScrollView.setVisibility(View.GONE);
+                    mIccPUKPanel.setVisibility(View.VISIBLE);
+                    mPUKCode.requestFocus();
+                }
+            } else if (mState == EntryState.ES_PUK) {
+                //should really check to see if the error is CommandException.PASSWORD_INCORRECT...
+                if (DBG) log("handleResult: puk2 failed!");
+                displayPUKAlert();
+                mPUKCode.getText().clear();
+                mPUKCode.requestFocus();
+            }
+        }
+    }
+    
+    private AlertDialog mPUKAlert;
+    private void displayPUKAlert () {
+        if (mPUKAlert == null) {
+            mPUKAlert = new AlertDialog.Builder(this)
+            .setMessage (R.string.puk_requested)
+            .setCancelable(false)
+            .show();
+        } else {
+            mPUKAlert.show();
+        }
+        //TODO: The 3 second delay here is somewhat arbitrary, reflecting the values
+        //used elsewhere for similar code.  This should get revisited with the framework
+        //crew to see if there is some standard we should adhere to.
+        mHandler.postDelayed(new Runnable() {
+            public void run() {
+                mPUKAlert.dismiss();
+            }
+        }, 3000);
+    }
+
+    private void showConfirmation() {
+        int id = mChangePin2 ? R.string.pin2_changed : R.string.pin_changed;
+        Toast.makeText(this, id, Toast.LENGTH_SHORT).show();
+    }
+
+    private void log(String msg) {
+        String prefix = mChangePin2 ? "[ChgPin2]" : "[ChgPin]";
+        Log.d(LOG_TAG, prefix + msg);
+    }
+}