1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/*
2c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Copyright (C) 2008 The Android Open Source Project
3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License.
6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at
7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software
11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and
14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License.
15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */
16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony.cdma;
18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
19e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
20c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
21c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
22e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
23e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
24e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
25e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
26e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport java.util.ArrayList;
27e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport java.util.Locale;
28c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.content.Context;
29c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.AsyncResult;
30c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Handler;
31c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Message;
32c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.Registrant;
33c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.os.SystemProperties;
34c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport android.util.Log;
35c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
36c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.AdnRecord;
37c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.AdnRecordCache;
38c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.AdnRecordLoader;
39c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.CommandsInterface;
40c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccCardConstants;
41e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.GsmAlphabet;
42c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccRefreshResponse;
43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.PhoneBase;
44c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.TelephonyProperties;
45c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.MccTable;
46e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.UiccCardApplication;
47c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
48c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville// can't be used since VoiceMailConstants is not public
49c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville//import com.android.internal.telephony.gsm.VoiceMailConstants;
50c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccException;
51c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccRecords;
52c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.IccUtils;
53c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savilleimport com.android.internal.telephony.PhoneProxy;
54e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.IccCardApplicationStatus.AppType;
55e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.IccRecords.IccRecordLoaded;
56e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.cdma.sms.UserData;
57c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
58c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
59c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/**
60c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * {@hide}
61c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */
62c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepublic final class RuimRecords extends IccRecords {
63c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    static final String LOG_TAG = "CDMA";
64c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
65c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final boolean DBG = true;
66c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private boolean  m_ota_commited=false;
67c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
68c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    // ***** Instance Variables
69c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
70c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private String mMyMobileNumber;
71c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private String mMin2Min1;
72c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
73c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private String mPrlVersion;
74e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // From CSIM application
75e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private byte[] mEFpl = null;
76e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private byte[] mEFli = null;
77e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    boolean mCsimSpnDisplayCondition = false;
78e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private String mMdn;
79e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private String mMin;
80e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private String mHomeSystemId;
81e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private String mHomeNetworkId;
82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
83c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    // ***** Event Constants
84e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private static final int EVENT_APP_READY = 1;
85c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_IMSI_DONE = 3;
86c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
87c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_ICCID_DONE = 5;
88c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
89c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_UPDATE_DONE = 14;
90c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_SST_DONE = 17;
91c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_ALL_SMS_DONE = 18;
92c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_MARK_SMS_READ_DONE = 19;
93c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
94c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_SMS_ON_RUIM = 21;
95c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_GET_SMS_DONE = 22;
96c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
97c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final int EVENT_RUIM_REFRESH = 31;
98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
99e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public RuimRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
100e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        super(app, c, ci);
101c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
102c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        adnCache = new AdnRecordCache(mFh);
103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
104c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsRequested = false;  // No load request is made till SIM ready
105c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
106c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // recordsToLoad is set to 0 because no requests are made yet
107c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsToLoad = 0;
108c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
109c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // NOTE the EVENT_SMS_ON_RUIM is not registered
110c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mCi.registerForIccRefresh(this, EVENT_RUIM_REFRESH, null);
111c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
112c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Start off by setting empty state
113e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        resetRecords();
114c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
115e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mParentApp.registerForReady(this, EVENT_APP_READY, null);
116c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
117c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
118c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
119c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void dispose() {
120c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (DBG) log("Disposing RuimRecords " + this);
121c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        //Unregister for all events
122c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mCi.unregisterForIccRefresh(this);
123e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mParentApp.unregisterForReady(this);
124e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        resetRecords();
125c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        super.dispose();
126c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
127c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
128c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
129c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    protected void finalize() {
130c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if(DBG) log("RuimRecords finalized");
131c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
132c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
133e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    protected void resetRecords() {
134c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        countVoiceMessages = 0;
135c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mncLength = UNINITIALIZED;
136c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        iccid = null;
137c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
138c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        adnCache.reset();
139c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
140c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Don't clean up PROPERTY_ICC_OPERATOR_ISO_COUNTRY and
141c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // PROPERTY_ICC_OPERATOR_NUMERIC here. Since not all CDMA
142c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // devices have RUIM, these properties should keep the original
143c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // values, e.g. build time settings, when there is no RUIM but
144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // set new values when RUIM is available and loaded.
145c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
146c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // recordsRequested is set to false indicating that the SIM
147c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // read requests made so far are not valid. This is set to
148c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // true only when fresh set of read requests are made.
149c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsRequested = false;
150c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
151c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
152e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    @Override
153e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public String getIMSI() {
154e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mImsi;
155e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
156e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
157c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public String getMdnNumber() {
158c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return mMyMobileNumber;
159c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
160c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
161c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public String getCdmaMin() {
162c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville         return mMin2Min1;
163c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
164c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
165c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /** Returns null if RUIM is not yet ready */
166c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public String getPrlVersion() {
167c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return mPrlVersion;
168c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
169c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
170c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
171c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){
172c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // In CDMA this is Operator/OEM dependent
173c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        AsyncResult.forMessage((onComplete)).exception =
174c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                new IccException("setVoiceMailNumber not implemented");
175c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        onComplete.sendToTarget();
176c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        loge("method setVoiceMailNumber is not implemented");
177c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
178c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
179c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
180c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Called by CCAT Service when REFRESH is received.
181c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * @param fileChanged indicates whether any files changed
182c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * @param fileList if non-null, a list of EF files that changed
183c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
184c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
185c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void onRefresh(boolean fileChanged, int[] fileList) {
186c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (fileChanged) {
187c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // A future optimization would be to inspect fileList and
188c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // only reload those files that we care about.  For now,
189c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // just re-fetch all RUIM records that we cache.
190c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            fetchRuimRecords();
191c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
192c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
193c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
194e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private int adjstMinDigits (int digits) {
195e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // Per C.S0005 section 2.3.1.
196e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        digits += 111;
197e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        digits = (digits % 10 == 0)?(digits - 10):digits;
198e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        digits = ((digits / 10) % 10 == 0)?(digits - 100):digits;
199e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits;
200e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return digits;
201e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
202e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
203c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
204c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * Returns the 5 or 6 digit MCC/MNC of the operator that
205c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     *  provided the RUIM card. Returns null of RUIM is not yet ready
206c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
207c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public String getRUIMOperatorNumeric() {
208c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (mImsi == null) {
209c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return null;
210c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
211c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
212c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (mncLength != UNINITIALIZED && mncLength != UNKNOWN) {
213c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // Length = length of MCC + length of MNC
214c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
215c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return mImsi.substring(0, 3 + mncLength);
216c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
217c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
218c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Guess the MNC length based on the MCC if we don't
219c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // have a valid value in ef[ad]
220c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
221c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        int mcc = Integer.parseInt(mImsi.substring(0,3));
222c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
223c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
224c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
225e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Refer to ETSI TS 102.221
226e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfPlLoaded implements IccRecordLoaded {
227e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
228e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_PL";
229e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
230e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
231e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
232e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mEFpl = (byte[]) ar.result;
233e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl));
234e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
235e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
236e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
237e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Refer to C.S0065 5.2.26
238e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimLiLoaded implements IccRecordLoaded {
239e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
240e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_LI";
241e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
242e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
243e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
244e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mEFli = (byte[]) ar.result;
245e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // convert csim efli data to iso 639 format
246e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            for (int i = 0; i < mEFli.length; i+=2) {
247e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                switch(mEFli[i+1]) {
248e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x01: mEFli[i] = 'e'; mEFli[i+1] = 'n';break;
249e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x02: mEFli[i] = 'f'; mEFli[i+1] = 'r';break;
250e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x03: mEFli[i] = 'e'; mEFli[i+1] = 's';break;
251e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x04: mEFli[i] = 'j'; mEFli[i+1] = 'a';break;
252e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x05: mEFli[i] = 'k'; mEFli[i+1] = 'o';break;
253e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x06: mEFli[i] = 'z'; mEFli[i+1] = 'h';break;
254e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case 0x07: mEFli[i] = 'h'; mEFli[i+1] = 'e';break;
255e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                default: mEFli[i] = ' '; mEFli[i+1] = ' ';
256e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                }
257e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
258e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
259e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli));
260e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
261e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
262e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
263e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    // Refer to C.S0065 5.2.32
264e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimSpnLoaded implements IccRecordLoaded {
265e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
266e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_SPN";
267e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
268e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
269e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
270e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            byte[] data = (byte[]) ar.result;
271e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("CSIM_SPN=" +
272e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                         IccUtils.bytesToHexString(data));
273e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
274e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // C.S0065 for EF_SPN decoding
275e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mCsimSpnDisplayCondition = ((0x01 & data[0]) != 0);
276e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
277e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int encoding = data[1];
278e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int language = data[2];
279e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            byte[] spnData = new byte[32];
280e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int len = ((data.length - 3) < 32) ? (data.length - 3) : 32;
281e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            System.arraycopy(data, 3, spnData, 0, len);
282e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
283e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int numBytes;
284e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            for (numBytes = 0; numBytes < spnData.length; numBytes++) {
285e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if ((spnData[numBytes] & 0xFF) == 0xFF) break;
286e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
287e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
288e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (numBytes == 0) {
289e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                spn = "";
290e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                return;
291e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
292e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            try {
293e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                switch (encoding) {
294e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_OCTET:
295e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_LATIN:
296e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    spn = new String(spnData, 0, numBytes, "ISO-8859-1");
297e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    break;
298e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_IA5:
299e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_GSM_7BIT_ALPHABET:
300e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_7BIT_ASCII:
301e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    spn = GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7);
302e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    break;
303e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case UserData.ENCODING_UNICODE_16:
304e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    spn =  new String(spnData, 0, numBytes, "utf-16");
305e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    break;
306e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                default:
307e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    log("SPN encoding not supported");
308e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                }
309e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            } catch(Exception e) {
310e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                log("spn decode error: " + e);
311e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
312e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("spn=" + spn);
313e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("spnCondition=" + mCsimSpnDisplayCondition);
314e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            SystemProperties.set(PROPERTY_ICC_OPERATOR_ALPHA, spn);
315e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
316e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
317e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
318e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimMdnLoaded implements IccRecordLoaded {
319e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
320e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_MDN";
321e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
322e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
323e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
324e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            byte[] data = (byte[]) ar.result;
325e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("CSIM_MDN=" + IccUtils.bytesToHexString(data));
326e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // Refer to C.S0065 5.2.35
327e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int mdnDigitsNum = 0x0F & data[0];
328e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mMdn = IccUtils.cdmaBcdToString(data, 1, mdnDigitsNum);
329e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("CSIM MDN=" + mMdn);
330e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
331e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
332e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
333e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimImsimLoaded implements IccRecordLoaded {
334e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
335e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_IMSIM";
336e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
337e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
338e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
339e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            byte[] data = (byte[]) ar.result;
340e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data));
341e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // C.S0065 section 5.2.2 for IMSI_M encoding
342e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // C.S0005 section 2.3.1 for MIN encoding in IMSI_M.
343e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            boolean provisioned = ((data[7] & 0x80) == 0x80);
344e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
345e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (provisioned) {
346e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]);
347e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6;
348e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                int digit7 = 0x0F & (data[4] >> 2);
349e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if (digit7 > 0x09) digit7 = 0;
350e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]);
351e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                first3digits = adjstMinDigits(first3digits);
352e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                second3digits = adjstMinDigits(second3digits);
353e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                last3digits = adjstMinDigits(last3digits);
354e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
355e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                StringBuilder builder = new StringBuilder();
356e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                builder.append(String.format(Locale.US, "%03d", first3digits));
357e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                builder.append(String.format(Locale.US, "%03d", second3digits));
358e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                builder.append(String.format(Locale.US, "%d", digit7));
359e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                builder.append(String.format(Locale.US, "%03d", last3digits));
360e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                mMin = builder.toString();
361e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if (DBG) log("min present=" + mMin);
362e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            } else {
363e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if (DBG) log("min not present");
364e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
365e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
366e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
367e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
368e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimCdmaHomeLoaded implements IccRecordLoaded {
369e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
370e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_CDMAHOME";
371e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
372e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
373e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
374e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // Per C.S0065 section 5.2.8
375e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            ArrayList<byte[]> dataList = (ArrayList<byte[]>) ar.result;
376e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (DBG) log("CSIM_CDMAHOME data size=" + dataList.size());
377e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (dataList.isEmpty()) {
378e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                return;
379e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
380e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            StringBuilder sidBuf = new StringBuilder();
381e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            StringBuilder nidBuf = new StringBuilder();
382e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
383e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            for (byte[] data : dataList) {
384e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if (data.length == 5) {
385e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    int sid = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF);
386e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    int nid = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF);
387e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    sidBuf.append(sid).append(',');
388e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    nidBuf.append(nid).append(',');
389e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                }
390e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
391e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // remove trailing ","
392e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            sidBuf.setLength(sidBuf.length()-1);
393e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            nidBuf.setLength(nidBuf.length()-1);
394e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
395e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mHomeSystemId = sidBuf.toString();
396e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mHomeNetworkId = nidBuf.toString();
397e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
398e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
399e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
400e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private class EfCsimEprlLoaded implements IccRecordLoaded {
401e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public String getEfName() {
402e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return "EF_CSIM_EPRL";
403e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
404e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        public void onRecordLoaded(AsyncResult ar) {
405e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            onGetCSimEprlDone(ar);
406e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
407e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
408e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
409e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private void onGetCSimEprlDone(AsyncResult ar) {
410e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // C.S0065 section 5.2.57 for EFeprl encoding
411e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // C.S0016 section 3.5.5 for PRL format.
412e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        byte[] data = (byte[]) ar.result;
413e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (DBG) log("CSIM_EPRL=" + IccUtils.bytesToHexString(data));
414e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
415e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // Only need the first 4 bytes of record
416e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (data.length > 3) {
417e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            int prlId = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
418e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mPrlVersion = Integer.toString(prlId);
419e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
420e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (DBG) log("CSIM PRL version=" + mPrlVersion);
421e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
422e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
423c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
424c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void handleMessage(Message msg) {
425c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        AsyncResult ar;
426c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
427c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        byte data[];
428c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
429c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        boolean isRecordLoadResponse = false;
430c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
431bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (mDestroyed.get()) {
432c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            loge("Received message " + msg +
433c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    "[" + msg.what + "] while being destroyed. Ignoring.");
434c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return;
435c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
436c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
437c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        try { switch (msg.what) {
438e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            case EVENT_APP_READY:
439e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                onReady();
440e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                break;
441c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
442c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_DEVICE_IDENTITY_DONE:
443c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                log("Event EVENT_GET_DEVICE_IDENTITY_DONE Received");
444c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
445c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
446c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            /* IO events */
447c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_IMSI_DONE:
448c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                isRecordLoadResponse = true;
449c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
450c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                ar = (AsyncResult)msg.obj;
451c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (ar.exception != null) {
452c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    loge("Exception querying IMSI, Exception:" + ar.exception);
453c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    break;
454c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
455c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
456c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                mImsi = (String) ar.result;
457c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
458c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
459c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                // than 15 (and usually 15).
460c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
461c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    loge("invalid IMSI " + mImsi);
462c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    mImsi = null;
463c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
464c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
465c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxxxx");
466c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
467c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                String operatorNumeric = getRUIMOperatorNumeric();
468c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (operatorNumeric != null) {
469c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    if(operatorNumeric.length() <= 6){
470c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                        MccTable.updateMccMncConfiguration(mContext, operatorNumeric);
471c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    }
472c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
473c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
474c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
475c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
476c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                ar = (AsyncResult)msg.obj;
477c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                String localTemp[] = (String[])ar.result;
478c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (ar.exception != null) {
479c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    break;
480c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
481c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
482c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                mMyMobileNumber = localTemp[0];
483c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                mMin2Min1 = localTemp[3];
484c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                mPrlVersion = localTemp[4];
485c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
486c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                log("MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1);
487c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
488c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
489c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
490c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_ICCID_DONE:
491c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                isRecordLoadResponse = true;
492c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
493c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                ar = (AsyncResult)msg.obj;
494c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                data = (byte[])ar.result;
495c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
496c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (ar.exception != null) {
497c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    break;
498c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
499c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
500c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                iccid = IccUtils.bcdToString(data, 0, data.length);
501c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
502c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                log("iccid: " + iccid);
503c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
504c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
505c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
506c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_UPDATE_DONE:
507c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                ar = (AsyncResult)msg.obj;
508c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (ar.exception != null) {
509c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    Log.i(LOG_TAG, "RuimRecords update failed", ar.exception);
510c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
511c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
512c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
513c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_ALL_SMS_DONE:
514c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_MARK_SMS_READ_DONE:
515c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_SMS_ON_RUIM:
516c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_SMS_DONE:
517c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                Log.w(LOG_TAG, "Event not supported: " + msg.what);
518c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
519c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
520c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // TODO: probably EF_CST should be read instead
521c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_GET_SST_DONE:
522c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                log("Event EVENT_GET_SST_DONE Received");
523c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            break;
524c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
525c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case EVENT_RUIM_REFRESH:
526c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                isRecordLoadResponse = false;
527c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                ar = (AsyncResult)msg.obj;
528c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (ar.exception == null) {
529c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    handleRuimRefresh((IccRefreshResponse)ar.result);
530c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                }
531c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
532c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
533e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            default:
534e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                super.handleMessage(msg);   // IccRecords handles generic record load responses
535e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
536c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }}catch (RuntimeException exc) {
537c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // I don't want these exceptions to be fatal
538c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
539c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        } finally {
540c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // Count up record load responses even if they are fails
541c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            if (isRecordLoadResponse) {
542c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                onRecordLoaded();
543c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            }
544c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
545c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
546c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
547e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private String findBestLanguage(byte[] languages) {
548e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        String bestMatch = null;
549e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        String[] locales = mContext.getAssets().getLocales();
550e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
551e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if ((languages == null) || (locales == null)) return null;
552e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
553e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // Each 2-bytes consists of one language
554e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        for (int i = 0; (i + 1) < languages.length; i += 2) {
555e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            try {
556e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                String lang = new String(languages, i, 2, "ISO-8859-1");
557e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                for (int j = 0; j < locales.length; j++) {
558e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    if (locales[j] != null && locales[j].length() >= 2 &&
559e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                        locales[j].substring(0, 2).equals(lang)) {
560e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                        return lang;
561e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    }
562e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                }
563e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                if (bestMatch != null) break;
564e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            } catch(java.io.UnsupportedEncodingException e) {
565e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                log ("Failed to parse SIM language records");
566e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
567e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
568e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // no match found. return null
569e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return null;
570e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
571e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
572e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private void setLocaleFromCsim() {
573e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        String prefLang = null;
574e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // check EFli then EFpl
575e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        prefLang = findBestLanguage(mEFli);
576e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
577e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (prefLang == null) {
578e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            prefLang = findBestLanguage(mEFpl);
579e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
580e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
581e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (prefLang != null) {
582e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            // check country code from SIM
583e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            String imsi = getIMSI();
584e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            String country = null;
585e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (imsi != null) {
586e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                country = MccTable.countryCodeForMcc(
587e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                                    Integer.parseInt(imsi.substring(0,3)));
588e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
589e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            log("Setting locale to " + prefLang + "_" + country);
590e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            MccTable.setSystemLocale(mContext, prefLang, country);
591e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        } else {
592e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            log ("No suitable CSIM selected locale");
593e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
594e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
595e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
596c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
597c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    protected void onRecordLoaded() {
598c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // One record loaded successfully or failed, In either case
599c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // we need to update the recordsToLoad count
600c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsToLoad -= 1;
601bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
602c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
603c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (recordsToLoad == 0 && recordsRequested == true) {
604c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            onAllRecordsLoaded();
605c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        } else if (recordsToLoad < 0) {
606bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka            loge("recordsToLoad <0, programmer error suspected");
607c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            recordsToLoad = 0;
608c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
609c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
610c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
611c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
612c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    protected void onAllRecordsLoaded() {
613bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (DBG) log("record load complete");
614bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
615c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Further records that can be inserted are Operator/OEM dependent
616c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
617c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        String operator = getRUIMOperatorNumeric();
618c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        log("RuimRecords: onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
619c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                operator + "'");
620c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
621c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
622c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (mImsi != null) {
623c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
624c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                    MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
625c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
626e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
627e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        setLocaleFromCsim();
628c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsLoadedRegistrants.notifyRegistrants(
629c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            new AsyncResult(null, null, null));
630c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
631c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
632c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
633c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void onReady() {
634c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        fetchRuimRecords();
635c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
636c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
637c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
638c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
639c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
640c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private void fetchRuimRecords() {
641c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsRequested = true;
642c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
643bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (DBG) log("fetchRuimRecords " + recordsToLoad);
644c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
645e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
646c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsToLoad++;
647c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
648c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mFh.loadEFTransparent(EF_ICCID,
649c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                obtainMessage(EVENT_GET_ICCID_DONE));
650c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        recordsToLoad++;
651c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
652e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFTransparent(EF_PL,
653e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
654e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
655e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
656e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFTransparent(EF_CSIM_LI,
657e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded()));
658e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
659e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
660e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFTransparent(EF_CSIM_SPN,
661e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded()));
662e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
663e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
664e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFLinearFixed(EF_CSIM_MDN, 1,
665e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded()));
666e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
667e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
668e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFTransparent(EF_CSIM_IMSIM,
669e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded()));
670e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
671e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
672e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME,
673e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded()));
674e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
675e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
676e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // Entire PRL could be huge. We are only interested in
677e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // the first 4 bytes of the record.
678e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        mFh.loadEFTransparent(EF_CSIM_EPRL, 4,
679e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimEprlLoaded()));
680e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        recordsToLoad++;
681e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
682bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (DBG) log("fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
683c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // Further records that can be inserted are Operator/OEM dependent
684c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
685c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
686c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    /**
687c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * {@inheritDoc}
688c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     *
689c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     * No Display rule for RUIMs yet.
690c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville     */
691c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
692c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public int getDisplayRule(String plmn) {
693c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // TODO together with spn
694c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        return 0;
695c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
696c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
697c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
698e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public boolean isProvisioned() {
699e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // If UICC card has CSIM app, look for MDN and MIN field
700e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // to determine if the SIM is provisioned.  Otherwise,
701e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // consider the SIM is provisioned. (for case of ordinal
702e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // USIM only UICC.)
703e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // If PROPERTY_TEST_CSIM is defined, bypess provision check
704e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        // and consider the SIM is provisioned.
705e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (SystemProperties.getBoolean(PROPERTY_TEST_CSIM, false)) {
706e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return true;
707e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
708e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
709e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (mParentApp == null) {
710e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return false;
711e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
712e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
713e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        if (mParentApp.getType() == AppType.APPTYPE_CSIM &&
714e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            ((mMdn == null) || (mMin == null))) {
715e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return false;
716e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
717e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return true;
718e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
719e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
720e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    @Override
721c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    public void setVoiceMessageWaiting(int line, int countWaiting) {
722c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (line != 1) {
723c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // only profile 1 is supported
724c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return;
725c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
726c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
727c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        // range check
728c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (countWaiting < 0) {
729c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            countWaiting = -1;
730c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        } else if (countWaiting > 0xff) {
731c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // C.S0015-B v2, 4.5.12
732c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // range: 0-99
733c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            countWaiting = 0xff;
734c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
735c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        countVoiceMessages = countWaiting;
736c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
737c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        mRecordsEventsRegistrants.notifyResult(EVENT_MWI);
738c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
739c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
740c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private void handleRuimRefresh(IccRefreshResponse refreshResponse) {
741c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (refreshResponse == null) {
742c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            if (DBG) log("handleRuimRefresh received without input");
743c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return;
744c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
745c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
746c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        if (refreshResponse.aid != null &&
747e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                !refreshResponse.aid.equals(mParentApp.getAid())) {
748c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            // This is for different app. Ignore.
749c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            return;
750c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
751c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
752c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        switch (refreshResponse.refreshResult) {
753c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
754c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
755c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                adnCache.reset();
756c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                fetchRuimRecords();
757c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
758c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case IccRefreshResponse.REFRESH_RESULT_INIT:
759c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
760c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                // need to reload all files (that we care about)
761c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                fetchRuimRecords();
762c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
763c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            case IccRefreshResponse.REFRESH_RESULT_RESET:
764c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
765c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                mCi.setRadioPower(false, null);
766c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                /* Note: no need to call setRadioPower(true).  Assuming the desired
767c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                * radio power state is still ON (as tracked by ServiceStateTracker),
768c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                * ServiceStateTracker will call setRadioPower when it receives the
769c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                * RADIO_STATE_CHANGED notification for the power off.  And if the
770c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                * desired power state has changed in the interim, we don't want to
771c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                * override it with an unconditional power on.
772c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                */
773c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
774c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville            default:
775c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                // unknown refresh operation
776c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                if (DBG) log("handleRuimRefresh with unknown operation");
777c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville                break;
778c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
779c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
780c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
781e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public String getMdn() {
782e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mMdn;
783e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
784e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
785e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public String getMin() {
786e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mMin;
787e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
788e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
789e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public String getSid() {
790e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mHomeSystemId;
791e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
792e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
793e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public String getNid() {
794e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mHomeNetworkId;
795e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
796e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
797e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public boolean getCsimSpnDisplayCondition() {
798e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        return mCsimSpnDisplayCondition;
799e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
800c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
801c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    protected void log(String s) {
802c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        Log.d(LOG_TAG, "[RuimRecords] " + s);
803c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
804c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
805c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    @Override
806c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    protected void loge(String s) {
807c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        Log.e(LOG_TAG, "[RuimRecords] " + s);
808c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
809c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville}
810