Loading src/java/com/android/internal/telephony/uicc/IccCardStatus.java +6 −2 Original line number Diff line number Diff line Loading @@ -121,8 +121,12 @@ public class IccCardStatus { StringBuilder sb = new StringBuilder(); sb.append("IccCardState {").append(mCardState).append(",") .append(mUniversalPinState) .append(",num_apps=").append(mApplications.length); .append(mUniversalPinState); if (mApplications != null) { sb.append(",num_apps=").append(mApplications.length); } else { sb.append(",mApplications=null"); } sb.append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex); if (mApplications != null Loading src/java/com/android/internal/telephony/uicc/UiccController.java +66 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; Loading @@ -25,11 +26,14 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.storage.StorageManager; import android.preference.PreferenceManager; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCardConstants; Loading @@ -37,6 +41,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import java.io.FileDescriptor; import java.io.PrintWriter; Loading Loading @@ -112,15 +117,26 @@ public class UiccController extends Handler { // this needs to be here, because on bootup we dont know which index maps to which UiccSlot private CommandsInterface[] mCis; private UiccSlot[] mUiccSlots; @VisibleForTesting public UiccSlot[] mUiccSlots; private int[] mPhoneIdToSlotId; private boolean mIsSlotStatusSupported = true; // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is // considered sensetive information. private ArrayList<String> mCardStrings; // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID private static final String CARD_STRINGS = "card_strings"; private static final Object mLock = new Object(); private static UiccController mInstance; private static ArrayList<IccSlotStatus> sLastSlotStatus; private Context mContext; @VisibleForTesting public Context mContext; protected RegistrantList mIccChangedRegistrants = new RegistrantList(); Loading Loading @@ -182,6 +198,7 @@ public class UiccController extends Handler { } mLauncher = new UiccStateChangedLauncher(c, this); mCardStrings = loadCardStrings(); } private int getSlotIdFromPhoneId(int phoneId) { Loading Loading @@ -530,10 +547,52 @@ public class UiccController extends Handler { mUiccSlots[slotId].update(mCis[index], status, index); UiccCard card = mUiccSlots[slotId].getUiccCard(); if (card != null && (card.getCardState() == CardState.CARDSTATE_PRESENT)) { // Card.getCardId returns the cardString, not the public card ID int String cardString = card.getCardId(); addCardId(cardString); } if (DBG) log("Notifying IccChangedRegistrants"); mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); } private void addCardId(String cardString) { if (TextUtils.isEmpty(cardString)) { return; } if (!mCardStrings.contains(cardString)) { mCardStrings.add(cardString); saveCardStrings(); } } /** * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId. * Returns -1 if the card string does not map to a cardId. */ public int convertToPublicCardId(String cardString) { return mCardStrings.indexOf(cardString); } private ArrayList<String> loadCardStrings() { String cardStrings = PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, ""); if (TextUtils.isEmpty(cardStrings)) { // just return an empty list, since String.split would return the list { "" } return new ArrayList<String>(); } return new ArrayList<String>(Arrays.asList(cardStrings.split(","))); } private void saveCardStrings() { SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings)); editor.commit(); } private synchronized void onGetSlotStatusDone(AsyncResult ar) { if (!mIsSlotStatusSupported) { if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false"); Loading Loading @@ -592,6 +651,11 @@ public class UiccController extends Handler { } mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss); if (mUiccSlots[i].isEuicc()) { String eid = iss.eid; addCardId(eid); } } if (VDBG) logPhoneIdToSlotIdMapping(); Loading tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java +61 −2 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.os.AsyncResult; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.telephony.TelephonyManager; Loading @@ -41,15 +43,23 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import java.util.ArrayList; public class UiccControllerTest extends TelephonyTest { private UiccController mUiccControllerUT; private UiccControllerHandlerThread mUiccControllerHandlerThread; private static final int PHONE_COUNT = 1; private static int ICC_CHANGED_EVENT = 0; private static final int ICC_CHANGED_EVENT = 0; private static final int EVENT_GET_ICC_STATUS_DONE = 3; private static final int EVENT_GET_SLOT_STATUS_DONE = 4; @Mock private Handler mMockedHandler; @Mock private IccCardStatus mIccCardStatus; @Mock private UiccSlot mMockSlot; @Mock private UiccCard mMockCard; private class UiccControllerHandlerThread extends HandlerThread { Loading Loading @@ -200,4 +210,53 @@ public class UiccControllerTest extends TelephonyTest { mCaptorLong.capture()); assertEquals(ICC_CHANGED_EVENT, mCaptorMessage.getValue().what); } @Test public void testCardIdFromIccStatus() { // Give UiccController a real context so it can use shared preferences mUiccControllerUT.mContext = InstrumentationRegistry.getContext(); // Mock out UiccSlots mUiccControllerUT.mUiccSlots[0] = mMockSlot; doReturn(mMockCard).when(mMockSlot).getUiccCard(); doReturn("A1B2C3D4").when(mMockCard).getCardId(); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mMockCard).getCardState(); // simulate card status loaded IccCardStatus ics = new IccCardStatus(); ics.setCardState(1 /* present */); ics.setUniversalPinState(3 /* disabled */); ics.atr = "abcdef0123456789abcdef"; ics.iccid = "123451234567890"; ics.eid = "A1B2C3D4"; AsyncResult ar = new AsyncResult(null, ics, null); Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar); mUiccControllerUT.handleMessage(msg); // assert that the card ID was created assertEquals(0, mUiccControllerUT.convertToPublicCardId(ics.eid)); } @Test public void testCardIdFromSlotStatus() { // Give UiccController a real context so it can use shared preferences mUiccControllerUT.mContext = InstrumentationRegistry.getContext(); // Mock out UiccSlots mUiccControllerUT.mUiccSlots[0] = mMockSlot; doReturn(true).when(mMockSlot).isEuicc(); // simulate slot status loaded IccSlotStatus iss = new IccSlotStatus(); iss.setSlotState(1 /* active */); iss.eid = "ABADACB"; ArrayList<IccSlotStatus> status = new ArrayList<IccSlotStatus>(); status.add(iss); AsyncResult ar = new AsyncResult(null, status, null); Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_SLOT_STATUS_DONE, ar); mUiccControllerUT.handleMessage(msg); // assert that the card ID was created assertEquals(0, mUiccControllerUT.convertToPublicCardId(iss.eid)); } } tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java +22 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,28 @@ public class EuiccCardTest extends TelephonyTest { } } @Test public void testPassEidInContructor() throws InterruptedException { mMockIccCardStatus.eid = "1A2B3C4D"; mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus, 0 /* phoneId */, new Object()); final int eventEidReady = 0; final CountDownLatch latch = new CountDownLatch(1); Handler handler = new Handler(mTestHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == eventEidReady) { assertEquals("1A2B3C4D", mEuiccCard.getEid()); latch.countDown(); } } }; // This will instantly return, since EID is already set mEuiccCard.registerForEidReady(handler, eventEidReady, null /* obj */); assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS)); } @Test public void testLoadEidAndNotifyRegistrants() throws InterruptedException { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); Loading Loading
src/java/com/android/internal/telephony/uicc/IccCardStatus.java +6 −2 Original line number Diff line number Diff line Loading @@ -121,8 +121,12 @@ public class IccCardStatus { StringBuilder sb = new StringBuilder(); sb.append("IccCardState {").append(mCardState).append(",") .append(mUniversalPinState) .append(",num_apps=").append(mApplications.length); .append(mUniversalPinState); if (mApplications != null) { sb.append(",num_apps=").append(mApplications.length); } else { sb.append(",mApplications=null"); } sb.append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex); if (mApplications != null Loading
src/java/com/android/internal/telephony/uicc/UiccController.java +66 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.AsyncResult; import android.os.Handler; Loading @@ -25,11 +26,14 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.storage.StorageManager; import android.preference.PreferenceManager; import android.telephony.CarrierConfigManager; import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCardConstants; Loading @@ -37,6 +41,7 @@ import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.PhoneFactory; import com.android.internal.telephony.RadioConfig; import com.android.internal.telephony.SubscriptionInfoUpdater; import com.android.internal.telephony.uicc.IccCardStatus.CardState; import java.io.FileDescriptor; import java.io.PrintWriter; Loading Loading @@ -112,15 +117,26 @@ public class UiccController extends Handler { // this needs to be here, because on bootup we dont know which index maps to which UiccSlot private CommandsInterface[] mCis; private UiccSlot[] mUiccSlots; @VisibleForTesting public UiccSlot[] mUiccSlots; private int[] mPhoneIdToSlotId; private boolean mIsSlotStatusSupported = true; // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID). // The array index is the card ID (int). // This mapping exists to expose card-based functionality without exposing the EID, which is // considered sensetive information. private ArrayList<String> mCardStrings; // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID private static final String CARD_STRINGS = "card_strings"; private static final Object mLock = new Object(); private static UiccController mInstance; private static ArrayList<IccSlotStatus> sLastSlotStatus; private Context mContext; @VisibleForTesting public Context mContext; protected RegistrantList mIccChangedRegistrants = new RegistrantList(); Loading Loading @@ -182,6 +198,7 @@ public class UiccController extends Handler { } mLauncher = new UiccStateChangedLauncher(c, this); mCardStrings = loadCardStrings(); } private int getSlotIdFromPhoneId(int phoneId) { Loading Loading @@ -530,10 +547,52 @@ public class UiccController extends Handler { mUiccSlots[slotId].update(mCis[index], status, index); UiccCard card = mUiccSlots[slotId].getUiccCard(); if (card != null && (card.getCardState() == CardState.CARDSTATE_PRESENT)) { // Card.getCardId returns the cardString, not the public card ID int String cardString = card.getCardId(); addCardId(cardString); } if (DBG) log("Notifying IccChangedRegistrants"); mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); } private void addCardId(String cardString) { if (TextUtils.isEmpty(cardString)) { return; } if (!mCardStrings.contains(cardString)) { mCardStrings.add(cardString); saveCardStrings(); } } /** * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId. * Returns -1 if the card string does not map to a cardId. */ public int convertToPublicCardId(String cardString) { return mCardStrings.indexOf(cardString); } private ArrayList<String> loadCardStrings() { String cardStrings = PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, ""); if (TextUtils.isEmpty(cardStrings)) { // just return an empty list, since String.split would return the list { "" } return new ArrayList<String>(); } return new ArrayList<String>(Arrays.asList(cardStrings.split(","))); } private void saveCardStrings() { SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings)); editor.commit(); } private synchronized void onGetSlotStatusDone(AsyncResult ar) { if (!mIsSlotStatusSupported) { if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false"); Loading Loading @@ -592,6 +651,11 @@ public class UiccController extends Handler { } mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss); if (mUiccSlots[i].isEuicc()) { String eid = iss.eid; addCardId(eid); } } if (VDBG) logPhoneIdToSlotIdMapping(); Loading
tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java +61 −2 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.os.AsyncResult; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.telephony.TelephonyManager; Loading @@ -41,15 +43,23 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import java.util.ArrayList; public class UiccControllerTest extends TelephonyTest { private UiccController mUiccControllerUT; private UiccControllerHandlerThread mUiccControllerHandlerThread; private static final int PHONE_COUNT = 1; private static int ICC_CHANGED_EVENT = 0; private static final int ICC_CHANGED_EVENT = 0; private static final int EVENT_GET_ICC_STATUS_DONE = 3; private static final int EVENT_GET_SLOT_STATUS_DONE = 4; @Mock private Handler mMockedHandler; @Mock private IccCardStatus mIccCardStatus; @Mock private UiccSlot mMockSlot; @Mock private UiccCard mMockCard; private class UiccControllerHandlerThread extends HandlerThread { Loading Loading @@ -200,4 +210,53 @@ public class UiccControllerTest extends TelephonyTest { mCaptorLong.capture()); assertEquals(ICC_CHANGED_EVENT, mCaptorMessage.getValue().what); } @Test public void testCardIdFromIccStatus() { // Give UiccController a real context so it can use shared preferences mUiccControllerUT.mContext = InstrumentationRegistry.getContext(); // Mock out UiccSlots mUiccControllerUT.mUiccSlots[0] = mMockSlot; doReturn(mMockCard).when(mMockSlot).getUiccCard(); doReturn("A1B2C3D4").when(mMockCard).getCardId(); doReturn(IccCardStatus.CardState.CARDSTATE_PRESENT).when(mMockCard).getCardState(); // simulate card status loaded IccCardStatus ics = new IccCardStatus(); ics.setCardState(1 /* present */); ics.setUniversalPinState(3 /* disabled */); ics.atr = "abcdef0123456789abcdef"; ics.iccid = "123451234567890"; ics.eid = "A1B2C3D4"; AsyncResult ar = new AsyncResult(null, ics, null); Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_ICC_STATUS_DONE, ar); mUiccControllerUT.handleMessage(msg); // assert that the card ID was created assertEquals(0, mUiccControllerUT.convertToPublicCardId(ics.eid)); } @Test public void testCardIdFromSlotStatus() { // Give UiccController a real context so it can use shared preferences mUiccControllerUT.mContext = InstrumentationRegistry.getContext(); // Mock out UiccSlots mUiccControllerUT.mUiccSlots[0] = mMockSlot; doReturn(true).when(mMockSlot).isEuicc(); // simulate slot status loaded IccSlotStatus iss = new IccSlotStatus(); iss.setSlotState(1 /* active */); iss.eid = "ABADACB"; ArrayList<IccSlotStatus> status = new ArrayList<IccSlotStatus>(); status.add(iss); AsyncResult ar = new AsyncResult(null, status, null); Message msg = Message.obtain(mUiccControllerUT, EVENT_GET_SLOT_STATUS_DONE, ar); mUiccControllerUT.handleMessage(msg); // assert that the card ID was created assertEquals(0, mUiccControllerUT.convertToPublicCardId(iss.eid)); } }
tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java +22 −0 Original line number Diff line number Diff line Loading @@ -165,6 +165,28 @@ public class EuiccCardTest extends TelephonyTest { } } @Test public void testPassEidInContructor() throws InterruptedException { mMockIccCardStatus.eid = "1A2B3C4D"; mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus, 0 /* phoneId */, new Object()); final int eventEidReady = 0; final CountDownLatch latch = new CountDownLatch(1); Handler handler = new Handler(mTestHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == eventEidReady) { assertEquals("1A2B3C4D", mEuiccCard.getEid()); latch.countDown(); } } }; // This will instantly return, since EID is already set mEuiccCard.registerForEidReady(handler, eventEidReady, null /* obj */); assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS)); } @Test public void testLoadEidAndNotifyRegistrants() throws InterruptedException { int channel = mockLogicalChannelResponses("BF3E065A041A2B3C4D9000"); Loading