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

Commit 54ca7617 authored by Sarah Chin's avatar Sarah Chin
Browse files

Add satellite modem state logic for calls

For emergency calls, turn off the satellite modem and retry.
For normal calls, return an error.

Test: unit tests, CTS
Test: manual verify normal call and fake emergency call
Bug: 278578254
Change-Id: I24fc69e18e06f6ad9e64052936f45b909f1990a5
parent 60cbd331
Loading
Loading
Loading
Loading
+28 −7
Original line number Original line Diff line number Diff line
@@ -22,8 +22,10 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;


import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.satellite.SatelliteController;
import com.android.telephony.Rlog;
import com.android.telephony.Rlog;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -44,7 +46,7 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
    private RadioOnStateListener.Callback mCallback;
    private RadioOnStateListener.Callback mCallback;
    private List<RadioOnStateListener> mListeners;
    private List<RadioOnStateListener> mListeners;
    private List<RadioOnStateListener> mInProgressListeners;
    private List<RadioOnStateListener> mInProgressListeners;
    private boolean mIsRadioOnCallingEnabled;
    private boolean mIsRadioReady;


    public RadioOnHelper(Context context) {
    public RadioOnHelper(Context context) {
        mContext = context;
        mContext = context;
@@ -72,9 +74,9 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
     * class.
     * class.
     *
     *
     * This method kicks off the following sequence:
     * This method kicks off the following sequence:
     * - Power on the radio for each Phone
     * - Power on the radio for each Phone and disable the satellite modem
     * - Listen for radio events telling us the radio has come up.
     * - Listen for events telling us the radio has come up or the satellite modem is disabled.
     * - Retry if we've gone a significant amount of time without any response from the radio.
     * - Retry if we've gone a significant amount of time without any response.
     * - Finally, clean up any leftover state.
     * - Finally, clean up any leftover state.
     *
     *
     * This method is safe to call from any thread, since it simply posts a message to the
     * This method is safe to call from any thread, since it simply posts a message to the
@@ -87,7 +89,7 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
        setupListeners();
        setupListeners();
        mCallback = callback;
        mCallback = callback;
        mInProgressListeners.clear();
        mInProgressListeners.clear();
        mIsRadioOnCallingEnabled = false;
        mIsRadioReady = false;
        for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) {
        for (int i = 0; i < TelephonyManager.from(mContext).getActiveModemCount(); i++) {
            Phone phone = PhoneFactory.getPhone(i);
            Phone phone = PhoneFactory.getPhone(i);
            if (phone == null) {
            if (phone == null) {
@@ -101,6 +103,9 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
                    && phone == phoneForEmergencyCall, timeoutCallbackInterval);
                    && phone == phoneForEmergencyCall, timeoutCallbackInterval);
        }
        }
        powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber);
        powerOnRadio(forEmergencyCall, phoneForEmergencyCall, isTestEmergencyNumber);
        if (SatelliteController.getInstance().isSatelliteEnabled()) {
            powerOffSatellite(phoneForEmergencyCall);
        }
    }
    }


    /**
    /**
@@ -141,16 +146,32 @@ public class RadioOnHelper implements RadioOnStateListener.Callback {
        }
        }
    }
    }


    /**
     * Attempt to power off the satellite modem. We'll eventually get an
     * onSatelliteModemStateChanged() callback when the satellite modem is successfully disabled.
     */
    private void powerOffSatellite(Phone phoneForEmergencyCall) {
        SatelliteController satelliteController = SatelliteController.getInstance();
        satelliteController.requestSatelliteEnabled(phoneForEmergencyCall.getSubId(),
                false /* enableSatellite */, false /* enableDemoMode */,
                new IIntegerConsumer.Stub() {
                    @Override
                    public void accept(int result) {

                    }
                });
    }

    /**
    /**
     * This method is called from multiple Listeners on the Main Looper. Synchronization is not
     * This method is called from multiple Listeners on the Main Looper. Synchronization is not
     * necessary.
     * necessary.
     */
     */
    @Override
    @Override
    public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
    public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
        mIsRadioOnCallingEnabled |= isRadioReady;
        mIsRadioReady |= isRadioReady;
        mInProgressListeners.remove(listener);
        mInProgressListeners.remove(listener);
        if (mCallback != null && mInProgressListeners.isEmpty()) {
        if (mCallback != null && mInProgressListeners.isEmpty()) {
            mCallback.onComplete(null, mIsRadioOnCallingEnabled);
            mCallback.onComplete(null, mIsRadioReady);
        }
        }
    }
    }


