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

Commit e1785ca9 authored by Hunsuk Choi's avatar Hunsuk Choi
Browse files

Delay dialing normal routing emergency number in airplane mode

Bug: 176505665
Test: RadioOnStateListenerTest
Change-Id: Ib323348450405a7dec4a2733530ff0eee9fd2317
parent 8ddb0be4
Loading
Loading
Loading
Loading
+7 −2
Original line number Original line Diff line number Diff line
@@ -1026,14 +1026,19 @@ public class EmergencyStateTracker {
                }
                }


                @Override
                @Override
                public boolean isOkToCall(Phone phone, int serviceState) {
                public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
                    // We currently only look to make sure that the radio is on before dialing. We
                    // We currently only look to make sure that the radio is on before dialing. We
                    // should be able to make emergency calls at any time after the radio has been
                    // should be able to make emergency calls at any time after the radio has been
                    // powered on and isn't in the UNAVAILABLE state, even if it is reporting the
                    // powered on and isn't in the UNAVAILABLE state, even if it is reporting the
                    // OUT_OF_SERVICE state.
                    // OUT_OF_SERVICE state.
                    return phone.getServiceStateTracker().isRadioOn();
                    return phone.getServiceStateTracker().isRadioOn();
                }
                }
            }, !isTestEmergencyNumber, phone, isTestEmergencyNumber);

                @Override
                public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
                    return true;
                }
            }, !isTestEmergencyNumber, phone, isTestEmergencyNumber, 0);
        } else {
        } else {
            switchDdsAndSetEmergencyMode(phone, emergencyType);
            switchDdsAndSetEmergencyMode(phone, emergencyType);
        }
        }
+14 −4
Original line number Original line Diff line number Diff line
@@ -82,7 +82,8 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
     * and runs on the main looper.)
     * and runs on the main looper.)
     */
     */
    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback,
    public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback,
            boolean forEmergencyCall, Phone phoneForEmergencyCall, boolean isTestEmergencyNumber) {
            boolean forEmergencyCall, Phone phoneForEmergencyCall, boolean isTestEmergencyNumber,
            int emergencyTimeoutIntervalMillis) {
        setupListeners();
        setupListeners();
        mCallback = callback;
        mCallback = callback;
        mInProgressListeners.clear();
        mInProgressListeners.clear();
@@ -93,9 +94,11 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
                continue;
                continue;
            }
            }


            int timeoutCallbackInterval = (forEmergencyCall && phone == phoneForEmergencyCall)
                    ? emergencyTimeoutIntervalMillis : 0;
            mInProgressListeners.add(mListeners.get(i));
            mInProgressListeners.add(mListeners.get(i));
            mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall, forEmergencyCall
            mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall, forEmergencyCall
                    && phone == phoneForEmergencyCall);
                    && phone == phoneForEmergencyCall, timeoutCallbackInterval);
        }
        }
        powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber);
        powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber);
    }
    }
@@ -152,7 +155,14 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
    }
    }


    @Override
    @Override
    public boolean isOkToCall(Phone phone, int serviceState) {
    public boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable) {
        return (mCallback == null) ? false : mCallback.isOkToCall(phone, serviceState);
        return (mCallback == null)
                ? false : mCallback.isOkToCall(phone, serviceState, imsVoiceCapable);
    }

    @Override
    public boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable) {
        return (mCallback == null)
                ? false : mCallback.onTimeout(phone, serviceState, imsVoiceCapable);
    }
    }
}
}
+126 −11
Original line number Original line Diff line number Diff line
@@ -42,10 +42,30 @@ public class RadioOnStateListener {
        void onComplete(RadioOnStateListener listener, boolean isRadioReady);
        void onComplete(RadioOnStateListener listener, boolean isRadioReady);


        /**
        /**
         * Given the Phone and the new service state of that phone, return whether or not this phone
         * Returns whether or not this phone is ok to call.
         * is ok to call. If it is, onComplete will be called shortly after.
         * If it is, onComplete will be called shortly after.
         *
         * @param phone The Phone associated.
         * @param serviceState The service state of that phone.
         * @param imsVoiceCapable The IMS voice capability of that phone.
         * @return {@code true} if this phone is ok to call. Otherwise, {@code false}.
         */
        boolean isOkToCall(Phone phone, int serviceState, boolean imsVoiceCapable);

        /**
         * Returns whether or not this phone is ok to call.
         * This callback will be called when timeout happens.
         * If this returns {@code true}, onComplete will be called shortly after.
         * Otherwise, a new timer will be started again to keep waiting for next timeout.
         * The timeout interval will be passed to {@link #waitForRadioOn()} when registering
         * this callback.
         *
         * @param phone The Phone associated.
         * @param serviceState The service state of that phone.
         * @param imsVoiceCapable The IMS voice capability of that phone.
         * @return {@code true} if this phone is ok to call. Otherwise, {@code false}.
         */
         */
        boolean isOkToCall(Phone phone, int serviceState);
        boolean onTimeout(Phone phone, int serviceState, boolean imsVoiceCapable);
    }
    }


    private static final String TAG = "RadioOnStateListener";
    private static final String TAG = "RadioOnStateListener";
