1c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville/*
2e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Copyright (C) 2011-2012 The Android Open Source Project
3c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
4c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Licensed under the Apache License, Version 2.0 (the "License");
5c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * you may not use this file except in compliance with the License.
6c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * You may obtain a copy of the License at
7c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
8c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *      http://www.apache.org/licenses/LICENSE-2.0
9c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville *
10c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * Unless required by applicable law or agreed to in writing, software
11c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * distributed under the License is distributed on an "AS IS" BASIS,
12c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * See the License for the specific language governing permissions and
14c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * limitations under the License.
15c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */
16c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
17c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Savillepackage com.android.internal.telephony.uicc;
18c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
19e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport android.content.Context;
20bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport android.os.AsyncResult;
21bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport android.os.Handler;
22bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport android.os.Message;
23bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport android.os.Registrant;
24bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkaimport android.os.RegistrantList;
25390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajanimport android.os.SystemProperties;
267695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajanimport android.os.storage.StorageManager;
27a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport android.telephony.TelephonyManager;
28ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Savilleimport android.telephony.Rlog;
294cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawalimport android.text.format.Time;
30c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
31e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenkaimport com.android.internal.telephony.CommandsInterface;
32a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.PhoneConstants;
33a8467dd0c524787104b1ccdddc5e8af10ba729edWink Savilleimport com.android.internal.telephony.SubscriptionController;
34e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
3505ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenkaimport java.io.FileDescriptor;
3605ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenkaimport java.io.PrintWriter;
374cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawalimport java.util.LinkedList;
3805ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka
39e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka/**
40e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * This class is responsible for keeping all knowledge about
41e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Universal Integrated Circuit Card (UICC), also know as SIM's,
42e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * in the system. It is also used as API to get appropriate
43c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville * applications to pass them to phone and service trackers.
44e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
45e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * UiccController is created with the call to make() function.
46e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * UiccController is a singleton and make() must only be called once
47e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * and throws an exception if called multiple times.
48e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
49e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
50e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * notifications. When such notification arrives UiccController will call
51e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
52e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * request appropriate tree of uicc objects will be created.
53e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
54e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Following is class diagram for uicc classes:
55e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
56e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                       UiccController
57e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                            #
58e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                            |
59e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                        UiccCard
60e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                          #   #
61e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                          |   ------------------
62e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                    UiccCardApplication    CatService
63e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                      #            #
64e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                      |            |
65e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                 IccRecords    IccFileHandler
66e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                 ^ ^ ^           ^ ^ ^ ^ ^
67e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *    SIMRecords---- | |           | | | | ---SIMFileHandler
68e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *    RuimRecords----- |           | | | ----RuimFileHandler
69e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *    IsimUiccRecords---           | | -----UsimFileHandler
70e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                                 | ------CsimFileHandler
71e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *                                 ----IsimFileHandler
72e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
73e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * Legend: # stands for Composition
74e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *         ^ stands for Generalization
75e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka *
76e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka * See also {@link com.android.internal.telephony.IccCard}
77cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville * and {@link com.android.internal.telephony.uicc.IccCardProxy}
78c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville */
79bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenkapublic class UiccController extends Handler {
80c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static final boolean DBG = true;
81cbaa45bbf2cab852b6c9c3a887e9f803d4e857eaWink Saville    private static final String LOG_TAG = "UiccController";
82c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
83e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public static final int APP_FAM_3GPP =  1;
84e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public static final int APP_FAM_3GPP2 = 2;
85e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    public static final int APP_FAM_IMS   = 3;
86e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
87bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    private static final int EVENT_ICC_STATUS_CHANGED = 1;
88bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    private static final int EVENT_GET_ICC_STATUS_DONE = 2;
895d8e4457b03d166aa249989916b66a85df898516Steven Liu    private static final int EVENT_RADIO_UNAVAILABLE = 3;
9062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal    private static final int EVENT_SIM_REFRESH = 4;
91bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
92390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan    private static final String DECRYPT_STATE = "trigger_restart_framework";
93390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan
94a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private CommandsInterface[] mCis;
95a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private UiccCard[] mUiccCards = new UiccCard[TelephonyManager.getDefault().getPhoneCount()];
96a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
97e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private static final Object mLock = new Object();
98c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private static UiccController mInstance;
99c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
100e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    private Context mContext;
101bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
102a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    protected RegistrantList mIccChangedRegistrants = new RegistrantList();
103c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
104c556e9a3149b6cbd4517fe02aae11689ec5a4e03Polina Bondarenko    private UiccStateChangedLauncher mLauncher;
105c556e9a3149b6cbd4517fe02aae11689ec5a4e03Polina Bondarenko
1064cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    // Logging for dumpsys. Useful in cases when the cards run into errors.
1074cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    private static final int MAX_PROACTIVE_COMMANDS_TO_LOG = 20;
1084cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    private LinkedList<String> mCardLogs = new LinkedList<String>();
1094cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal
110a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    public static UiccController make(Context c, CommandsInterface[] ci) {
111a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        synchronized (mLock) {
112a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            if (mInstance != null) {
113a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                throw new RuntimeException("MSimUiccController.make() should only be called once");
114a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
115a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            mInstance = new UiccController(c, ci);
116a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return (UiccController)mInstance;
117a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
118a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
119a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
120a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private UiccController(Context c, CommandsInterface []ci) {
121a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (DBG) log("Creating UiccController");
122a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mContext = c;
123a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mCis = ci;
124a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        for (int i = 0; i < mCis.length; i++) {
125a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            Integer index = new Integer(i);
126a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
127a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            // TODO remove this once modem correctly notifies the unsols
1287695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan            // If the device has been decrypted or FBE is supported, read SIM when radio state is
1297695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan            // available.
1307695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan            // Else wait for radio to be on. This is needed for the scenario when SIM is locked --
1317695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan            // to avoid overlap of CryptKeeper and SIM unlock screen.
1327695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan            if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) ||
1337695051bf2bb6562ad6a9b5fa7616cd1002f245aAmit Mahajan                    StorageManager.isFileEncryptedNativeOrEmulated()) {
134390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan                mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
135390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan            } else {
136390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan                mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
137390c357ab9e1300f03d7477bf9d86bf67a3c8413Amit Mahajan            }
1385d8e4457b03d166aa249989916b66a85df898516Steven Liu            mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index);
13962648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index);
140a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
141c556e9a3149b6cbd4517fe02aae11689ec5a4e03Polina Bondarenko
142c556e9a3149b6cbd4517fe02aae11689ec5a4e03Polina Bondarenko        mLauncher = new UiccStateChangedLauncher(c, this);
143a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
144c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
145bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    public static UiccController getInstance() {
146e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        synchronized (mLock) {
147e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            if (mInstance == null) {
148e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                throw new RuntimeException(
149e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                        "UiccController.getInstance can't be called before make()");
150e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
151e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return mInstance;
152e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
153e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka    }
154e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
155062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal    public UiccCard getUiccCard(int phoneId) {
156e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        synchronized (mLock) {
157062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal            if (isValidCardIndex(phoneId)) {
158062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal                return mUiccCards[phoneId];
159e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
160e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            return null;
161e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
162bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    }
163bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
164a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    public UiccCard[] getUiccCards() {
165a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        // Return cloned array since we don't want to give out reference
166a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        // to internal data structure.
167a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        synchronized (mLock) {
168a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return mUiccCards.clone();
169a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
170a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
171a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
172a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    // Easy to use API
173062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal    public IccRecords getIccRecords(int phoneId, int family) {
174a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        synchronized (mLock) {
175062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal            UiccCardApplication app = getUiccCardApplication(phoneId, family);
176a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            if (app != null) {
177a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                return app.getIccRecords();
178a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
179a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return null;
180a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
181a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
182a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
183a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    // Easy to use API
184062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal    public IccFileHandler getIccFileHandler(int phoneId, int family) {
185a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        synchronized (mLock) {
186062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal            UiccCardApplication app = getUiccCardApplication(phoneId, family);
187a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            if (app != null) {
188a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                return app.getIccFileHandler();
189a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
190a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return null;
191a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
192a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
193a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
194c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
195bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    //Notifies when card status changes
196bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    public void registerForIccChanged(Handler h, int what, Object obj) {
197e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        synchronized (mLock) {
198e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            Registrant r = new Registrant (h, what, obj);
199e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mIccChangedRegistrants.add(r);
200e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            //Notify registrant right after registering, so that it will get the latest ICC status,
201e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            //otherwise which may not happen until there is an actual change in ICC status.
202e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            r.notifyRegistrant();
203e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
204bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    }
205e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka
206bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    public void unregisterForIccChanged(Handler h) {
207e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        synchronized (mLock) {
208e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            mIccChangedRegistrants.remove(h);
209e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        }
210bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    }
211bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
212bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    @Override
213bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    public void handleMessage (Message msg) {
214e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        synchronized (mLock) {
215a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            Integer index = getCiIndex(msg);
216a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
217a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            if (index < 0 || index >= mCis.length) {
218a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what);
219a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                return;
220a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
221a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
22262648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            AsyncResult ar = (AsyncResult)msg.obj;
223e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            switch (msg.what) {
224e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case EVENT_ICC_STATUS_CHANGED:
225e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
226a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                    mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
227e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    break;
228e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                case EVENT_GET_ICC_STATUS_DONE:
229e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
230a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                    onGetIccCardStatusDone(ar, index);
231e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                    break;
2325d8e4457b03d166aa249989916b66a85df898516Steven Liu                case EVENT_RADIO_UNAVAILABLE:
2335d8e4457b03d166aa249989916b66a85df898516Steven Liu                    if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
2345d8e4457b03d166aa249989916b66a85df898516Steven Liu                    if (mUiccCards[index] != null) {
2355d8e4457b03d166aa249989916b66a85df898516Steven Liu                        mUiccCards[index].dispose();
2365d8e4457b03d166aa249989916b66a85df898516Steven Liu                    }
2375d8e4457b03d166aa249989916b66a85df898516Steven Liu                    mUiccCards[index] = null;
2385d8e4457b03d166aa249989916b66a85df898516Steven Liu                    mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
2395d8e4457b03d166aa249989916b66a85df898516Steven Liu                    break;
24062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                case EVENT_SIM_REFRESH:
24162648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                    if (DBG) log("Received EVENT_SIM_REFRESH");
24262648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                    onSimRefresh(ar, index);
24362648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                    break;
244e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka                default:
245ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville                    Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
246e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            }
247bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        }
248bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    }
249bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
250a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private Integer getCiIndex(Message msg) {
251a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        AsyncResult ar;
252a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        Integer index = new Integer(PhoneConstants.DEFAULT_CARD_INDEX);
253a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
254a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        /*
255a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville         * The events can be come in two ways. By explicitly sending it using
256a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville         * sendMessage, in this case the user object passed is msg.obj and from
257a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville         * the CommandsInterface, in this case the user object is msg.obj.userObj
258a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville         */
259a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (msg != null) {
260a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            if (msg.obj != null && msg.obj instanceof Integer) {
261a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                index = (Integer)msg.obj;
262a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            } else if(msg.obj != null && msg.obj instanceof AsyncResult) {
263a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                ar = (AsyncResult)msg.obj;
264a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                if (ar.userObj != null && ar.userObj instanceof Integer) {
265a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                    index = (Integer)ar.userObj;
266a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                }
267a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
268a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
269a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        return index;
270a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
271a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
272a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    // Easy to use API
273062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal    public UiccCardApplication getUiccCardApplication(int phoneId, int family) {
274a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        synchronized (mLock) {
275062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal            if (isValidCardIndex(phoneId)) {
276062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal                UiccCard c = mUiccCards[phoneId];
277a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                if (c != null) {
278062a2a3838c8d8adf16f4d9fbde8d52450da0336Shishir Agrawal                    return mUiccCards[phoneId].getApplication(family);
279a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville                }
280a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            }
281a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return null;
282a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
283a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
284a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
285a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
286bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (ar.exception != null) {
287ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville            Rlog.e(LOG_TAG,"Error getting ICC status. "
288bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka                    + "RIL_REQUEST_GET_ICC_STATUS should "
289bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka                    + "never return an error", ar.exception);
290bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka            return;
291c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville        }
292a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (!isValidCardIndex(index)) {
293a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
294a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            return;
295a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        }
296c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville
297bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        IccCardStatus status = (IccCardStatus)ar.result;
298bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
299a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        if (mUiccCards[index] == null) {
300e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            //Create new card
301a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
302e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka        } else {
303e287feac673ff68565b766e0e463d105fa9cef9dAlex Yakavenka            //Update already existing card
304a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville            mUiccCards[index].update(mContext, mCis[index] , status);
305bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        }
306bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
307bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka        if (DBG) log("Notifying IccChangedRegistrants");
308a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
309a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
310a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    }
311a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
31262648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal    private void onSimRefresh(AsyncResult ar, Integer index) {
31362648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        if (ar.exception != null) {
31462648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            Rlog.e(LOG_TAG, "Sim REFRESH with exception: " + ar.exception);
31562648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            return;
31662648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        }
31762648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
31862648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        if (!isValidCardIndex(index)) {
31962648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
32062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            return;
32162648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        }
32262648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
32362648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        IccRefreshResponse resp = (IccRefreshResponse) ar.result;
32462648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        Rlog.d(LOG_TAG, "onSimRefresh: " + resp);
32562648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
32662648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        if (mUiccCards[index] == null) {
32762648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
32862648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            return;
32962648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        }
33062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
331626e120359bef26ef72c710c0d2d1c7b7d76722bShishir Agrawal        if (resp.refreshResult != IccRefreshResponse.REFRESH_RESULT_RESET) {
332626e120359bef26ef72c710c0d2d1c7b7d76722bShishir Agrawal          Rlog.d(LOG_TAG, "Ignoring non reset refresh: " + resp);
333626e120359bef26ef72c710c0d2d1c7b7d76722bShishir Agrawal          return;
33462648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        }
33562648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
336626e120359bef26ef72c710c0d2d1c7b7d76722bShishir Agrawal        Rlog.d(LOG_TAG, "Handling refresh reset: " + resp);
337626e120359bef26ef72c710c0d2d1c7b7d76722bShishir Agrawal
33862648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        boolean changed = mUiccCards[index].resetAppWithAid(resp.aid);
33962648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        if (changed) {
34062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean(
34162648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset);
34262648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            if (requirePowerOffOnSimRefreshReset) {
34362648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                mCis[index].setRadioPower(false, null);
34462648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            } else {
34562648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal                mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
34662648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            }
34762648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal            mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
34862648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal        }
34962648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal    }
35062648296ee1514d871d7d779d6f33da5e55babcaShishir Agrawal
351a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville    private boolean isValidCardIndex(int index) {
352a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville        return (index >= 0 && index < mUiccCards.length);
353bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka    }
354bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka
355c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    private void log(String string) {
356ded9c0af7fa49504c047275ed34c2d3b22bf0c3aWink Saville        Rlog.d(LOG_TAG, string);
357c38bb60d867c5d61d90b7179a9ed2b2d1848124fWink Saville    }
35805ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka
3594cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    // TODO: This is hacky. We need a better way of saving the logs.
3604cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    public void addCardLog(String data) {
3614cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        Time t = new Time();
3624cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        t.setToNow();
3634cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        mCardLogs.addLast(t.format("%m-%d %H:%M:%S") + " " + data);
3644cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        if (mCardLogs.size() > MAX_PROACTIVE_COMMANDS_TO_LOG) {
3654cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal            mCardLogs.removeFirst();
3664cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        }
3674cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal    }
368a8467dd0c524787104b1ccdddc5e8af10ba729edWink Saville
36905ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
37005ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.println("UiccController: " + this);
37105ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.println(" mContext=" + mContext);
37205ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.println(" mInstance=" + mInstance);
37305ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size());
37405ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        for (int i = 0; i < mIccChangedRegistrants.size(); i++) {
37505ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka            pw.println("  mIccChangedRegistrants[" + i + "]="
37605ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka                    + ((Registrant)mIccChangedRegistrants.get(i)).getHandler());
37705ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        }
37805ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.println();
37905ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka        pw.flush();
38038aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        pw.println(" mUiccCards: size=" + mUiccCards.length);
38138aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        for (int i = 0; i < mUiccCards.length; i++) {
38238aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            if (mUiccCards[i] == null) {
38338aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal                pw.println("  mUiccCards[" + i + "]=null");
38438aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            } else {
38538aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal                pw.println("  mUiccCards[" + i + "]=" + mUiccCards[i]);
38638aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal                mUiccCards[i].dump(fd, pw, args);
38738aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal            }
38838aa6d75f4edfe03a20826952e41572127bcd6c9Shishir Agrawal        }
3894cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        pw.println("mCardLogs: ");
3904cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        for (int i = 0; i < mCardLogs.size(); ++i) {
3914cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal            pw.println("  " + mCardLogs.get(i));
3924cdf0a453fa3df6015032ec5cbb8d3253b6f81daShishir Agrawal        }
39305ef3b65972826780859b9acbd1fa9580d099832Alex Yakavenka    }
394bb36adde615d3d85fa0fc23935197c6bc6a799edAlex Yakavenka}
395