+73 −7
Original line number Original line Diff line number Diff line
@@ -21,10 +21,14 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.telephony.ServiceState;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.ISatelliteStateCallback;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.SomeArgs;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.satellite.SatelliteController;
import com.android.telephony.Rlog;
import com.android.telephony.Rlog;


import java.util.Locale;
import java.util.Locale;
@@ -37,7 +41,8 @@ public class RadioOnStateListener {


    public interface Callback {
    public interface Callback {
        /**
        /**
         * Receives the result of the RadioOnStateListener's attempt to turn on the radio.
         * Receives the result of the RadioOnStateListener's attempt to turn on the radio
         * and turn off the satellite modem.
         */
         */
        void onComplete(RadioOnStateListener listener, boolean isRadioReady);
        void onComplete(RadioOnStateListener listener, boolean isRadioReady);


@@ -86,6 +91,8 @@ public class RadioOnStateListener {
    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_IMS_CAPABILITY_CHANGED = 6;
    public static final int MSG_TIMEOUT_ONTIMEOUT_CALLBACK = 7;
    public static final int MSG_TIMEOUT_ONTIMEOUT_CALLBACK = 7;
    @VisibleForTesting
    public static final int MSG_SATELLITE_ENABLED_CHANGED = 8;


    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        @Override
@@ -123,6 +130,10 @@ public class RadioOnStateListener {
                    break;
                    break;
                case MSG_TIMEOUT_ONTIMEOUT_CALLBACK:
                case MSG_TIMEOUT_ONTIMEOUT_CALLBACK:
                    onTimeoutCallbackTimeout();
                    onTimeoutCallbackTimeout();
                    break;
                case MSG_SATELLITE_ENABLED_CHANGED:
                    onSatelliteEnabledChanged();
                    break;
                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));
@@ -131,8 +142,17 @@ public class RadioOnStateListener {
        }
        }
    };
    };


    private final ISatelliteStateCallback mSatelliteCallback = new ISatelliteStateCallback.Stub() {
        @Override
        public void onSatelliteModemStateChanged(int state) {
            mHandler.obtainMessage(MSG_SATELLITE_ENABLED_CHANGED).sendToTarget();
        }
    };

    private Callback mCallback; // The callback to notify upon completion.
    private Callback mCallback; // The callback to notify upon completion.
    private Phone mPhone; // The phone that will attempt to place the call.
    private Phone mPhone; // The phone that will attempt to place the call.
    // SatelliteController instance to check whether satellite has been disabled.
    private SatelliteController mSatelliteController;
    private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call.
    private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call.
    // Whether this phone is selected to place emergency call. Can be true only if
    // Whether this phone is selected to place emergency call. Can be true only if
    // mForEmergencyCall is true.
    // mForEmergencyCall is true.
