Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f1f1d19 authored by nharold's avatar nharold Committed by android-build-merger
Browse files

Merge "Change initial IccCardProxy Card State to UNKNOWN" am: d9f54a31 am: a5a41171

am: aa3bc759

Change-Id: I57b5376dcfb84068b32276bac46c3b7a2c6c8187
parents af8bc6b7 aa3bc759
Loading
Loading
Loading
Loading
+44 −19
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;

import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.CommandsInterface.RadioState;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
@@ -105,7 +106,7 @@ public class IccCardProxy extends Handler implements IccCard {
    private UiccCardApplication mUiccApplication = null;
    private IccRecords mIccRecords = null;
    private CdmaSubscriptionSourceManager mCdmaSSM = null;
    private boolean mRadioOn = false;
    private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE;
    private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
                                        // ACTION_SIM_STATE_CHANGED intents
    private boolean mInitialized = false;
@@ -128,7 +129,6 @@ public class IccCardProxy extends Handler implements IccCard {
        ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);

        resetProperties();
        setExternalState(State.NOT_READY, false);
    }

    public void dispose() {
@@ -209,15 +209,18 @@ public class IccCardProxy extends Handler implements IccCard {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EVENT_RADIO_OFF_OR_UNAVAILABLE:
                mRadioOn = false;
                if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
                    setExternalState(State.NOT_READY);
                }
                mRadioState = mCi.getRadioState();
                updateExternalState();
                break;
            case EVENT_RADIO_ON:
                mRadioOn = true;
                mRadioState = RadioState.RADIO_ON;
                if (!mInitialized) {
                    updateQuietMode();
                } else {
                    // updateQuietMode() triggers ICC_CHANGED, which eventually
                    // calls updateExternalState; thus, we don't need this in the
                    // above case
                    updateExternalState();
                }
                break;
            case EVENT_ICC_CHANGED:
@@ -324,11 +327,9 @@ public class IccCardProxy extends Handler implements IccCard {
    private void updateIccAvailability() {
        synchronized (mLock) {
            UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
            CardState state = CardState.CARDSTATE_ABSENT;
            UiccCardApplication newApp = null;
            IccRecords newRecords = null;
            if (newCard != null) {
                state = newCard.getCardState();
                newApp = newCard.getApplication(mCurrentAppType);
                if (newApp != null) {
                    newRecords = newApp.getIccRecords();
@@ -336,7 +337,7 @@ public class IccCardProxy extends Handler implements IccCard {
            }

            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
                if (DBG) log("Icc changed. Reregestering.");
                if (DBG) log("Icc changed. Reregistering.");
                unregisterUiccCardEvents();
                mUiccCard = newCard;
                mUiccApplication = newApp;
@@ -366,15 +367,27 @@ public class IccCardProxy extends Handler implements IccCard {
        // mUiccCard could be null at bootup, before valid card states have
        // been received from UiccController.
        if (mUiccCard == null) {
            setExternalState(State.NOT_READY);
            setExternalState(State.UNKNOWN);
            return;
        }

        if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
            if (mRadioOn) {
                setExternalState(State.ABSENT);
            /*
             * Both IccCardProxy and UiccController are registered for
             * RadioState changes. When the UiccController receives a radio
             * state changed to Unknown it will dispose of all of the IccCard
             * objects, which will then notify the IccCardProxy and the null
             * object will force the state to unknown. However, because the
             * IccCardProxy is also registered for RadioState changes, it will
             * recieve that signal first. By triggering on radio state changes
             * directly, we reduce the time window during which the modem is
             * UNAVAILABLE but the IccStatus is reported as something valid.
             * This is not ideal.
             */
            if (mRadioState == RadioState.RADIO_UNAVAILABLE) {
                setExternalState(State.UNKNOWN);
            } else {
                setExternalState(State.NOT_READY);
                setExternalState(State.ABSENT);
            }
            return;
        }
@@ -394,9 +407,20 @@ public class IccCardProxy extends Handler implements IccCard {
            return;
        }

        // By process of elimination, the UICC Card State = PRESENT
        switch (mUiccApplication.getState()) {
            case APPSTATE_UNKNOWN:
                setExternalState(State.UNKNOWN);
                /*
                 * APPSTATE_UNKNOWN is a catch-all state reported whenever the app
                 * is not explicitly in one of the other states. To differentiate the
                 * case where we know that there is a card present, but the APP is not
                 * ready, we choose NOT_READY here instead of unknown. This is possible
                 * in at least two cases:
                 * 1) A transient during the process of the SIM bringup
                 * 2) There is no valid App on the SIM to load, which can be the case with an
                 *    eSIM/soft SIM.
                 */
                setExternalState(State.NOT_READY);
                break;
            case APPSTATE_DETECTED:
                HandleDetectedState();
@@ -513,15 +537,16 @@ public class IccCardProxy extends Handler implements IccCard {
            }

            if (!override && newState == mExternalState) {
                loge("setExternalState: !override and newstate unchanged from " + newState);
                log("setExternalState: !override and newstate unchanged from " + newState);
                return;
            }
            mExternalState = newState;
            loge("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
            log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
            mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());

            // For locked states, we should be sending internal broadcast.
            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(
                        getIccStateIntentString(mExternalState))) {
                broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
                        getIccStateReason(mExternalState));
            } else {
@@ -934,7 +959,7 @@ public class IccCardProxy extends Handler implements IccCard {
        pw.println(" mUiccApplication=" + mUiccApplication);
        pw.println(" mIccRecords=" + mIccRecords);
        pw.println(" mCdmaSSM=" + mCdmaSSM);
        pw.println(" mRadioOn=" + mRadioOn);
        pw.println(" mRadioState=" + mRadioState);
        pw.println(" mQuietMode=" + mQuietMode);
        pw.println(" mInitialized=" + mInitialized);
        pw.println(" mExternalState=" + mExternalState);
+141 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.internal.telephony.uicc;

import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;

import android.os.Handler;
import android.os.HandlerThread;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

public class IccCardProxyTest extends TelephonyTest {
    private IccCardProxy mIccCardProxyUT;
    // private UiccCard mUiccCard;
    private IccCardProxyHandlerThread mIccCardProxyHandlerThread;
    private static final int PHONE_ID = 0;
    private static final int PHONE_COUNT = 1;

    private static final int SCARY_SLEEP_MS = 200;
    // Must match IccCardProxy.EVENT_ICC_CHANGED
    private static final int EVENT_ICC_CHANGED = 3;

    @Mock private Handler mMockedHandler;
    @Mock private IccCardStatus mIccCardStatus;
    @Mock private UiccCard mUiccCard;
    @Mock private UiccCardApplication mUiccCardApplication;

    private class IccCardProxyHandlerThread extends HandlerThread {

        private IccCardProxyHandlerThread(String name) {
            super(name);
        }

        @Override
        public void onLooperPrepared() {
            /* create a new UICC Controller associated with the simulated Commands */
            mIccCardProxyUT = new IccCardProxy(mContext, mSimulatedCommands, PHONE_ID);
            setReady(true);
        }
    }

    @Before
    public void setUp() throws Exception {
        super.setUp(this.getClass().getSimpleName());
        doReturn(PHONE_COUNT).when(mTelephonyManager).getPhoneCount();
        doReturn(PHONE_COUNT).when(mTelephonyManager).getSimCount();
        mSimulatedCommands.setIccCardStatus(mIccCardStatus);
        mIccCardProxyHandlerThread = new IccCardProxyHandlerThread(TAG);
        mIccCardProxyHandlerThread.start();
        waitUntilReady();
    }

    @After
    public void tearDown() throws Exception {
        mIccCardProxyHandlerThread.quitSafely();
        super.tearDown();
    }

    @Test
    @SmallTest
    public void testInitialCardState() {
        assertEquals(mIccCardProxyUT.getState(), State.UNKNOWN);
    }

    @Test
    @SmallTest
    public void testPowerOn() {
        mSimulatedCommands.setRadioPower(true, null);
        mSimulatedCommands.notifyRadioOn();
        when(mUiccController.getUiccCard(anyInt())).thenReturn(mUiccCard);
        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
        waitForMs(SCARY_SLEEP_MS);
        assertEquals(CommandsInterface.RadioState.RADIO_ON, mSimulatedCommands.getRadioState());
        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
        logd("IccCardProxy state = " + mIccCardProxyUT.getState());
    }

    @Test
    @SmallTest
    public void testCardLoaded() {
        testPowerOn();
        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
        waitForMs(SCARY_SLEEP_MS);
        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
    }

    @Test
    @SmallTest
    public void testAppNotLoaded() {
        testPowerOn();
        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
        when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_UNKNOWN);
        when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);

        waitForMs(SCARY_SLEEP_MS);
        assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
    }

    @Test
    @SmallTest
    public void testAppReady() {
        testPowerOn();
        when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
        mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
        when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_READY);
        when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);

        waitForMs(SCARY_SLEEP_MS);
        assertEquals(mIccCardProxyUT.getState(), State.READY);
    }
}