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