@@ -146,6 +166,7 @@ public class RadioOnStateListener {
     *
     *
     * This method kicks off the following sequence:
     * This method kicks off the following sequence:
     * - Listen for the service state change event telling us the radio has come up.
     * - Listen for the service state change event telling us the radio has come up.
     * - Listen for the satellite state changed event telling us the satellite service is disabled.
     * - Retry if we've gone {@link #TIME_BETWEEN_RETRIES_MILLIS} without any response from the
     * - Retry if we've gone {@link #TIME_BETWEEN_RETRIES_MILLIS} without any response from the
     *   radio.
     *   radio.
     * - Finally, clean up any leftover state.
     * - Finally, clean up any leftover state.
@@ -156,7 +177,7 @@ public class RadioOnStateListener {
     */
     */
    public void waitForRadioOn(Phone phone, Callback callback,
    public void waitForRadioOn(Phone phone, Callback callback,
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            int onTimeoutCallbackInverval) {
            int onTimeoutCallbackInterval) {
        Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId());
        Rlog.d(TAG, "waitForRadioOn: Phone " + phone.getPhoneId());


        if (mPhone != null) {
        if (mPhone != null) {
@@ -169,7 +190,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;
        args.argi1 = onTimeoutCallbackInterval;
        mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
        mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
    }
    }


@@ -182,6 +203,7 @@ public class RadioOnStateListener {
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall,
            int onTimeoutCallbackInterval) {
            int onTimeoutCallbackInterval) {
        Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId());
        Rlog.d(TAG, "startSequenceInternal: Phone " + phone.getPhoneId());
        mSatelliteController = SatelliteController.getInstance();


        // 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
        // ensures that we'll behave sanely if another startTurnOnRadioSequence() comes in while
        // ensures that we'll behave sanely if another startTurnOnRadioSequence() comes in while
@@ -198,9 +220,14 @@ public class RadioOnStateListener {
        // 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
        // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF.
        // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF.
        registerForRadioOff();
        registerForRadioOff();
        // Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see
        if (mSatelliteController.isSatelliteEnabled()) {
        // onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
            // Register for satellite modem state changed to notify when satellite is disabled.
        // the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
            registerForSatelliteEnabledChanged();
        }
        // Next step: when the SERVICE_STATE_CHANGED or SATELLITE_ENABLED_CHANGED event comes in,
        // we'll retry the call; see onServiceStateChanged() and onSatelliteEnabledChanged().
        // But also, just in case, start a timer to make sure we'll retry the call even if the
        // SERVICE_STATE_CHANGED or SATELLITE_ENABLED_CHANGED events never come in for some reason.
        startRetryTimer();
        startRetryTimer();
        registerForImsCapabilityChanged();
        registerForImsCapabilityChanged();
        startOnTimeoutCallbackTimer();
        startOnTimeoutCallbackTimer();
@@ -292,6 +319,19 @@ public class RadioOnStateListener {
        }
        }
    }
    }


    private void onSatelliteEnabledChanged() {
        if (mPhone == null) {
            return;
        }
        if (isOkToCall(mPhone.getServiceState().getState(),
                mPhone.isVoiceOverCellularImsEnabled())) {
            onComplete(true);
            cleanup();
        } else {
            Rlog.d(TAG, "onSatelliteEnabledChanged: not ready to call yet, keep waiting.");
        }
    }

    /**
    /**
     * 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.
     */
     */
@@ -348,9 +388,20 @@ public class RadioOnStateListener {
                Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up.");
                Rlog.w(TAG, "Hit MAX_NUM_RETRIES; giving up.");
                cleanup();
                cleanup();
            } else {
            } else {
                Rlog.d(TAG, "Trying (again) to turn on the radio.");
                Rlog.d(TAG, "Trying (again) to turn the radio on and satellite modem off.");
                mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall,
                mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall,
                        false);
                        false);
                if (mSatelliteController.isSatelliteEnabled()) {
                    mSatelliteController.requestSatelliteEnabled(mPhone.getSubId(),
                            false /* enableSatellite */, false /* enableDemoMode */,
                            new IIntegerConsumer.Stub() {
                                @Override
                                public void accept(int result) {
                                    mHandler.obtainMessage(MSG_SATELLITE_ENABLED_CHANGED)
                                            .sendToTarget();
                                }
                            });
                }
                startRetryTimer();
                startRetryTimer();
            }
            }
        }
        }
