14de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan/*
24de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * Copyright 2017 The Android Open Source Project
34de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan *
44de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * Licensed under the Apache License, Version 2.0 (the "License");
54de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * you may not use this file except in compliance with the License.
64de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * You may obtain a copy of the License at
74de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan *
84de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan *      http://www.apache.org/licenses/LICENSE-2.0
94de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan *
104de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * Unless required by applicable law or agreed to in writing, software
114de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * distributed under the License is distributed on an "AS IS" BASIS,
124de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * See the License for the specific language governing permissions and
144de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * limitations under the License.
154de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan */
164de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
174de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanpackage com.android.internal.telephony.uicc;
184de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
194de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.app.AlertDialog;
204de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.ActivityNotFoundException;
214de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.ComponentName;
224de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.Context;
234de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.DialogInterface;
244de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.Intent;
254de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.content.res.Resources;
264de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.os.Handler;
274de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.os.Message;
284de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.os.PowerManager;
294de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.telephony.Rlog;
304de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport android.view.WindowManager;
314de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
324de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport com.android.internal.R;
334de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport com.android.internal.telephony.CommandsInterface;
344de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport com.android.internal.telephony.CommandsInterface.RadioState;
3506c1f46c4f7d32f1a9832121f7e4cfe67f6660bcAmit Mahajanimport com.android.internal.telephony.IccCardConstants;
364de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport com.android.internal.telephony.uicc.IccCardStatus.CardState;
372e7e5ab2b4a80d3df4df40157b1cfd5c72e6e4b8Holly Jiuyu Sunimport com.android.internal.telephony.uicc.euicc.EuiccCard;
384de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
394de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport java.io.FileDescriptor;
404de8effafa19167eb55efb666fa275fe419cc615Amit Mahajanimport java.io.PrintWriter;
414de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
424de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan/**
434de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan * This class represents a physical slot on the device.
444de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan */
453caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajanpublic class UiccSlot extends Handler {
464de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private static final String TAG = "UiccSlot";
474de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private static final boolean DBG = true;
484de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
494de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    public static final String EXTRA_ICC_CARD_ADDED =
504de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            "com.android.internal.telephony.uicc.ICC_CARD_ADDED";
51184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li    public static final int INVALID_PHONE_ID = -1;
524de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
534de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private final Object mLock = new Object();
544de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private boolean mActive;
5596170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    private boolean mStateIsUnknown = true;
564de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private CardState mCardState;
574de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private Context mContext;
584de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private CommandsInterface mCi;
594de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private UiccCard mUiccCard;
604de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private RadioState mLastRadioState = RadioState.RADIO_UNAVAILABLE;
61ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    private boolean mIsEuicc;
62ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    private String mIccId;
6328dcffcfdf04b4f5fa16f78219278987febc68e3yinxu    private AnswerToReset mAtr;
64184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li    private int mPhoneId = INVALID_PHONE_ID;
654de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
664de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private static final int EVENT_CARD_REMOVED = 13;
674de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private static final int EVENT_CARD_ADDED = 14;
684de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
693caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    public UiccSlot(Context c, boolean isActive) {
704de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        if (DBG) log("Creating");
713caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        mContext = c;
724de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        mActive = isActive;
73a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen        mCardState = null;
744de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
754de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
764de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    /**
774de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     * Update slot. The main trigger for this is a change in the ICC Card status.
784de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     */
79ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    public void update(CommandsInterface ci, IccCardStatus ics, int phoneId) {
80de72f77373b6b38cd650133c89f6cf72c55ac06byinxu        if (DBG) log("cardStatus update: " + ics.toString());
814de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        synchronized (mLock) {
824de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            CardState oldState = mCardState;
834de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            mCardState = ics.mCardState;
84de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            mIccId = ics.iccid;
8506c1f46c4f7d32f1a9832121f7e4cfe67f6660bcAmit Mahajan            mPhoneId = phoneId;
86ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan            parseAtr(ics.atr);
874de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            mCi = ci;
884de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
894de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            RadioState radioState = mCi.getRadioState();
904de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            if (DBG) {
914de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState);
924de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            }
934de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
94a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            if (absentStateUpdateNeeded(oldState)) {
95a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                updateCardStateAbsent();
96de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            // Because mUiccCard may be updated in both IccCardStatus and IccSlotStatus, we need to
97de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            // create a new UiccCard instance in two scenarios:
98de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            //   1. mCardState is changing from ABSENT to non ABSENT.
99de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            //   2. The latest mCardState is not ABSENT, but there is no UiccCard instance.
100de72f77373b6b38cd650133c89f6cf72c55ac06byinxu            } else if ((oldState == null || oldState == CardState.CARDSTATE_ABSENT
101de72f77373b6b38cd650133c89f6cf72c55ac06byinxu                    || mUiccCard == null) && mCardState != CardState.CARDSTATE_ABSENT) {
1024de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                // No notifications while radio is off or we just powering up
1034de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
1044de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    if (DBG) log("update: notify card added");
1053caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                    sendMessage(obtainMessage(EVENT_CARD_ADDED, null));
1064de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                }
1074de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
1084de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                // card is present in the slot now; create new mUiccCard
1094de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                if (mUiccCard != null) {
1104de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    loge("update: mUiccCard != null when card was present; disposing it now");
1114de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    mUiccCard.dispose();
1124de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                }
1134de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
114ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                if (!mIsEuicc) {
11598a7a2b7cd8e0c4ea787e434ed9c6c6d5ddf8d5fAmit Mahajan                    mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId, mLock);
116ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                } else {
11798a7a2b7cd8e0c4ea787e434ed9c6c6d5ddf8d5fAmit Mahajan                    mUiccCard = new EuiccCard(mContext, mCi, ics, phoneId, mLock);
118ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                }
1193caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            } else {
1203caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                if (mUiccCard != null) {
1213caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                    mUiccCard.update(mContext, mCi, ics);
1223caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                }
1234de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            }
1244de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            mLastRadioState = radioState;
1254de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        }
1264de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
1274de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
128ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    /**
129ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan     * Update slot based on IccSlotStatus.
130ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan     */
131ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    public void update(CommandsInterface ci, IccSlotStatus iss) {
132de72f77373b6b38cd650133c89f6cf72c55ac06byinxu        if (DBG) log("slotStatus update: " + iss.toString());
133ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan        synchronized (mLock) {
134a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            CardState oldState = mCardState;
135ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan            mCi = ci;
136909b9acc801116e577b3856d153a8a65b691409ayinxu            parseAtr(iss.atr);
137909b9acc801116e577b3856d153a8a65b691409ayinxu            mCardState = iss.cardState;
138909b9acc801116e577b3856d153a8a65b691409ayinxu            mIccId = iss.iccid;
139ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan            if (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_INACTIVE) {
140a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                // TODO: (b/79432584) evaluate whether should broadcast card state change
141a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                // even if it's inactive.
142ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                if (mActive) {
143ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                    mActive = false;
14428eb337c9a4d6a9b7b032ff35e0b348ea514bdb7Amit Mahajan                    mLastRadioState = RadioState.RADIO_UNAVAILABLE;
145184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li                    mPhoneId = INVALID_PHONE_ID;
14628eb337c9a4d6a9b7b032ff35e0b348ea514bdb7Amit Mahajan                    if (mUiccCard != null) mUiccCard.dispose();
14796170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu                    nullifyUiccCard(true /* sim state is unknown */);
148ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                }
149a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            } else {
150ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan                mActive = true;
151a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                mPhoneId = iss.logicalSlotIndex;
152a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                if (absentStateUpdateNeeded(oldState)) {
153a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                    updateCardStateAbsent();
154a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                }
155a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                // TODO: (b/79432584) Create UiccCard or EuiccCard object here.
156a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                // Right now It's OK not creating it because Card status update will do it.
157a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                // But we should really make them symmetric.
158ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan            }
159ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan        }
160ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    }
161ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan
162a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen    private boolean absentStateUpdateNeeded(CardState oldState) {
163a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        return (oldState != CardState.CARDSTATE_ABSENT || mUiccCard != null)
164a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                && mCardState == CardState.CARDSTATE_ABSENT;
165a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen    }
166a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen
167a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen    private void updateCardStateAbsent() {
168a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        RadioState radioState =
169a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                (mCi == null) ? RadioState.RADIO_UNAVAILABLE : mCi.getRadioState();
170a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        // No notifications while radio is off or we just powering up
171a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
172a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            if (DBG) log("update: notify card removed");
173a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
174a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        }
175a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen
176a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        UiccController.updateInternalIccState(
177a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen                IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, mPhoneId);
178a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen
179a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        // no card present in the slot now; dispose card and make mUiccCard null
180a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        if (mUiccCard != null) {
181a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen            mUiccCard.dispose();
182a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        }
183a12e3dabbddce9fb8669dfb06627b38f01c5efd4Malcolm Chen        nullifyUiccCard(false /* sim state is not unknown */);
184a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen        mLastRadioState = radioState;
185a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen    }
186a1d802eb4b862a9a796a36072e9b2c805360d834Malcolm Chen
18796170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    // whenever we set mUiccCard to null, we lose the ability to differentiate between absent and
18896170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    // unknown states. To mitigate this, we will us mStateIsUnknown to keep track. The sim is only
18996170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    // unknown if we haven't heard from the radio or if the radio has become unavailable.
19096170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    private void nullifyUiccCard(boolean stateUnknown) {
19196170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu        mStateIsUnknown = stateUnknown;
19296170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu        mUiccCard = null;
19396170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    }
19496170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu
19596170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    public boolean isStateUnknown() {
196a12e3dabbddce9fb8669dfb06627b38f01c5efd4Malcolm Chen        return (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) && mStateIsUnknown;
19796170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu    }
19896170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu
19928dcffcfdf04b4f5fa16f78219278987febc68e3yinxu    private void checkIsEuiccSupported() {
20028dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        if (mAtr != null && mAtr.isEuiccSupported()) {
20128dcffcfdf04b4f5fa16f78219278987febc68e3yinxu            mIsEuicc = true;
20228dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        } else {
20328dcffcfdf04b4f5fa16f78219278987febc68e3yinxu            mIsEuicc = false;
20428dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        }
20528dcffcfdf04b4f5fa16f78219278987febc68e3yinxu    }
20628dcffcfdf04b4f5fa16f78219278987febc68e3yinxu
207ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    private void parseAtr(String atr) {
20828dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        mAtr = AnswerToReset.parseAtr(atr);
20928dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        if (mAtr == null) {
21028dcffcfdf04b4f5fa16f78219278987febc68e3yinxu            return;
21128dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        }
21228dcffcfdf04b4f5fa16f78219278987febc68e3yinxu        checkIsEuiccSupported();
213ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    }
214ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan
215ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    public boolean isEuicc() {
216ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan        return mIsEuicc;
217ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    }
218ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan
219ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    public boolean isActive() {
220ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan        return mActive;
221ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    }
222ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan
223184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li    public int getPhoneId() {
224184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li        return mPhoneId;
225184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li    }
226184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li
227ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    public String getIccId() {
2281acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan        if (mIccId != null) {
2291acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan            return mIccId;
2301acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan        } else if (mUiccCard != null) {
2311acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan            return mUiccCard.getIccId();
2321acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan        } else {
2331acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan            return null;
2341acc4c72ae6e1b7c38e36b96f65330c52b7fd58eAmit Mahajan        }
235ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan    }
236ce32bfe78ca1e8e30f30c04457ce8c700086f769Amit Mahajan
237258ed5bd03c1c2c59749bbaaa59c173f3eec0fb9Qingxi Li    public boolean isExtendedApduSupported() {
238258ed5bd03c1c2c59749bbaaa59c173f3eec0fb9Qingxi Li        return  (mAtr != null && mAtr.isExtendedApduSupported());
239258ed5bd03c1c2c59749bbaaa59c173f3eec0fb9Qingxi Li    }
240258ed5bd03c1c2c59749bbaaa59c173f3eec0fb9Qingxi Li
2414de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    @Override
2424de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    protected void finalize() {
2434de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        if (DBG) log("UiccSlot finalized");
2444de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
2454de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2464de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private void onIccSwap(boolean isAdded) {
2474de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2484de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        boolean isHotSwapSupported = mContext.getResources().getBoolean(
2494de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                R.bool.config_hotswapCapable);
2504de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2514de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        if (isHotSwapSupported) {
2524de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            log("onIccSwap: isHotSwapSupported is true, don't prompt for rebooting");
2534de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            return;
2544de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        }
2554de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        log("onIccSwap: isHotSwapSupported is false, prompt for rebooting");
2564de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2574de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        promptForRestart(isAdded);
2584de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
2594de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2604de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private void promptForRestart(boolean isAdded) {
2614de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        synchronized (mLock) {
2624de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            final Resources res = mContext.getResources();
2634de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            final String dialogComponent = res.getString(
2644de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    R.string.config_iccHotswapPromptForRestartDialogComponent);
2654de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            if (dialogComponent != null) {
2664de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                Intent intent = new Intent().setComponent(ComponentName.unflattenFromString(
2674de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                        dialogComponent)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
2684de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                        .putExtra(EXTRA_ICC_CARD_ADDED, isAdded);
2694de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                try {
2704de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    mContext.startActivity(intent);
2714de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    return;
2724de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                } catch (ActivityNotFoundException e) {
2734de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    loge("Unable to find ICC hotswap prompt for restart activity: " + e);
2744de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                }
2754de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            }
2764de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2774de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            // TODO: Here we assume the device can't handle SIM hot-swap
2784de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            //      and has to reboot. We may want to add a property,
2794de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            //      e.g. REBOOT_ON_SIM_SWAP, to indicate if modem support
2804de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            //      hot-swap.
2814de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            DialogInterface.OnClickListener listener = null;
2824de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2834de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
2844de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            // TODO: SimRecords is not reset while SIM ABSENT (only reset while
2854de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            //       Radio_off_or_not_available). Have to reset in both both
2864de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            //       added or removed situation.
2874de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            listener = new DialogInterface.OnClickListener() {
2884de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                @Override
2894de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                public void onClick(DialogInterface dialog, int which) {
2904de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    synchronized (mLock) {
2914de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                        if (which == DialogInterface.BUTTON_POSITIVE) {
2924de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                            if (DBG) log("Reboot due to SIM swap");
2934de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                            PowerManager pm = (PowerManager) mContext
2944de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                                    .getSystemService(Context.POWER_SERVICE);
2954de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                            pm.reboot("SIM is added.");
2964de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                        }
2974de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    }
2984de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                }
2994de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3004de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            };
3014de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3024de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            Resources r = Resources.getSystem();
3034de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3044de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            String title = (isAdded) ? r.getString(R.string.sim_added_title) :
3054de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    r.getString(R.string.sim_removed_title);
3064de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            String message = (isAdded) ? r.getString(R.string.sim_added_message) :
3074de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    r.getString(R.string.sim_removed_message);
3084de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            String buttonTxt = r.getString(R.string.sim_restart_button);
3094de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3104de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            AlertDialog dialog = new AlertDialog.Builder(mContext)
3114de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    .setTitle(title)
3124de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    .setMessage(message)
3134de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    .setPositiveButton(buttonTxt, listener)
3144de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan                    .create();
3154de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
3164de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan            dialog.show();
3174de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        }
3184de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
3194de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3203caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    @Override
3213caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    public void handleMessage(Message msg) {
3223caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        switch (msg.what) {
3233caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            case EVENT_CARD_REMOVED:
3243caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                onIccSwap(false);
3253caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                break;
3263caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            case EVENT_CARD_ADDED:
3273caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                onIccSwap(true);
3283caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                break;
3293caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            default:
3303caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan                loge("Unknown Event " + msg.what);
3314de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        }
3323caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    }
3334de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3344de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    /**
3354de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     * Returns the state of the UiccCard in the slot.
3364de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     * @return
3374de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     */
3384de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    public CardState getCardState() {
3394de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        synchronized (mLock) {
340a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen            if (mCardState == null) {
341a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen                return CardState.CARDSTATE_ABSENT;
342a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen            } else {
343a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen                return mCardState;
344a3d5188fe326da174471025db03f5a3e4594be20Malcolm Chen            }
3454de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        }
3464de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
3474de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3483caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    /**
3493caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan     * Returns the UiccCard in the slot.
3503caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan     */
3513caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    public UiccCard getUiccCard() {
3523caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        synchronized (mLock) {
3533caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            return mUiccCard;
3543caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        }
3553caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    }
3563caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan
3573caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    /**
3583caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan     * Processes radio state unavailable event
3593caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan     */
3603caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    public void onRadioStateUnavailable() {
3613caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        if (mUiccCard != null) {
3623caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            mUiccCard.dispose();
3633caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        }
36496170b8afa17db4832f5f0e7fab0f64dc2428a64Jordan Liu        nullifyUiccCard(true /* sim state is unknown */);
3654a7b0a1de1c07c26eefda1fe5d2609cd54c2ecbdAmit Mahajan
366184357ae34f91869f31c259af5b53a852c03f8a6Qingxi Li        if (mPhoneId != INVALID_PHONE_ID) {
3672a63f28dd26512f45b706ddab00c18c4f91bc7e4Malcolm Chen            UiccController.updateInternalIccState(
36806c1f46c4f7d32f1a9832121f7e4cfe67f6660bcAmit Mahajan                    IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null, mPhoneId);
36906c1f46c4f7d32f1a9832121f7e4cfe67f6660bcAmit Mahajan        }
3704a7b0a1de1c07c26eefda1fe5d2609cd54c2ecbdAmit Mahajan
3713caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        mCardState = CardState.CARDSTATE_ABSENT;
3723caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        mLastRadioState = RadioState.RADIO_UNAVAILABLE;
3733caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan    }
3743caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan
3754de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private void log(String msg) {
3764de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        Rlog.d(TAG, msg);
3774de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
3784de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3794de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    private void loge(String msg) {
3804de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        Rlog.e(TAG, msg);
3814de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
3824de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan
3834de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    /**
3844de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     * Dump
3854de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan     */
3864de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3874de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println("UiccSlot:");
3884de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println(" mCi=" + mCi);
3894de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println(" mActive=" + mActive);
3904de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println(" mLastRadioState=" + mLastRadioState);
3914de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println(" mCardState=" + mCardState);
3923caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        if (mUiccCard != null) {
3933caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            pw.println(" mUiccCard=" + mUiccCard);
3943caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            mUiccCard.dump(fd, pw, args);
3953caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        } else {
3963caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan            pw.println(" mUiccCard=null");
3973caa000d2f0643c50bf74d85a3e6672e484e25e1Amit Mahajan        }
3984de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.println();
3994de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.flush();
4004de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan        pw.flush();
4014de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan    }
4024de8effafa19167eb55efb666fa275fe419cc615Amit Mahajan}
403