2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony.cdma;
19 import android.os.AsyncResult;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.os.Registrant;
23 import android.util.Log;
25 import com.android.internal.telephony.AdnRecord;
26 import com.android.internal.telephony.AdnRecordCache;
27 import com.android.internal.telephony.AdnRecordLoader;
28 import com.android.internal.telephony.CommandsInterface;
29 import com.android.internal.telephony.TelephonyProperties;
30 import com.android.internal.telephony.cdma.RuimCard;
31 import com.android.internal.telephony.MccTable;
33 // can't be used since VoiceMailConstants is not public
34 //import com.android.internal.telephony.gsm.VoiceMailConstants;
35 import com.android.internal.telephony.IccException;
36 import com.android.internal.telephony.IccRecords;
37 import com.android.internal.telephony.IccUtils;
38 import com.android.internal.telephony.PhoneProxy;
44 public final class RuimRecords extends IccRecords {
45 static final String LOG_TAG = "CDMA";
47 private static final boolean DBG = true;
48 private boolean m_ota_commited=false;
50 // ***** Instance Variables
53 private String mMyMobileNumber;
54 private String mMin2Min1;
56 private String mPrlVersion;
58 // ***** Event Constants
60 private static final int EVENT_RUIM_READY = 1;
61 private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
62 private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
63 private static final int EVENT_GET_ICCID_DONE = 5;
64 private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
65 private static final int EVENT_UPDATE_DONE = 14;
66 private static final int EVENT_GET_SST_DONE = 17;
67 private static final int EVENT_GET_ALL_SMS_DONE = 18;
68 private static final int EVENT_MARK_SMS_READ_DONE = 19;
70 private static final int EVENT_SMS_ON_RUIM = 21;
71 private static final int EVENT_GET_SMS_DONE = 22;
73 private static final int EVENT_RUIM_REFRESH = 31;
76 RuimRecords(CDMAPhone p) {
79 adnCache = new AdnRecordCache(phone);
81 recordsRequested = false; // No load request is made till SIM ready
83 // recordsToLoad is set to 0 because no requests are made yet
87 p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null);
88 p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
89 // NOTE the EVENT_SMS_ON_RUIM is not registered
90 p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null);
92 // Start off by setting empty state
93 onRadioOffOrNotAvailable();
97 public void dispose() {
98 //Unregister for all events
99 phone.mCM.unregisterForRUIMReady(this);
100 phone.mCM.unregisterForOffOrNotAvailable( this);
101 phone.mCM.unSetOnIccRefresh(this);
105 protected void finalize() {
106 if(DBG) Log.d(LOG_TAG, "RuimRecords finalized");
110 protected void onRadioOffOrNotAvailable() {
111 countVoiceMessages = 0;
112 mncLength = UNINITIALIZED;
117 // recordsRequested is set to false indicating that the SIM
118 // read requests made so far are not valid. This is set to
119 // true only when fresh set of read requests are made.
120 recordsRequested = false;
123 public String getMdnNumber() {
124 return mMyMobileNumber;
127 public String getCdmaMin() {
131 /** Returns null if RUIM is not yet ready */
132 public String getPrlVersion() {
137 public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){
138 // In CDMA this is Operator/OEM dependent
139 AsyncResult.forMessage((onComplete)).exception =
140 new IccException("setVoiceMailNumber not implemented");
141 onComplete.sendToTarget();
142 Log.e(LOG_TAG, "method setVoiceMailNumber is not implemented");
146 * Called by CCAT Service when REFRESH is received.
147 * @param fileChanged indicates whether any files changed
148 * @param fileList if non-null, a list of EF files that changed
151 public void onRefresh(boolean fileChanged, int[] fileList) {
153 // A future optimization would be to inspect fileList and
154 // only reload those files that we care about. For now,
155 // just re-fetch all RUIM records that we cache.
161 * Returns the 5 or 6 digit MCC/MNC of the operator that
162 * provided the RUIM card. Returns null of RUIM is not yet ready
164 public String getRUIMOperatorNumeric() {
169 if (mncLength != UNINITIALIZED && mncLength != UNKNOWN) {
170 // Length = length of MCC + length of MNC
171 // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
172 return mImsi.substring(0, 3 + mncLength);
175 // Guess the MNC length based on the MCC if we don't
176 // have a valid value in ef[ad]
178 int mcc = Integer.parseInt(mImsi.substring(0,3));
179 return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
183 public void handleMessage(Message msg) {
188 boolean isRecordLoadResponse = false;
190 try { switch (msg.what) {
191 case EVENT_RUIM_READY:
195 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
196 onRadioOffOrNotAvailable();
199 case EVENT_GET_DEVICE_IDENTITY_DONE:
200 Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received");
205 case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
206 ar = (AsyncResult)msg.obj;
207 String localTemp[] = (String[])ar.result;
208 if (ar.exception != null) {
212 mMyMobileNumber = localTemp[0];
213 mMin2Min1 = localTemp[3];
214 mPrlVersion = localTemp[4];
216 Log.d(LOG_TAG, "MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1);
220 case EVENT_GET_ICCID_DONE:
221 isRecordLoadResponse = true;
223 ar = (AsyncResult)msg.obj;
224 data = (byte[])ar.result;
226 if (ar.exception != null) {
230 iccid = IccUtils.bcdToString(data, 0, data.length);
232 Log.d(LOG_TAG, "iccid: " + iccid);
236 case EVENT_UPDATE_DONE:
237 ar = (AsyncResult)msg.obj;
238 if (ar.exception != null) {
239 Log.i(LOG_TAG, "RuimRecords update failed", ar.exception);
243 case EVENT_GET_ALL_SMS_DONE:
244 case EVENT_MARK_SMS_READ_DONE:
245 case EVENT_SMS_ON_RUIM:
246 case EVENT_GET_SMS_DONE:
247 Log.w(LOG_TAG, "Event not supported: " + msg.what);
250 // TODO: probably EF_CST should be read instead
251 case EVENT_GET_SST_DONE:
252 Log.d(LOG_TAG, "Event EVENT_GET_SST_DONE Received");
255 case EVENT_RUIM_REFRESH:
256 isRecordLoadResponse = false;
257 ar = (AsyncResult)msg.obj;
258 if (ar.exception == null) {
259 handleRuimRefresh((int[])(ar.result));
263 }}catch (RuntimeException exc) {
264 // I don't want these exceptions to be fatal
265 Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
267 // Count up record load responses even if they are fails
268 if (isRecordLoadResponse) {
275 protected void onRecordLoaded() {
276 // One record loaded successfully or failed, In either case
277 // we need to update the recordsToLoad count
280 if (recordsToLoad == 0 && recordsRequested == true) {
281 onAllRecordsLoaded();
282 } else if (recordsToLoad < 0) {
283 Log.e(LOG_TAG, "RuimRecords: recordsToLoad <0, programmer error suspected");
289 protected void onAllRecordsLoaded() {
290 Log.d(LOG_TAG, "RuimRecords: record load complete");
292 // Further records that can be inserted are Operator/OEM dependent
294 recordsLoadedRegistrants.notifyRegistrants(
295 new AsyncResult(null, null, null));
296 ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
297 RuimCard.INTENT_VALUE_ICC_LOADED, null);
300 private void onRuimReady() {
301 /* broadcast intent ICC_READY here so that we can make sure
302 READY is sent before IMSI ready
305 ((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
306 RuimCard.INTENT_VALUE_ICC_READY, null);
310 phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
315 private void fetchRuimRecords() {
316 recordsRequested = true;
318 Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
320 phone.getIccFileHandler().loadEFTransparent(EF_ICCID,
321 obtainMessage(EVENT_GET_ICCID_DONE));
324 // Further records that can be inserted are Operator/OEM dependent
328 protected int getDisplayRule(String plmn) {
329 // TODO together with spn
334 public void setVoiceMessageWaiting(int line, int countWaiting) {
336 // only profile 1 is supported
341 if (countWaiting < 0) {
343 } else if (countWaiting > 0xff) {
344 // C.S0015-B v2, 4.5.12
348 countVoiceMessages = countWaiting;
350 ((CDMAPhone) phone).notifyMessageWaitingIndicator();
353 private void handleRuimRefresh(int[] result) {
354 if (result == null || result.length == 0) {
355 if (DBG) log("handleRuimRefresh without input");
359 switch ((result[0])) {
360 case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
361 if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
365 case CommandsInterface.SIM_REFRESH_INIT:
366 if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
367 // need to reload all files (that we care about)
370 case CommandsInterface.SIM_REFRESH_RESET:
371 if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
372 phone.mCM.setRadioPower(false, null);
373 /* Note: no need to call setRadioPower(true). Assuming the desired
374 * radio power state is still ON (as tracked by ServiceStateTracker),
375 * ServiceStateTracker will call setRadioPower when it receives the
376 * RADIO_STATE_CHANGED notification for the power off. And if the
377 * desired power state has changed in the interim, we don't want to
378 * override it with an unconditional power on.
382 // unknown refresh operation
383 if (DBG) log("handleRuimRefresh with unknown operation");
389 protected void log(String s) {
390 Log.d(LOG_TAG, "[RuimRecords] " + s);