4c587095afca4ff0ec1873ce4a53128ccd0b42fe
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / cdma / CdmaMmiCode.java
1 /*
2  * Copyright (C) 2006 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.telephony.cdma;
18
19 import android.content.Context;
20
21 import com.android.internal.telephony.CommandException;
22 import com.android.internal.telephony.MmiCode;
23
24 import android.os.AsyncResult;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.telephony.Rlog;
28
29 import java.util.regex.Pattern;
30 import java.util.regex.Matcher;
31
32 /**
33  * This class can handle Puk code Mmi
34  *
35  * {@hide}
36  *
37  */
38 public final class CdmaMmiCode  extends Handler implements MmiCode {
39     static final String LOG_TAG = "CdmaMmiCode";
40
41     // Constants
42
43     // From TS 22.030 6.5.2
44     static final String ACTION_REGISTER = "**";
45
46     // Supp Service codes from TS 22.030 Annex B
47     static final String SC_PUK          = "05";
48
49     // Event Constant
50
51     static final int EVENT_SET_COMPLETE = 1;
52
53     // Instance Variables
54
55     CDMAPhone mPhone;
56     Context mContext;
57
58     String mAction;              // ACTION_REGISTER
59     String mSc;                  // Service Code
60     String mSia, mSib, mSic;     // Service Info a,b,c
61     String mPoundString;         // Entire MMI string up to and including #
62     String mDialingNumber;
63     String mPwd;                 // For password registration
64
65     State mState = State.PENDING;
66     CharSequence mMessage;
67
68     // Class Variables
69
70     static Pattern sPatternSuppService = Pattern.compile(
71         "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
72 /*       1  2                    3          4  5       6   7         8    9     10  11             12
73
74          1 = Full string up to and including #
75          2 = action
76          3 = service code
77          5 = SIA
78          7 = SIB
79          9 = SIC
80          10 = dialing number
81 */
82
83     static final int MATCH_GROUP_POUND_STRING = 1;
84     static final int MATCH_GROUP_ACTION = 2;
85     static final int MATCH_GROUP_SERVICE_CODE = 3;
86     static final int MATCH_GROUP_SIA = 5;
87     static final int MATCH_GROUP_SIB = 7;
88     static final int MATCH_GROUP_SIC = 9;
89     static final int MATCH_GROUP_PWD_CONFIRM = 11;
90     static final int MATCH_GROUP_DIALING_NUMBER = 12;
91
92
93     // Public Class methods
94
95     /**
96      * Check if provided string contains Mmi code in it and create corresponding
97      * Mmi if it does
98      */
99
100     public static CdmaMmiCode
101     newFromDialString(String dialString, CDMAPhone phone) {
102         Matcher m;
103         CdmaMmiCode ret = null;
104
105         m = sPatternSuppService.matcher(dialString);
106
107         // Is this formatted like a standard supplementary service code?
108         if (m.matches()) {
109             ret = new CdmaMmiCode(phone);
110             ret.mPoundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
111             ret.mAction = makeEmptyNull(m.group(MATCH_GROUP_ACTION));
112             ret.mSc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
113             ret.mSia = makeEmptyNull(m.group(MATCH_GROUP_SIA));
114             ret.mSib = makeEmptyNull(m.group(MATCH_GROUP_SIB));
115             ret.mSic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
116             ret.mPwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
117             ret.mDialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
118
119         }
120
121         return ret;
122     }
123
124     // Private Class methods
125
126     /** make empty strings be null.
127      *  Regexp returns empty strings for empty groups
128      */
129     private static String
130     makeEmptyNull (String s) {
131         if (s != null && s.length() == 0) return null;
132
133         return s;
134     }
135
136     // Constructor
137
138     CdmaMmiCode (CDMAPhone phone) {
139         super(phone.getHandler().getLooper());
140         mPhone = phone;
141         mContext = phone.getContext();
142     }
143
144     // MmiCode implementation
145
146     @Override
147     public State
148     getState() {
149         return mState;
150     }
151
152     @Override
153     public CharSequence
154     getMessage() {
155         return mMessage;
156     }
157
158     // inherited javadoc suffices
159     @Override
160     public void
161     cancel() {
162         // Complete or failed cannot be cancelled
163         if (mState == State.COMPLETE || mState == State.FAILED) {
164             return;
165         }
166
167         mState = State.CANCELLED;
168         mPhone.onMMIDone (this);
169     }
170
171     @Override
172     public boolean isCancelable() {
173         return false;
174     }
175
176     // Instance Methods
177
178     /**
179      * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
180      */
181     boolean isPukCommand() {
182         return mSc != null && mSc.equals(SC_PUK);
183      }
184
185     boolean isRegister() {
186         return mAction != null && mAction.equals(ACTION_REGISTER);
187     }
188
189     @Override
190     public boolean isUssdRequest() {
191         Rlog.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode");
192         return false;
193     }
194
195     /** Process a MMI PUK code */
196     void
197     processCode () {
198         try {
199             if (isPukCommand()) {
200                 // sia = old PUK
201                 // sib = new PIN
202                 // sic = new PIN
203                 String oldPinOrPuk = mSia;
204                 String newPin = mSib;
205                 int pinLen = newPin.length();
206                 if (isRegister()) {
207                     if (!newPin.equals(mSic)) {
208                         // password mismatch; return error
209                         handlePasswordError(com.android.internal.R.string.mismatchPin);
210                     } else if (pinLen < 4 || pinLen > 8 ) {
211                         // invalid length
212                         handlePasswordError(com.android.internal.R.string.invalidPin);
213                     } else {
214                         mPhone.mCi.supplyIccPuk(oldPinOrPuk, newPin,
215                                 obtainMessage(EVENT_SET_COMPLETE, this));
216                     }
217                 } else {
218                     throw new RuntimeException ("Invalid or Unsupported MMI Code");
219                 }
220             } else {
221                 throw new RuntimeException ("Invalid or Unsupported MMI Code");
222             }
223         } catch (RuntimeException exc) {
224             mState = State.FAILED;
225             mMessage = mContext.getText(com.android.internal.R.string.mmiError);
226             mPhone.onMMIDone(this);
227         }
228     }
229
230     private void handlePasswordError(int res) {
231         mState = State.FAILED;
232         StringBuilder sb = new StringBuilder(getScString());
233         sb.append("\n");
234         sb.append(mContext.getText(res));
235         mMessage = sb;
236         mPhone.onMMIDone(this);
237     }
238
239     @Override
240     public void
241     handleMessage (Message msg) {
242         AsyncResult ar;
243
244         if (msg.what == EVENT_SET_COMPLETE) {
245             ar = (AsyncResult) (msg.obj);
246             onSetComplete(ar);
247         } else {
248             Rlog.e(LOG_TAG, "Unexpected reply");
249         }
250     }
251     // Private instance methods
252
253     private CharSequence getScString() {
254         if (mSc != null) {
255             if (isPukCommand()) {
256                 return mContext.getText(com.android.internal.R.string.PinMmi);
257             }
258         }
259
260         return "";
261     }
262
263     private void
264     onSetComplete(AsyncResult ar){
265         StringBuilder sb = new StringBuilder(getScString());
266         sb.append("\n");
267
268         if (ar.exception != null) {
269             mState = State.FAILED;
270             if (ar.exception instanceof CommandException) {
271                 CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
272                 if (err == CommandException.Error.PASSWORD_INCORRECT) {
273                     if (isPukCommand()) {
274                         sb.append(mContext.getText(
275                                 com.android.internal.R.string.badPuk));
276                     } else {
277                         sb.append(mContext.getText(
278                                 com.android.internal.R.string.passwordIncorrect));
279                     }
280                 } else {
281                     sb.append(mContext.getText(
282                             com.android.internal.R.string.mmiError));
283                 }
284             } else {
285                 sb.append(mContext.getText(
286                         com.android.internal.R.string.mmiError));
287             }
288         } else if (isRegister()) {
289             mState = State.COMPLETE;
290             sb.append(mContext.getText(
291                     com.android.internal.R.string.serviceRegistered));
292         } else {
293             mState = State.FAILED;
294             sb.append(mContext.getText(
295                     com.android.internal.R.string.mmiError));
296         }
297
298         mMessage = sb;
299         mPhone.onMMIDone(this);
300     }
301
302 }