@@ -64,6 +84,8 @@ public class RadioOnStateListener {
    @VisibleForTesting
    @VisibleForTesting
    public static final int MSG_RADIO_ON = 4;
    public static final int MSG_RADIO_ON = 4;
    public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5;
    public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5;
    public static final int MSG_IMS_CAPABILITY_CHANGED = 6;
    public static final int MSG_TIMEOUT_ONTIMEOUT_CALLBACK = 7;


    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        @Override
@@ -77,8 +99,9 @@ public class RadioOnStateListener {
                                (RadioOnStateListener.Callback) args.arg2;
                                (RadioOnStateListener.Callback) args.arg2;
                        boolean forEmergencyCall = (boolean) args.arg3;
                        boolean forEmergencyCall = (boolean) args.arg3;
                        boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4;
                        boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4;
                        int onTimeoutCallbackInterval = args.argi1;
                        startSequenceInternal(phone, callback, forEmergencyCall,
                        startSequenceInternal(phone, callback, forEmergencyCall,
                                isSelectedPhoneForEmergencyCall);
                                isSelectedPhoneForEmergencyCall, onTimeoutCallbackInterval);
                    } finally {
                    } finally {
                        args.recycle();
                        args.recycle();
                    }
                    }
@@ -95,6 +118,11 @@ public class RadioOnStateListener {
                case MSG_RETRY_TIMEOUT:
                case MSG_RETRY_TIMEOUT:
                    onRetryTimeout();
                    onRetryTimeout();
                    break;
                    break;
                case MSG_IMS_CAPABILITY_CHANGED:
                    onImsCapabilityChanged();
                    break;
                case MSG_TIMEOUT_ONTIMEOUT_CALLBACK:
                    onTimeoutCallbackTimeout();
                default:
                default:
                    Rlog.w(TAG, String.format(Locale.getDefault(),
                    Rlog.w(TAG, String.format(Locale.getDefault(),
                        "handleMessage: unexpected message: %d.", msg.what));
                        "handleMessage: unexpected message: %d.", msg.what));
@@ -110,6 +138,7 @@ public class RadioOnStateListener {
    // mForEmergencyCall is true.
    // mForEmergencyCall is true.
    private boolean mSelectedPhoneForEmergencyCall;
    private boolean mSelectedPhoneForEmergencyCall;
    private int mNumRetriesSoFar;
    private int mNumRetriesSoFar;
    private int mOnTimeoutCallbackInterval; // the interval between onTimeout callbacks


    /**
    /**
     * Starts the "wait for radio" sequence. This is the (single) external API of the
     * Starts the "wait for radio" sequence. This is the (single) external API of the
@@ -126,7 +155,8 @@ public class RadioOnStateListener {
     * serialized, and runs only on the handler thread.)
     * serialized, and runs only on the handler thread.)
     */
     */
    public void waitForRadioOn(Phone phone, Callback callback,
    public void waitForRadioOn(Phone phone, Callback callback,
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            int onTimeoutCallbackInverval) {
        Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId());
        Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId());


        if (mPhone != null) {
        if (mPhone != null) {
@@ -139,6 +169,7 @@ public class RadioOnStateListener {
        args.arg2 = callback;
        args.arg2 = callback;
        args.arg3 = forEmergencyCall;
        args.arg3 = forEmergencyCall;
        args.arg4 = isSelectedPhoneForEmergencyCall;
        args.arg4 = isSelectedPhoneForEmergencyCall;
        args.argi1 = onTimeoutCallbackInverval;
        mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
        mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
    }
    }


@@ -148,7 +179,8 @@ public class RadioOnStateListener {
     * @see #waitForRadioOn
     * @see #waitForRadioOn
     */
     */
    private void startSequenceInternal(Phone phone, Callback callback,
    private void startSequenceInternal(Phone phone, Callback callback,
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            int onTimeoutCallbackInterval) {
        Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId());
        Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId());


        // First of all, clean up any state left over from a prior RadioOn call sequence. This
        // First of all, clean up any state left over from a prior RadioOn call sequence. This
@@ -160,6 +192,7 @@ public class RadioOnStateListener {
        mCallback = callback;
        mCallback = callback;
        mForEmergencyCall = forEmergencyCall;
        mForEmergencyCall = forEmergencyCall;
        mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall;
        mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall;
        mOnTimeoutCallbackInterval = onTimeoutCallbackInterval;


        registerForServiceStateChanged();
        registerForServiceStateChanged();
        // Register for RADIO_OFF to handle cases where emergency call is dialed before
        // Register for RADIO_OFF to handle cases where emergency call is dialed before
@@ -169,6 +202,49 @@ public class RadioOnStateListener {
        // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
        // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
        // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
        // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
        startRetryTimer();
        startRetryTimer();
        registerForImsCapabilityChanged();
        startOnTimeoutCallbackTimer();
    }

    private void onImsCapabilityChanged() {
        if (mPhone == null) {
            return;
        }

        boolean imsVoiceCapable = mPhone.isVoiceOverCellularImsEnabled();

        Rlog.d(TAG, String.format("onImsCapabilityChanged, capable = %s, Phone = %s",
                imsVoiceCapable, mPhone.getPhoneId()));

        if (isOkToCall(mPhone.getServiceState().getState(), imsVoiceCapable)) {
            Rlog.d(TAG, "onImsCapabilityChanged: ok to call!");

            onComplete(true);
            cleanup();
        } else {
            // The IMS capability changed, but we're still not ready to call yet.
            Rlog.d(TAG, "onImsCapabilityChanged: not ready to call yet, keep waiting.");
        }
    }

    private void onTimeoutCallbackTimeout() {
        if (mPhone == null) {
            return;
        }

        if (onTimeout(mPhone.getServiceState().getState(),
                  mPhone.isVoiceOverCellularImsEnabled())) {
            Rlog.d(TAG, "onTimeout: ok to call!");

            onComplete(true);
            cleanup();
        } else if (mNumRetriesSoFar > MAX_NUM_RETRIES) {
            Rlog.w(TAG, "onTimeout: Hit MAX_NUM_RETRIES; giving up.");
            cleanup();
        } else {
            Rlog.d(TAG, "onTimeout: not ready to call yet, keep waiting.");
            startOnTimeoutCallbackTimer();
        }
    }
    }


    /**
    /**
@@ -190,7 +266,7 @@ public class RadioOnStateListener {
        // - STATE_EMERGENCY_ONLY    // Only emergency numbers are allowed; currently not used
        // - STATE_EMERGENCY_ONLY    // Only emergency numbers are allowed; currently not used
        // - STATE_POWER_OFF         // Radio is explicitly powered off (airplane mode)
        // - STATE_POWER_OFF         // Radio is explicitly powered off (airplane mode)


        if (isOkToCall(state.getState())) {
        if (isOkToCall(state.getState(), mPhone.isVoiceOverCellularImsEnabled())) {
            // Woo hoo! It's OK to actually place the call.
            // Woo hoo! It's OK to actually place the call.
            Rlog.d(TAG, "onServiceStateChanged: ok to call!");
            Rlog.d(TAG, "onServiceStateChanged: ok to call!");


@@ -208,7 +284,7 @@ public class RadioOnStateListener {
        }
        }
        ServiceState state = mPhone.getServiceState();
        ServiceState state = mPhone.getServiceState();
        Rlog.d(TAG, String.format("onRadioOn, state = %s, Phone = %s", state, mPhone.getPhoneId()));
        Rlog.d(TAG, String.format("onRadioOn, state = %s, Phone = %s", state, mPhone.getPhoneId()));
        if (isOkToCall(state.getState())) {
        if (isOkToCall(state.getState(), mPhone.isVoiceOverCellularImsEnabled())) {
            onComplete(true);
            onComplete(true);
            cleanup();
            cleanup();
        } else {
        } else {
@@ -219,8 +295,17 @@ public class RadioOnStateListener {
    /**
    /**
     * Callback to see if it is okay to call yet, given the current conditions.
     * Callback to see if it is okay to call yet, given the current conditions.
     */
     */
    private boolean isOkToCall(int serviceState) {
    private boolean isOkToCall(int serviceState, boolean imsVoiceCapable) {
        return (mCallback == null) ? false : mCallback.isOkToCall(mPhone, serviceState);
        return (mCallback == null)
                ? false : mCallback.isOkToCall(mPhone, serviceState, imsVoiceCapable);
    }

    /**
     * Callback to see if it is okay to call yet, given the current conditions.
     */
    private boolean onTimeout(int serviceState, boolean imsVoiceCapable) {
        return (mCallback == null)
                ? false : mCallback.onTimeout(mPhone, serviceState, imsVoiceCapable);
    }
    }


    /**
    /**
@@ -242,7 +327,7 @@ public class RadioOnStateListener {
        //   call.
        //   call.
        // - If the radio is still powered off, try powering it on again.
        // - If the radio is still powered off, try powering it on again.


        if (isOkToCall(serviceState)) {
        if (isOkToCall(serviceState, mPhone.isVoiceOverCellularImsEnabled())) {
            Rlog.d(TAG, "onRetryTimeout: Radio is on. Cleaning up.");
            Rlog.d(TAG, "onRetryTimeout: Radio is on. Cleaning up.");


            // Woo hoo -- we successfully got out of airplane mode.
            // Woo hoo -- we successfully got out of airplane mode.
@@ -256,6 +341,10 @@ public class RadioOnStateListener {
            Rlog.d(TAG, "mNumRetriesSoFar is now " + mNumRetriesSoFar);
            Rlog.d(TAG, "mNumRetriesSoFar is now " + mNumRetriesSoFar);


            if (mNumRetriesSoFar > MAX_NUM_RETRIES) {
            if (mNumRetriesSoFar > MAX_NUM_RETRIES) {
                if (mHandler.hasMessages(MSG_TIMEOUT_ONTIMEOUT_CALLBACK)) {
                    Rlog.w(TAG, "Hit MAX_NUM_RETRIES; waiting onTimeout callback");
                    return;
                }
                Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up.");
                Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up.");
                cleanup();
                cleanup();
            } else {
            } else {
@@ -295,10 +384,12 @@ public class RadioOnStateListener {
        unregisterForRadioOff();
        unregisterForRadioOff();
        unregisterForRadioOn();
        unregisterForRadioOn();
        cancelRetryTimer();
        cancelRetryTimer();
        unregisterForImsCapabilityChanged();


        // Used for unregisterForServiceStateChanged() so we null it out here instead.
        // Used for unregisterForServiceStateChanged() so we null it out here instead.
        mPhone = null;
        mPhone = null;
        mNumRetriesSoFar = 0;
        mNumRetriesSoFar = 0;
        mOnTimeoutCallbackInterval = 0;
    }
    }


    private void startRetryTimer() {
    private void startRetryTimer() {
@@ -351,6 +442,30 @@ public class RadioOnStateListener {
        mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too
        mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too
    }
    }


    private void registerForImsCapabilityChanged() {
        unregisterForImsCapabilityChanged();
        mPhone.getServiceStateTracker()
                .registerForImsCapabilityChanged(mHandler, MSG_IMS_CAPABILITY_CHANGED, null);
    }

    private void unregisterForImsCapabilityChanged() {
        if (mPhone != null) {
            mPhone.getServiceStateTracker()
                    .unregisterForImsCapabilityChanged(mHandler);
        }
        mHandler.removeMessages(MSG_IMS_CAPABILITY_CHANGED);
    }

    private void startOnTimeoutCallbackTimer() {
        Rlog.d(TAG, "startOnTimeoutCallbackTimer: mOnTimeoutCallbackInterval="
                + mOnTimeoutCallbackInterval);
        mHandler.removeMessages(MSG_TIMEOUT_ONTIMEOUT_CALLBACK);
        if (mOnTimeoutCallbackInterval > 0) {
            mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT_ONTIMEOUT_CALLBACK,
                    mOnTimeoutCallbackInterval);
        }
    }

    private void onComplete(boolean isRadioReady) {
    private void onComplete(boolean isRadioReady) {
        if (mCallback != null) {
        if (mCallback != null) {
            Callback tempCallback = mCallback;
            Callback tempCallback = mCallback;
+8 −6
Original line number Original line Diff line number Diff line
@@ -157,11 +157,13 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
        ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
        ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                .forClass(RadioOnStateListener.Callback.class);
                .forClass(RadioOnStateListener.Callback.class);
        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
                eq(false));
                eq(false), eq(0));
        // isOkToCall() should return true once radio is on
        // isOkToCall() should return true once radio is on
        assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
        assertFalse(callback.getValue()
                .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
        when(mSST.isRadioOn()).thenReturn(true);
        when(mSST.isRadioOn()).thenReturn(true);
        assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
        assertTrue(callback.getValue()
                .isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE, false));
        // Once radio on is complete, trigger delay dial
        // Once radio on is complete, trigger delay dial
        callback.getValue().onComplete(null, true);
        callback.getValue().onComplete(null, true);
        ArgumentCaptor<Consumer<Boolean>> completeConsumer = ArgumentCaptor
        ArgumentCaptor<Consumer<Boolean>> completeConsumer = ArgumentCaptor
@@ -194,7 +196,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest {
        ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
        ArgumentCaptor<RadioOnStateListener.Callback> callback = ArgumentCaptor
                .forClass(RadioOnStateListener.Callback.class);
                .forClass(RadioOnStateListener.Callback.class);
        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
        verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true), eq(testPhone),
                eq(false));
                eq(false), eq(0));
        // Verify future completes with DisconnectCause.POWER_OFF if radio not ready
        // Verify future completes with DisconnectCause.POWER_OFF if radio not ready
        CompletableFuture<Void> unused = future.thenAccept((result) -> {
        CompletableFuture<Void> unused = future.thenAccept((result) -> {
            assertEquals((Integer) result, (Integer) DisconnectCause.POWER_OFF);
            assertEquals((Integer) result, (Integer) DisconnectCause.POWER_OFF);
@@ -222,7 +224,7 @@ public class EmergencyStateTrackerTest extends TelephonyTest {


        // Radio already on so shouldn't trigger this
        // Radio already on so shouldn't trigger this
        verify(mRadioOnHelper, never()).triggerRadioOnAndListen(any(), anyBoolean(), any(),
        verify(mRadioOnHelper, never()).triggerRadioOnAndListen(any(), anyBoolean(), any(),
                anyBoolean());
                anyBoolean(), eq(0));
        // Carrier supports control-plane fallback, so no DDS switch
        // Carrier supports control-plane fallback, so no DDS switch
        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
        verify(mPhoneSwitcher, never()).overrideDefaultDataForEmergency(anyInt(), anyInt(), any());
    }
    }
+44 −15
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;
@@ -64,6 +65,7 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        super.setUp(getClass().getSimpleName());
        super.setUp(getClass().getSimpleName());
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
        mListener = new RadioOnStateListener();
        mListener = new RadioOnStateListener();
        doReturn(mSST).when(mMockPhone).getServiceStateTracker();
    }
    }


    @After
    @After
@@ -83,7 +85,7 @@ public class RadioOnStateListenerTest extends TelephonyTest {
    @Test
    @Test
    public void testRegisterForCallback() {
    public void testRegisterForCallback() {
        mMockPhone.mCi = mMockCi;
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);


        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);


@@ -96,8 +98,9 @@ public class RadioOnStateListenerTest extends TelephonyTest {
    }
    }


    /**
    /**
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns true, so we are
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true,
     * expecting {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
     * so we are expecting
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
     * return true.
     * return true.
     */
     */
    @Test
    @Test
@@ -106,9 +109,10 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        state.setState(ServiceState.STATE_IN_SERVICE);
        state.setState(ServiceState.STATE_IN_SERVICE);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(true);
        mMockPhone.mCi = mMockCi;
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);


        mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
        mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -121,17 +125,18 @@ public class RadioOnStateListenerTest extends TelephonyTest {
    /**
    /**
     * We never receive a
     * We never receive a
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returns false.
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns false.
     */
     */
    @Test
    @Test
    public void testPhoneChangeState_NoOkToCall_Timeout() {
    public void testPhoneChangeState_NoOkToCall_Timeout() {
        ServiceState state = new ServiceState();
        ServiceState state = new ServiceState();
        state.setState(ServiceState.STATE_OUT_OF_SERVICE);
        state.setState(ServiceState.STATE_OUT_OF_SERVICE);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(false);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getServiceState()).thenReturn(state);
        mMockPhone.mCi = mMockCi;
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);


        mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
        mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -142,8 +147,8 @@ public class RadioOnStateListenerTest extends TelephonyTest {
    }
    }


    /**
    /**
     * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int)} returning false and
     * Tests {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returning
     * hitting the max number of retries. This should result in
     * false and hitting the max number of retries. This should result in
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} returning
     * false.
     * false.
     */
     */
@@ -153,13 +158,14 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        state.setState(ServiceState.STATE_POWER_OFF);
        state.setState(ServiceState.STATE_POWER_OFF);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(false);
        mListener.setTimeBetweenRetriesMillis(0/* ms */);
        mListener.setTimeBetweenRetriesMillis(0/* ms */);
        mListener.setMaxNumRetries(2);
        mListener.setMaxNumRetries(2);


        // Wait for the timer to expire and check state manually in onRetryTimeout
        // Wait for the timer to expire and check state manually in onRetryTimeout
        mMockPhone.mCi = mMockCi;
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS);


        verify(mCallback).onComplete(eq(mListener), eq(false));
        verify(mCallback).onComplete(eq(mListener), eq(false));
@@ -172,16 +178,39 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        state.setState(ServiceState.STATE_POWER_OFF);
        state.setState(ServiceState.STATE_POWER_OFF);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(false);
        mListener.setTimeBetweenRetriesMillis(0/* ms */);
        mListener.setTimeBetweenRetriesMillis(0/* ms */);
        mListener.setMaxNumRetries(2);
        mListener.setMaxNumRetries(2);


        // Wait for the timer to expire and check state manually in onRetryTimeout
        // Wait for the timer to expire and check state manually in onRetryTimeout
        mMockPhone.mCi = mMockCi;
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true);
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 0);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS );
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS );


        verify(mCallback).onComplete(eq(mListener), eq(false));
        verify(mCallback).onComplete(eq(mListener), eq(false));
        verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false));
        verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false));
    }
    }

    @Test
    public void testTimeout_OnTimeoutForEmergency() {
        ServiceState state = new ServiceState();
        state.setState(ServiceState.STATE_POWER_OFF);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(false);
        when(mCallback.onTimeout(eq(mMockPhone), anyInt(), anyBoolean()))
                .thenReturn(true);
        mListener.setTimeBetweenRetriesMillis(0 /* ms */);
        mListener.setMaxNumRetries(1);

        // Wait for the timer to expire and check state manually in onRetryTimeout
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 100);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS);

        verify(mCallback).onTimeout(eq(mMockPhone), anyInt(), anyBoolean());
        verify(mCallback).onComplete(eq(mListener), eq(true));
    }
}
}