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