1/*
2* Copyright (C) 2014 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8*      http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17package com.android.internal.telephony;
18
19import static android.Manifest.permission.READ_PHONE_STATE;
20
21import android.app.ActivityManagerNative;
22import android.app.IUserSwitchObserver;
23import android.content.BroadcastReceiver;
24import android.content.Context;
25import android.content.ContentResolver;
26import android.content.ContentValues;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.SharedPreferences;
30import android.content.pm.IPackageManager;
31import android.os.AsyncResult;
32import android.os.Handler;
33import android.os.IRemoteCallback;
34import android.os.Message;
35import android.os.RemoteException;
36import android.os.ServiceManager;
37import android.os.UserHandle;
38import android.preference.PreferenceManager;
39import android.provider.Settings;
40import android.telephony.Rlog;
41import android.telephony.CarrierConfigManager;
42import android.telephony.SubscriptionManager;
43import android.telephony.SubscriptionInfo;
44import android.telephony.TelephonyManager;
45import com.android.internal.telephony.uicc.IccCardProxy;
46import com.android.internal.telephony.uicc.IccConstants;
47import com.android.internal.telephony.uicc.IccFileHandler;
48import com.android.internal.telephony.uicc.IccRecords;
49import com.android.internal.telephony.uicc.IccUtils;
50
51import android.text.TextUtils;
52
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55import java.util.List;
56
57/**
58 *@hide
59 */
60public class SubscriptionInfoUpdater extends Handler {
61    private static final String LOG_TAG = "SubscriptionInfoUpdater";
62    private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();
63
64    private static final int EVENT_SIM_LOCKED_QUERY_ICCID_DONE = 1;
65    private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
66    private static final int EVENT_SIM_LOADED = 3;
67    private static final int EVENT_SIM_ABSENT = 4;
68    private static final int EVENT_SIM_LOCKED = 5;
69    private static final int EVENT_SIM_IO_ERROR = 6;
70    private static final int EVENT_SIM_UNKNOWN = 7;
71
72    private static final String ICCID_STRING_FOR_NO_SIM = "";
73    /**
74     *  int[] sInsertSimState maintains all slots' SIM inserted status currently,
75     *  it may contain 4 kinds of values:
76     *    SIM_NOT_INSERT : no SIM inserted in slot i now
77     *    SIM_CHANGED    : a valid SIM insert in slot i and is different SIM from last time
78     *                     it will later become SIM_NEW or SIM_REPOSITION during update procedure
79     *    SIM_NOT_CHANGE : a valid SIM insert in slot i and is the same SIM as last time
80     *    SIM_NEW        : a valid SIM insert in slot i and is a new SIM
81     *    SIM_REPOSITION : a valid SIM insert in slot i and is inserted in different slot last time
82     *    positive integer #: index to distinguish SIM cards with the same IccId
83     */
84    public static final int SIM_NOT_CHANGE = 0;
85    public static final int SIM_CHANGED    = -1;
86    public static final int SIM_NEW        = -2;
87    public static final int SIM_REPOSITION = -3;
88    public static final int SIM_NOT_INSERT = -99;
89
90    public static final int STATUS_NO_SIM_INSERTED = 0x00;
91    public static final int STATUS_SIM1_INSERTED = 0x01;
92    public static final int STATUS_SIM2_INSERTED = 0x02;
93    public static final int STATUS_SIM3_INSERTED = 0x04;
94    public static final int STATUS_SIM4_INSERTED = 0x08;
95
96    // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED.
97    public static final String CURR_SUBID = "curr_subid";
98
99    private static Phone[] mPhone;
100    private static Context mContext = null;
101    private static String mIccId[] = new String[PROJECT_SIM_NUM];
102    private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
103    private SubscriptionManager mSubscriptionManager = null;
104    private IPackageManager mPackageManager;
105    // The current foreground user ID.
106    private int mCurrentlyActiveUserId;
107    private CarrierServiceBindHelper mCarrierServiceBindHelper;
108
109    public SubscriptionInfoUpdater(Context context, Phone[] phoneProxy, CommandsInterface[] ci) {
110        logd("Constructor invoked");
111
112        mContext = context;
113        mPhone = phoneProxy;
114        mSubscriptionManager = SubscriptionManager.from(mContext);
115        mPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
116
117        IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
118        intentFilter.addAction(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
119        mContext.registerReceiver(sReceiver, intentFilter);
120
121        mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
122        initializeCarrierApps();
123    }
124
125    private void initializeCarrierApps() {
126        // Initialize carrier apps:
127        // -Now (on system startup)
128        // -Whenever new carrier privilege rules might change (new SIM is loaded)
129        // -Whenever we switch to a new user
130        mCurrentlyActiveUserId = 0;
131        try {
132            ActivityManagerNative.getDefault().registerUserSwitchObserver(
133                    new IUserSwitchObserver.Stub() {
134                @Override
135                public void onUserSwitching(int newUserId, IRemoteCallback reply)
136                        throws RemoteException {
137                    mCurrentlyActiveUserId = newUserId;
138                    CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
139                            mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
140
141                    if (reply != null) {
142                        try {
143                            reply.sendResult(null);
144                        } catch (RemoteException e) {
145                        }
146                    }
147                }
148
149                @Override
150                public void onUserSwitchComplete(int newUserId) {
151                    // Ignore.
152                }
153
154                @Override
155                public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {
156                    // Ignore.
157                }
158            });
159            mCurrentlyActiveUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
160        } catch (RemoteException e) {
161            logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
162        }
163        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
164                mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
165    }
166
167    private final BroadcastReceiver sReceiver = new  BroadcastReceiver() {
168        @Override
169        public void onReceive(Context context, Intent intent) {
170            logd("[Receiver]+");
171            String action = intent.getAction();
172            logd("Action: " + action);
173
174            if (!action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED) &&
175                !action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
176                return;
177            }
178
179            int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
180                    SubscriptionManager.INVALID_SIM_SLOT_INDEX);
181            logd("slotId: " + slotId);
182            if (slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
183                return;
184            }
185
186            String simStatus = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
187            logd("simStatus: " + simStatus);
188
189            if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
190                if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(simStatus)) {
191                    sendMessage(obtainMessage(EVENT_SIM_ABSENT, slotId, -1));
192                } else if (IccCardConstants.INTENT_VALUE_ICC_UNKNOWN.equals(simStatus)) {
193                    sendMessage(obtainMessage(EVENT_SIM_UNKNOWN, slotId, -1));
194                } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(simStatus)) {
195                    sendMessage(obtainMessage(EVENT_SIM_IO_ERROR, slotId, -1));
196                } else {
197                    logd("Ignoring simStatus: " + simStatus);
198                }
199            } else if (action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
200                if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {
201                    String reason = intent.getStringExtra(
202                        IccCardConstants.INTENT_KEY_LOCKED_REASON);
203                    sendMessage(obtainMessage(EVENT_SIM_LOCKED, slotId, -1, reason));
204                } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)) {
205                    sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, -1));
206                } else {
207                    logd("Ignoring simStatus: " + simStatus);
208                }
209            }
210            logd("[Receiver]-");
211        }
212    };
213
214    private boolean isAllIccIdQueryDone() {
215        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
216            if (mIccId[i] == null) {
217                logd("Wait for SIM" + (i + 1) + " IccId");
218                return false;
219            }
220        }
221        logd("All IccIds query complete");
222
223        return true;
224    }
225
226    public void setDisplayNameForNewSub(String newSubName, int subId, int newNameSource) {
227        SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
228        if (subInfo != null) {
229            // overwrite SIM display name if it is not assigned by user
230            int oldNameSource = subInfo.getNameSource();
231            CharSequence oldSubName = subInfo.getDisplayName();
232            logd("[setDisplayNameForNewSub] subId = " + subInfo.getSubscriptionId()
233                    + ", oldSimName = " + oldSubName + ", oldNameSource = " + oldNameSource
234                    + ", newSubName = " + newSubName + ", newNameSource = " + newNameSource);
235            if (oldSubName == null ||
236                (oldNameSource ==
237                    SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE && newSubName != null) ||
238                (oldNameSource == SubscriptionManager.NAME_SOURCE_SIM_SOURCE && newSubName != null
239                        && !newSubName.equals(oldSubName))) {
240                mSubscriptionManager.setDisplayName(newSubName, subInfo.getSubscriptionId(),
241                        newNameSource);
242            }
243        } else {
244            logd("SUB" + (subId + 1) + " SubInfo not created yet");
245        }
246    }
247
248    @Override
249    public void handleMessage(Message msg) {
250        switch (msg.what) {
251            case EVENT_SIM_LOCKED_QUERY_ICCID_DONE: {
252                AsyncResult ar = (AsyncResult)msg.obj;
253                QueryIccIdUserObj uObj = (QueryIccIdUserObj) ar.userObj;
254                int slotId = uObj.slotId;
255                logd("handleMessage : <EVENT_SIM_LOCKED_QUERY_ICCID_DONE> SIM" + (slotId + 1));
256                if (ar.exception == null) {
257                    if (ar.result != null) {
258                        byte[] data = (byte[])ar.result;
259                        mIccId[slotId] = IccUtils.bcdToString(data, 0, data.length);
260                    } else {
261                        logd("Null ar");
262                        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
263                    }
264                } else {
265                    mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
266                    logd("Query IccId fail: " + ar.exception);
267                }
268                logd("sIccId[" + slotId + "] = " + mIccId[slotId]);
269                if (isAllIccIdQueryDone()) {
270                    updateSubscriptionInfoByIccId();
271                }
272                broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED,
273                                         uObj.reason);
274                if (!ICCID_STRING_FOR_NO_SIM.equals(mIccId[slotId])) {
275                    updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
276                }
277                break;
278            }
279
280            case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
281                AsyncResult ar = (AsyncResult)msg.obj;
282                Integer slotId = (Integer)ar.userObj;
283                if (ar.exception == null && ar.result != null) {
284                    int[] modes = (int[])ar.result;
285                    if (modes[0] == 1) {  // Manual mode.
286                        mPhone[slotId].setNetworkSelectionModeAutomatic(null);
287                    }
288                } else {
289                    logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode.");
290                }
291                break;
292            }
293
294           case EVENT_SIM_LOADED:
295                handleSimLoaded(msg.arg1);
296                break;
297
298            case EVENT_SIM_ABSENT:
299                handleSimAbsent(msg.arg1);
300                break;
301
302            case EVENT_SIM_LOCKED:
303                handleSimLocked(msg.arg1, (String) msg.obj);
304                break;
305
306            case EVENT_SIM_UNKNOWN:
307                updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
308                break;
309
310            case EVENT_SIM_IO_ERROR:
311                updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
312                break;
313
314            default:
315                logd("Unknown msg:" + msg.what);
316        }
317    }
318
319    private static class QueryIccIdUserObj {
320        public String reason;
321        public int slotId;
322
323        QueryIccIdUserObj(String reason, int slotId) {
324            this.reason = reason;
325            this.slotId = slotId;
326        }
327    };
328
329    private void handleSimLocked(int slotId, String reason) {
330        if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
331            logd("SIM" + (slotId + 1) + " hot plug in");
332            mIccId[slotId] = null;
333        }
334
335
336        IccFileHandler fileHandler = mPhone[slotId].getIccCard() == null ? null :
337                mPhone[slotId].getIccCard().getIccFileHandler();
338
339        if (fileHandler != null) {
340            String iccId = mIccId[slotId];
341            if (iccId == null) {
342                logd("Querying IccId");
343                fileHandler.loadEFTransparent(IccConstants.EF_ICCID,
344                        obtainMessage(EVENT_SIM_LOCKED_QUERY_ICCID_DONE,
345                                new QueryIccIdUserObj(reason, slotId)));
346            } else {
347                logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
348                updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
349                broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason);
350            }
351        } else {
352            logd("sFh[" + slotId + "] is null, ignore");
353        }
354    }
355
356    private void handleSimLoaded(int slotId) {
357        logd("handleSimStateLoadedInternal: slotId: " + slotId);
358
359        // The SIM should be loaded at this state, but it is possible in cases such as SIM being
360        // removed or a refresh RESET that the IccRecords could be null. The right behavior is to
361        // not broadcast the SIM loaded.
362        IccRecords records = mPhone[slotId].getIccCard().getIccRecords();
363        if (records == null) {  // Possibly a race condition.
364            logd("onRecieve: IccRecords null");
365            return;
366        }
367        if (records.getIccId() == null) {
368            logd("onRecieve: IccID null");
369            return;
370        }
371        mIccId[slotId] = records.getIccId();
372
373        if (isAllIccIdQueryDone()) {
374            updateSubscriptionInfoByIccId();
375        }
376
377        int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
378        int[] subIds = SubscriptionController.getInstance().getSubId(slotId);
379        if (subIds != null) {   // Why an array?
380            subId = subIds[0];
381        }
382
383        if (SubscriptionManager.isValidSubscriptionId(subId)) {
384            String operator = records.getOperatorNumeric();
385            if (operator != null) {
386                if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
387                    MccTable.updateMccMncConfiguration(mContext, operator, false);
388                }
389                SubscriptionController.getInstance().setMccMnc(operator,subId);
390            } else {
391                logd("EVENT_RECORDS_LOADED Operator name is null");
392            }
393            TelephonyManager tm = TelephonyManager.getDefault();
394            String msisdn = tm.getLine1NumberForSubscriber(subId);
395            ContentResolver contentResolver = mContext.getContentResolver();
396
397            if (msisdn != null) {
398                ContentValues number = new ContentValues(1);
399                number.put(SubscriptionManager.NUMBER, msisdn);
400                contentResolver.update(SubscriptionManager.CONTENT_URI, number,
401                        SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
402                        + Long.toString(subId), null);
403            }
404
405            SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
406            String nameToSet;
407            String simCarrierName = tm.getSimOperatorNameForSubscription(subId);
408            ContentValues name = new ContentValues(1);
409
410            if (subInfo != null && subInfo.getNameSource() !=
411                    SubscriptionManager.NAME_SOURCE_USER_INPUT) {
412                if (!TextUtils.isEmpty(simCarrierName)) {
413                    nameToSet = simCarrierName;
414                } else {
415                    nameToSet = "CARD " + Integer.toString(slotId + 1);
416                }
417                name.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
418                logd("sim name = " + nameToSet);
419                contentResolver.update(SubscriptionManager.CONTENT_URI, name,
420                        SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
421                        + "=" + Long.toString(subId), null);
422            }
423
424            /* Update preferred network type and network selection mode on SIM change.
425             * Storing last subId in SharedPreference for now to detect SIM change. */
426            SharedPreferences sp =
427                    PreferenceManager.getDefaultSharedPreferences(mContext);
428            int storedSubId = sp.getInt(CURR_SUBID + slotId, -1);
429
430            if (storedSubId != subId) {
431                int networkType = RILConstants.PREFERRED_NETWORK_MODE;
432
433                // Set the modem network mode
434                mPhone[slotId].setPreferredNetworkType(networkType, null);
435                Settings.Global.putInt(mPhone[slotId].getContext().getContentResolver(),
436                        Settings.Global.PREFERRED_NETWORK_MODE + subId,
437                        networkType);
438
439                // Only support automatic selection mode on SIM change.
440                mPhone[slotId].getNetworkSelectionMode(
441                        obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE, new Integer(slotId)));
442
443                // Update stored subId
444                SharedPreferences.Editor editor = sp.edit();
445                editor.putInt(CURR_SUBID + slotId, subId);
446                editor.apply();
447            }
448        } else {
449            logd("Invalid subId, could not update ContentResolver");
450        }
451
452        // Update set of enabled carrier apps now that the privilege rules may have changed.
453        CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
454                mPackageManager, TelephonyManager.getDefault(), mCurrentlyActiveUserId);
455
456        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
457        updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
458    }
459
460    private void updateCarrierServices(int slotId, String simState) {
461        CarrierConfigManager configManager = (CarrierConfigManager)
462                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
463        configManager.updateConfigForPhoneId(slotId, simState);
464        mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
465    }
466
467    private void handleSimAbsent(int slotId) {
468        if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
469            logd("SIM" + (slotId + 1) + " hot plug out");
470        }
471        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
472        if (isAllIccIdQueryDone()) {
473            updateSubscriptionInfoByIccId();
474        }
475        updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
476    }
477
478    /**
479     * TODO: Simplify more, as no one is interested in what happened
480     * only what the current list contains.
481     */
482    synchronized private void updateSubscriptionInfoByIccId() {
483        logd("updateSubscriptionInfoByIccId:+ Start");
484
485        mSubscriptionManager.clearSubscriptionInfo();
486
487        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
488            mInsertSimState[i] = SIM_NOT_CHANGE;
489        }
490
491        int insertedSimCount = PROJECT_SIM_NUM;
492        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
493            if (ICCID_STRING_FOR_NO_SIM.equals(mIccId[i])) {
494                insertedSimCount--;
495                mInsertSimState[i] = SIM_NOT_INSERT;
496            }
497        }
498        logd("insertedSimCount = " + insertedSimCount);
499
500        int index = 0;
501        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
502            if (mInsertSimState[i] == SIM_NOT_INSERT) {
503                continue;
504            }
505            index = 2;
506            for (int j = i + 1; j < PROJECT_SIM_NUM; j++) {
507                if (mInsertSimState[j] == SIM_NOT_CHANGE && mIccId[i].equals(mIccId[j])) {
508                    mInsertSimState[i] = 1;
509                    mInsertSimState[j] = index;
510                    index++;
511                }
512            }
513        }
514
515        ContentResolver contentResolver = mContext.getContentResolver();
516        String[] oldIccId = new String[PROJECT_SIM_NUM];
517        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
518            oldIccId[i] = null;
519            List<SubscriptionInfo> oldSubInfo =
520                    SubscriptionController.getInstance().getSubInfoUsingSlotIdWithCheck(i, false,
521                    mContext.getOpPackageName());
522            if (oldSubInfo != null) {
523                oldIccId[i] = oldSubInfo.get(0).getIccId();
524                logd("updateSubscriptionInfoByIccId: oldSubId = "
525                        + oldSubInfo.get(0).getSubscriptionId());
526                if (mInsertSimState[i] == SIM_NOT_CHANGE && !mIccId[i].equals(oldIccId[i])) {
527                    mInsertSimState[i] = SIM_CHANGED;
528                }
529                if (mInsertSimState[i] != SIM_NOT_CHANGE) {
530                    ContentValues value = new ContentValues(1);
531                    value.put(SubscriptionManager.SIM_SLOT_INDEX,
532                            SubscriptionManager.INVALID_SIM_SLOT_INDEX);
533                    contentResolver.update(SubscriptionManager.CONTENT_URI, value,
534                            SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
535                            + Integer.toString(oldSubInfo.get(0).getSubscriptionId()), null);
536                }
537            } else {
538                if (mInsertSimState[i] == SIM_NOT_CHANGE) {
539                    // no SIM inserted last time, but there is one SIM inserted now
540                    mInsertSimState[i] = SIM_CHANGED;
541                }
542                oldIccId[i] = ICCID_STRING_FOR_NO_SIM;
543                logd("updateSubscriptionInfoByIccId: No SIM in slot " + i + " last time");
544            }
545        }
546
547        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
548            logd("updateSubscriptionInfoByIccId: oldIccId[" + i + "] = " + oldIccId[i] +
549                    ", sIccId[" + i + "] = " + mIccId[i]);
550        }
551
552        //check if the inserted SIM is new SIM
553        int nNewCardCount = 0;
554        int nNewSimStatus = 0;
555        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
556            if (mInsertSimState[i] == SIM_NOT_INSERT) {
557                logd("updateSubscriptionInfoByIccId: No SIM inserted in slot " + i + " this time");
558            } else {
559                if (mInsertSimState[i] > 0) {
560                    //some special SIMs may have the same IccIds, add suffix to distinguish them
561                    //FIXME: addSubInfoRecord can return an error.
562                    mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i]
563                            + Integer.toString(mInsertSimState[i]), i);
564                    logd("SUB" + (i + 1) + " has invalid IccId");
565                } else /*if (sInsertSimState[i] != SIM_NOT_INSERT)*/ {
566                    mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i], i);
567                }
568                if (isNewSim(mIccId[i], oldIccId)) {
569                    nNewCardCount++;
570                    switch (i) {
571                        case PhoneConstants.SUB1:
572                            nNewSimStatus |= STATUS_SIM1_INSERTED;
573                            break;
574                        case PhoneConstants.SUB2:
575                            nNewSimStatus |= STATUS_SIM2_INSERTED;
576                            break;
577                        case PhoneConstants.SUB3:
578                            nNewSimStatus |= STATUS_SIM3_INSERTED;
579                            break;
580                        //case PhoneConstants.SUB3:
581                        //    nNewSimStatus |= STATUS_SIM4_INSERTED;
582                        //    break;
583                    }
584
585                    mInsertSimState[i] = SIM_NEW;
586                }
587            }
588        }
589
590        for (int i = 0; i < PROJECT_SIM_NUM; i++) {
591            if (mInsertSimState[i] == SIM_CHANGED) {
592                mInsertSimState[i] = SIM_REPOSITION;
593            }
594            logd("updateSubscriptionInfoByIccId: sInsertSimState[" + i + "] = "
595                    + mInsertSimState[i]);
596        }
597
598        List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
599        int nSubCount = (subInfos == null) ? 0 : subInfos.size();
600        logd("updateSubscriptionInfoByIccId: nSubCount = " + nSubCount);
601        for (int i=0; i < nSubCount; i++) {
602            SubscriptionInfo temp = subInfos.get(i);
603
604            String msisdn = TelephonyManager.getDefault().getLine1NumberForSubscriber(
605                    temp.getSubscriptionId());
606
607            if (msisdn != null) {
608                ContentValues value = new ContentValues(1);
609                value.put(SubscriptionManager.NUMBER, msisdn);
610                contentResolver.update(SubscriptionManager.CONTENT_URI, value,
611                        SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
612                        + Integer.toString(temp.getSubscriptionId()), null);
613            }
614        }
615
616        // Ensure the modems are mapped correctly
617        mSubscriptionManager.setDefaultDataSubId(mSubscriptionManager.getDefaultDataSubId());
618
619        SubscriptionController.getInstance().notifySubscriptionInfoChanged();
620        logd("updateSubscriptionInfoByIccId:- SsubscriptionInfo update complete");
621    }
622
623    private boolean isNewSim(String iccId, String[] oldIccId) {
624        boolean newSim = true;
625        for(int i = 0; i < PROJECT_SIM_NUM; i++) {
626            if(iccId.equals(oldIccId[i])) {
627                newSim = false;
628                break;
629            }
630        }
631        logd("newSim = " + newSim);
632
633        return newSim;
634    }
635
636    private void broadcastSimStateChanged(int slotId, String state, String reason) {
637        Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
638        // TODO - we'd like this intent to have a single snapshot of all sim state,
639        // but until then this should not use REPLACE_PENDING or we may lose
640        // information
641        // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
642        //         | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
643        i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
644        i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
645        i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
646        i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
647        SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
648        logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " +
649             IccCardConstants.INTENT_VALUE_ICC_LOADED + " reason " + null +
650             " for mCardIndex : " + slotId);
651        ActivityManagerNative.broadcastStickyIntent(i, READ_PHONE_STATE,
652                UserHandle.USER_ALL);
653    }
654
655    public void dispose() {
656        logd("[dispose]");
657        mContext.unregisterReceiver(sReceiver);
658    }
659
660    private void logd(String message) {
661        Rlog.d(LOG_TAG, message);
662    }
663
664    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
665        pw.println("SubscriptionInfoUpdater:");
666        mCarrierServiceBindHelper.dump(fd, pw, args);
667    }
668}
669