@@ -383,6 +434,7 @@ public class RadioOnStateListener {
        unregisterForServiceStateChanged();
        unregisterForServiceStateChanged();
        unregisterForRadioOff();
        unregisterForRadioOff();
        unregisterForRadioOn();
        unregisterForRadioOn();
        unregisterForSatelliteEnabledChanged();
        cancelRetryTimer();
        cancelRetryTimer();
        unregisterForImsCapabilityChanged();
        unregisterForImsCapabilityChanged();


@@ -442,6 +494,20 @@ 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 registerForSatelliteEnabledChanged() {
        mSatelliteController.registerForSatelliteModemStateChanged(
                mPhone.getSubId(), mSatelliteCallback);
    }

    private void unregisterForSatelliteEnabledChanged() {
        int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
        if (mPhone != null) {
            subId = mPhone.getSubId();
        }
        mSatelliteController.unregisterForSatelliteModemStateChanged(subId, mSatelliteCallback);
        mHandler.removeMessages(MSG_SATELLITE_ENABLED_CHANGED);
    }

    private void registerForImsCapabilityChanged() {
    private void registerForImsCapabilityChanged() {
        unregisterForImsCapabilityChanged();
        unregisterForImsCapabilityChanged();
        mPhone.getServiceStateTracker()
        mPhone.getServiceStateTracker()
+4 −0
Original line number Original line Diff line number Diff line
@@ -115,6 +115,7 @@ import com.android.internal.telephony.metrics.PersistAtomsStorage;
import com.android.internal.telephony.metrics.ServiceStateStats;
import com.android.internal.telephony.metrics.ServiceStateStats;
import com.android.internal.telephony.metrics.SmsStats;
import com.android.internal.telephony.metrics.SmsStats;
import com.android.internal.telephony.metrics.VoiceCallSessionStats;
import com.android.internal.telephony.metrics.VoiceCallSessionStats;
import com.android.internal.telephony.satellite.SatelliteController;
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.test.SimulatedCommands;
import com.android.internal.telephony.test.SimulatedCommands;
import com.android.internal.telephony.test.SimulatedCommandsVerifier;
import com.android.internal.telephony.test.SimulatedCommandsVerifier;
@@ -267,6 +268,7 @@ public abstract class TelephonyTest {
    protected DataServiceManager mMockedWwanDataServiceManager;
    protected DataServiceManager mMockedWwanDataServiceManager;
    protected DataServiceManager mMockedWlanDataServiceManager;
    protected DataServiceManager mMockedWlanDataServiceManager;
    protected ServiceStateStats mServiceStateStats;
    protected ServiceStateStats mServiceStateStats;
    protected SatelliteController mSatelliteController;


    // Initialized classes
    // Initialized classes
    protected ActivityManager mActivityManager;
    protected ActivityManager mActivityManager;
@@ -501,6 +503,7 @@ public abstract class TelephonyTest {
        mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class);
        mMockedWwanDataServiceManager = Mockito.mock(DataServiceManager.class);
        mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class);
        mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class);
        mServiceStateStats = Mockito.mock(ServiceStateStats.class);
        mServiceStateStats = Mockito.mock(ServiceStateStats.class);
        mSatelliteController = Mockito.mock(SatelliteController.class);


        TelephonyManager.disableServiceHandleCaching();
        TelephonyManager.disableServiceHandleCaching();
        PropertyInvalidatedCache.disableForTestMode();
        PropertyInvalidatedCache.disableForTestMode();
@@ -862,6 +865,7 @@ public abstract class TelephonyTest {
        replaceInstance(PhoneFactory.class, "sCommandsInterfaces", null,
        replaceInstance(PhoneFactory.class, "sCommandsInterfaces", null,
                new CommandsInterface[] {mSimulatedCommands});
                new CommandsInterface[] {mSimulatedCommands});
        replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
        replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
        replaceInstance(SatelliteController.class, "sInstance", null, mSatelliteController);


        setReady(false);
        setReady(false);
        // create default TestableLooper for test and add to list of monitored loopers
        // create default TestableLooper for test and add to list of monitored loopers
+73 −17
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);
        mListener = new RadioOnStateListener();
        mListener = new RadioOnStateListener();
        doReturn(mSST).when(mMockPhone).getServiceStateTracker();
        doReturn(mSST).when(mMockPhone).getServiceStateTracker();
        mMockPhone.mCi = mMockCi;
    }
    }


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


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


        verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
        verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
        verify(mSatelliteController).unregisterForSatelliteModemStateChanged(anyInt(), any());
        verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
        verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
                eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
                eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
        verify(mSatelliteController, never()).registerForSatelliteModemStateChanged(
                anyInt(), any());


        verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class),
        verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class),
                eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull());
                eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull());
    }
    }


    /**
    /**
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true,
     * Ensure that we successfully register for the satellite modem state changed messages.
     * so we are expecting
     */
    @Test
    public void testRegisterForSatelliteCallback() {
        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);

        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);

        verify(mSatelliteController).unregisterForSatelliteModemStateChanged(anyInt(), any());
        verify(mSatelliteController).registerForSatelliteModemStateChanged(anyInt(), any());
    }

    /**
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true after
     * service state changes, so we are expecting
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
     * return true.
     * return true.
     */
     */
