| /* |
| * 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.internal.telephony.cdma; |
| |
| import android.content.Context; |
| |
| import com.android.internal.telephony.CommandException; |
| import com.android.internal.telephony.MmiCode; |
| |
| import android.os.AsyncResult; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.util.Log; |
| |
| import java.util.regex.Pattern; |
| import java.util.regex.Matcher; |
| |
| /** |
| * This class can handle Puk code Mmi |
| * |
| * {@hide} |
| * |
| */ |
| public final class CdmaMmiCode extends Handler implements MmiCode { |
| static final String LOG_TAG = "CDMA_MMI"; |
| |
| // Constants |
| |
| // From TS 22.030 6.5.2 |
| static final String ACTION_REGISTER = "**"; |
| |
| // Supp Service codes from TS 22.030 Annex B |
| static final String SC_PUK = "05"; |
| |
| // Event Constant |
| |
| static final int EVENT_SET_COMPLETE = 1; |
| |
| // Instance Variables |
| |
| CDMAPhone phone; |
| Context context; |
| |
| String action; // ACTION_REGISTER |
| String sc; // Service Code |
| String sia, sib, sic; // Service Info a,b,c |
| String poundString; // Entire MMI string up to and including # |
| String dialingNumber; |
| String pwd; // For password registration |
| |
| State state = State.PENDING; |
| CharSequence message; |
| |
| // Class Variables |
| |
| static Pattern sPatternSuppService = Pattern.compile( |
| "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)"); |
| /* 1 2 3 4 5 6 7 8 9 10 11 12 |
| |
| 1 = Full string up to and including # |
| 2 = action |
| 3 = service code |
| 5 = SIA |
| 7 = SIB |
| 9 = SIC |
| 10 = dialing number |
| */ |
| |
| static final int MATCH_GROUP_POUND_STRING = 1; |
| static final int MATCH_GROUP_ACTION = 2; |
| static final int MATCH_GROUP_SERVICE_CODE = 3; |
| static final int MATCH_GROUP_SIA = 5; |
| static final int MATCH_GROUP_SIB = 7; |
| static final int MATCH_GROUP_SIC = 9; |
| static final int MATCH_GROUP_PWD_CONFIRM = 11; |
| static final int MATCH_GROUP_DIALING_NUMBER = 12; |
| |
| |
| // Public Class methods |
| |
| /** |
| * Check if provided string contains Mmi code in it and create corresponding |
| * Mmi if it does |
| */ |
| |
| public static CdmaMmiCode |
| newFromDialString(String dialString, CDMAPhone phone) { |
| Matcher m; |
| CdmaMmiCode ret = null; |
| |
| m = sPatternSuppService.matcher(dialString); |
| |
| // Is this formatted like a standard supplementary service code? |
| if (m.matches()) { |
| ret = new CdmaMmiCode(phone); |
| ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING)); |
| ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION)); |
| ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); |
| ret.sia = makeEmptyNull(m.group(MATCH_GROUP_SIA)); |
| ret.sib = makeEmptyNull(m.group(MATCH_GROUP_SIB)); |
| ret.sic = makeEmptyNull(m.group(MATCH_GROUP_SIC)); |
| ret.pwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM)); |
| ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER)); |
| |
| } |
| |
| return ret; |
| } |
| |
| // Private Class methods |
| |
| /** make empty strings be null. |
| * Regexp returns empty strings for empty groups |
| */ |
| private static String |
| makeEmptyNull (String s) { |
| if (s != null && s.length() == 0) return null; |
| |
| return s; |
| } |
| |
| // Constructor |
| |
| CdmaMmiCode (CDMAPhone phone) { |
| super(phone.getHandler().getLooper()); |
| this.phone = phone; |
| this.context = phone.getContext(); |
| } |
| |
| // MmiCode implementation |
| |
| public State |
| getState() { |
| return state; |
| } |
| |
| public CharSequence |
| getMessage() { |
| return message; |
| } |
| |
| // inherited javadoc suffices |
| public void |
| cancel() { |
| // Complete or failed cannot be cancelled |
| if (state == State.COMPLETE || state == State.FAILED) { |
| return; |
| } |
| |
| state = State.CANCELLED; |
| phone.onMMIDone (this); |
| } |
| |
| public boolean isCancelable() { |
| return false; |
| } |
| |
| // Instance Methods |
| |
| /** |
| * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related |
| */ |
| boolean isPukCommand() { |
| return sc != null && sc.equals(SC_PUK); |
| } |
| |
| boolean isRegister() { |
| return action != null && action.equals(ACTION_REGISTER); |
| } |
| |
| public boolean isUssdRequest() { |
| Log.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode"); |
| return false; |
| } |
| |
| /** Process a MMI PUK code */ |
| void |
| processCode () { |
| try { |
| if (isPukCommand()) { |
| // sia = old PUK |
| // sib = new PIN |
| // sic = new PIN |
| String oldPinOrPuk = sia; |
| String newPin = sib; |
| int pinLen = newPin.length(); |
| if (isRegister()) { |
| if (!newPin.equals(sic)) { |
| // password mismatch; return error |
| handlePasswordError(com.android.internal.R.string.mismatchPin); |
| } else if (pinLen < 4 || pinLen > 8 ) { |
| // invalid length |
| handlePasswordError(com.android.internal.R.string.invalidPin); |
| } else { |
| phone.mCM.supplyIccPuk(oldPinOrPuk, newPin, |
| obtainMessage(EVENT_SET_COMPLETE, this)); |
| } |
| } else { |
| throw new RuntimeException ("Invalid or Unsupported MMI Code"); |
| } |
| } else { |
| throw new RuntimeException ("Invalid or Unsupported MMI Code"); |
| } |
| } catch (RuntimeException exc) { |
| state = State.FAILED; |
| message = context.getText(com.android.internal.R.string.mmiError); |
| phone.onMMIDone(this); |
| } |
| } |
| |
| private void handlePasswordError(int res) { |
| state = State.FAILED; |
| StringBuilder sb = new StringBuilder(getScString()); |
| sb.append("\n"); |
| sb.append(context.getText(res)); |
| message = sb; |
| phone.onMMIDone(this); |
| } |
| |
| public void |
| handleMessage (Message msg) { |
| AsyncResult ar; |
| |
| if (msg.what == EVENT_SET_COMPLETE) { |
| ar = (AsyncResult) (msg.obj); |
| onSetComplete(ar); |
| } else { |
| Log.e(LOG_TAG, "Unexpected reply"); |
| } |
| } |
| // Private instance methods |
| |
| private CharSequence getScString() { |
| if (sc != null) { |
| if (isPukCommand()) { |
| return context.getText(com.android.internal.R.string.PinMmi); |
| } |
| } |
| |
| return ""; |
| } |
| |
| private void |
| onSetComplete(AsyncResult ar){ |
| StringBuilder sb = new StringBuilder(getScString()); |
| sb.append("\n"); |
| |
| if (ar.exception != null) { |
| state = State.FAILED; |
| if (ar.exception instanceof CommandException) { |
| CommandException.Error err = ((CommandException)(ar.exception)).getCommandError(); |
| if (err == CommandException.Error.PASSWORD_INCORRECT) { |
| if (isPukCommand()) { |
| sb.append(context.getText( |
| com.android.internal.R.string.badPuk)); |
| } else { |
| sb.append(context.getText( |
| com.android.internal.R.string.passwordIncorrect)); |
| } |
| } else { |
| sb.append(context.getText( |
| com.android.internal.R.string.mmiError)); |
| } |
| } else { |
| sb.append(context.getText( |
| com.android.internal.R.string.mmiError)); |
| } |
| } else if (isRegister()) { |
| state = State.COMPLETE; |
| sb.append(context.getText( |
| com.android.internal.R.string.serviceRegistered)); |
| } else { |
| state = State.FAILED; |
| sb.append(context.getText( |
| com.android.internal.R.string.mmiError)); |
| } |
| |
| message = sb; |
| phone.onMMIDone(this); |
| } |
| |
| } |