Skip to content

Commit 7751667

Browse files
Jean-Baptiste QueruAndroid Code Review
authored andcommitted
Merge "Telephony: Add PUK MMI code support for CDMA RUIM phones"
2 parents 12849c8 + e9c0a6d commit 7751667

File tree

2 files changed

+338
-3
lines changed

2 files changed

+338
-3
lines changed

telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
6868
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
6969

70+
import java.util.ArrayList;
7071
import java.util.List;
7172

7273

@@ -101,6 +102,7 @@ public class CDMAPhone extends PhoneBase {
101102
RuimFileHandler mRuimFileHandler;
102103
RuimRecords mRuimRecords;
103104
RuimCard mRuimCard;
105+
ArrayList <CdmaMmiCode> mPendingMmis = new ArrayList<CdmaMmiCode>();
104106
RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
105107
RuimSmsInterfaceManager mRuimSmsInterfaceManager;
106108
PhoneSubInfo mSubInfo;
@@ -223,6 +225,8 @@ public void dispose() {
223225
mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
224226
mCM.unSetOnSuppServiceNotification(this);
225227

228+
mPendingMmis.clear();
229+
226230
//Force all referenced classes to unregister their former registered events
227231
mCT.dispose();
228232
mDataConnection.dispose();
@@ -365,8 +369,7 @@ public SignalStrength getSignalStrength() {
365369

366370
public List<? extends MmiCode>
367371
getPendingMmiCodes() {
368-
Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!");
369-
return null;
372+
return mPendingMmis;
370373
}
371374

372375
public void registerForSuppServiceNotification(
@@ -383,6 +386,15 @@ public boolean handleInCallMmiCommands(String dialString) {
383386
return false;
384387
}
385388

389+
boolean isInCall() {
390+
CdmaCall.State foregroundCallState = getForegroundCall().getState();
391+
CdmaCall.State backgroundCallState = getBackgroundCall().getState();
392+
CdmaCall.State ringingCallState = getRingingCall().getState();
393+
394+
return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState
395+
.isAlive());
396+
}
397+
386398
public void
387399
setNetworkSelectionModeAutomatic(Message response) {
388400
Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
@@ -482,7 +494,18 @@ public void setOnPostDialCharacter(Handler h, int what, Object obj) {
482494
}
483495

484496
public boolean handlePinMmi(String dialString) {
485-
Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!");
497+
CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this);
498+
499+
if (mmi == null) {
500+
Log.e(LOG_TAG, "Mmi is NULL!");
501+
return false;
502+
} else if (mmi.isPukCommand()) {
503+
mPendingMmis.add(mmi);
504+
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
505+
mmi.processCode();
506+
return true;
507+
}
508+
Log.e(LOG_TAG, "Unrecognized mmi!");
486509
return false;
487510
}
488511

@@ -494,6 +517,22 @@ public boolean isDataConnectivityPossible() {
494517
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
495518
}
496519

520+
/**
521+
* Removes the given MMI from the pending list and notifies registrants that
522+
* it is complete.
523+
*
524+
* @param mmi MMI that is done
525+
*/
526+
void onMMIDone(CdmaMmiCode mmi) {
527+
/*
528+
* Only notify complete if it's on the pending list. Otherwise, it's
529+
* already been handled (eg, previously canceled).
530+
*/
531+
if (mPendingMmis.remove(mmi)) {
532+
mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
533+
}
534+
}
535+
497536
public void setLine1Number(String alphaTag, String number, Message onComplete) {
498537
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
499538
}
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
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.util.Log;
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 = "CDMA_MMI";
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 phone;
56+
Context context;
57+
58+
String action; // ACTION_REGISTER
59+
String sc; // Service Code
60+
String sia, sib, sic; // Service Info a,b,c
61+
String poundString; // Entire MMI string up to and including #
62+
String dialingNumber;
63+
String pwd; // For password registration
64+
65+
State state = State.PENDING;
66+
CharSequence message;
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.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
111+
ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION));
112+
ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
113+
ret.sia = makeEmptyNull(m.group(MATCH_GROUP_SIA));
114+
ret.sib = makeEmptyNull(m.group(MATCH_GROUP_SIB));
115+
ret.sic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
116+
ret.pwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
117+
ret.dialingNumber = 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+
this.phone = phone;
141+
this.context = phone.getContext();
142+
}
143+
144+
// MmiCode implementation
145+
146+
public State
147+
getState() {
148+
return state;
149+
}
150+
151+
public CharSequence
152+
getMessage() {
153+
return message;
154+
}
155+
156+
// inherited javadoc suffices
157+
public void
158+
cancel() {
159+
// Complete or failed cannot be cancelled
160+
if (state == State.COMPLETE || state == State.FAILED) {
161+
return;
162+
}
163+
164+
state = State.CANCELLED;
165+
phone.onMMIDone (this);
166+
}
167+
168+
public boolean isCancelable() {
169+
return false;
170+
}
171+
172+
// Instance Methods
173+
174+
/**
175+
* @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
176+
*/
177+
boolean isPukCommand() {
178+
return sc != null && sc.equals(SC_PUK);
179+
}
180+
181+
boolean isRegister() {
182+
return action != null && action.equals(ACTION_REGISTER);
183+
}
184+
185+
public boolean isUssdRequest() {
186+
Log.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode");
187+
return false;
188+
}
189+
190+
/** Process a MMI PUK code */
191+
void
192+
processCode () {
193+
try {
194+
if (isPukCommand()) {
195+
// sia = old PUK
196+
// sib = new PIN
197+
// sic = new PIN
198+
String oldPinOrPuk = sia;
199+
String newPin = sib;
200+
int pinLen = newPin.length();
201+
if (isRegister()) {
202+
if (!newPin.equals(sic)) {
203+
// password mismatch; return error
204+
handlePasswordError(com.android.internal.R.string.mismatchPin);
205+
} else if (pinLen < 4 || pinLen > 8 ) {
206+
// invalid length
207+
handlePasswordError(com.android.internal.R.string.invalidPin);
208+
} else {
209+
phone.mCM.supplyIccPuk(oldPinOrPuk, newPin,
210+
obtainMessage(EVENT_SET_COMPLETE, this));
211+
}
212+
} else {
213+
throw new RuntimeException ("Invalid or Unsupported MMI Code");
214+
}
215+
} else {
216+
throw new RuntimeException ("Invalid or Unsupported MMI Code");
217+
}
218+
} catch (RuntimeException exc) {
219+
state = State.FAILED;
220+
message = context.getText(com.android.internal.R.string.mmiError);
221+
phone.onMMIDone(this);
222+
}
223+
}
224+
225+
private void handlePasswordError(int res) {
226+
state = State.FAILED;
227+
StringBuilder sb = new StringBuilder(getScString());
228+
sb.append("\n");
229+
sb.append(context.getText(res));
230+
message = sb;
231+
phone.onMMIDone(this);
232+
}
233+
234+
public void
235+
handleMessage (Message msg) {
236+
AsyncResult ar;
237+
238+
if (msg.what == EVENT_SET_COMPLETE) {
239+
ar = (AsyncResult) (msg.obj);
240+
onSetComplete(ar);
241+
} else {
242+
Log.e(LOG_TAG, "Unexpected reply");
243+
}
244+
}
245+
// Private instance methods
246+
247+
private CharSequence getScString() {
248+
if (sc != null) {
249+
if (isPukCommand()) {
250+
return context.getText(com.android.internal.R.string.PinMmi);
251+
}
252+
}
253+
254+
return "";
255+
}
256+
257+
private void
258+
onSetComplete(AsyncResult ar){
259+
StringBuilder sb = new StringBuilder(getScString());
260+
sb.append("\n");
261+
262+
if (ar.exception != null) {
263+
state = State.FAILED;
264+
if (ar.exception instanceof CommandException) {
265+
CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
266+
if (err == CommandException.Error.PASSWORD_INCORRECT) {
267+
if (isPukCommand()) {
268+
sb.append(context.getText(
269+
com.android.internal.R.string.badPuk));
270+
} else {
271+
sb.append(context.getText(
272+
com.android.internal.R.string.passwordIncorrect));
273+
}
274+
} else {
275+
sb.append(context.getText(
276+
com.android.internal.R.string.mmiError));
277+
}
278+
} else {
279+
sb.append(context.getText(
280+
com.android.internal.R.string.mmiError));
281+
}
282+
} else if (isRegister()) {
283+
state = State.COMPLETE;
284+
sb.append(context.getText(
285+
com.android.internal.R.string.serviceRegistered));
286+
} else {
287+
state = State.FAILED;
288+
sb.append(context.getText(
289+
com.android.internal.R.string.mmiError));
290+
}
291+
292+
message = sb;
293+
phone.onMMIDone(this);
294+
}
295+
296+
}

0 commit comments

Comments
 (0)