@@ -109,9 +126,7 @@ 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(), anyBoolean()))
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(true);
                .thenReturn(true);
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);


@@ -122,6 +137,29 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        verify(mCallback).onComplete(eq(mListener), eq(true));
        verify(mCallback).onComplete(eq(mListener), eq(true));
    }
    }


    /**
     * {@link RadioOnStateListener.Callback#isOkToCall(Phone, int, boolean)} returns true after
     * satellite modem state changes, so we are expecting
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} to
     * return true.
     */
    @Test
    public void testSatelliteChangeState_OkToCallTrue() {
        ServiceState state = new ServiceState();
        state.setState(ServiceState.STATE_IN_SERVICE);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(true);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);

        mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SATELLITE_ENABLED_CHANGED)
                .sendToTarget();

        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        verify(mCallback).onComplete(eq(mListener), eq(true));
    }

    /**
    /**
     * We never receive a
     * We never receive a
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
     * {@link RadioOnStateListener.Callback#onComplete(RadioOnStateListener, boolean)} because
@@ -132,10 +170,8 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        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(), anyBoolean()))
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false);
                .thenReturn(false);
        when(mMockPhone.getServiceState()).thenReturn(state);
        when(mMockPhone.getServiceState()).thenReturn(state);
        mMockPhone.mCi = mMockCi;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
        waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);


@@ -158,18 +194,18 @@ 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(), anyBoolean()))
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false);
                .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;
        mListener.waitForRadioOn(mMockPhone, mCallback, false, false, 0);
        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));
        verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(false), eq(false), eq(false));
        verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(false), eq(false), eq(false));
        verify(mSatelliteController, never()).requestSatelliteEnabled(
                anyInt(), eq(false), eq(false), any());
    }
    }


    @Test
    @Test
@@ -178,18 +214,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(), anyBoolean()))
        when(mCallback.isOkToCall(eq(mMockPhone), anyInt(), anyBoolean())).thenReturn(false);
                .thenReturn(false);
        mListener.setTimeBetweenRetriesMillis(0/* ms */);
        mListener.setMaxNumRetries(2);

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

        verify(mCallback).onComplete(eq(mListener), eq(false));
        verify(mMockPhone, times(2)).setRadioPower(eq(true), eq(true), eq(true), eq(false));
        verify(mSatelliteController, never()).requestSatelliteEnabled(
                anyInt(), eq(false), eq(false), any());
    }

    @Test
    public void testTimeout_RetryFailure_WithSatellite() {
        doReturn(true).when(mSatelliteController).isSatelliteEnabled();
        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);
        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;
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 0);
        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));
        verify(mSatelliteController, times(2)).requestSatelliteEnabled(
                anyInt(), eq(false), eq(false), any());
    }
    }


    @Test
    @Test
@@ -206,7 +263,6 @@ public class RadioOnStateListenerTest extends TelephonyTest {
        mListener.setMaxNumRetries(1);
        mListener.setMaxNumRetries(1);


        // 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;
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 100);
        mListener.waitForRadioOn(mMockPhone, mCallback, true, true, 100);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS);
        waitForDelayedHandlerAction(mListener.getHandler(), TIMEOUT_MS /* delay */, TIMEOUT_MS);