blob: a02666a55922e0b65fe38f8813835e4824bfcb0f [file] [log] [blame]
/*
* Copyright (C) 2009 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 android.telephony.cts;
import static androidx.test.InstrumentationRegistry.getContext;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.BarringInfo;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.cts.util.TelephonyUtils;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
import android.util.Log;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.ShellIdentityUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class PhoneStateListenerTest {
public static final long WAIT_TIME = 1000;
private static final String TEST_EMERGENCY_NUMBER = "998877665544332211";
private boolean mOnActiveDataSubscriptionIdChanged;
private boolean mOnCallForwardingIndicatorChangedCalled;
private boolean mOnCallStateChangedCalled;
private boolean mOnCellLocationChangedCalled;
private boolean mOnUserMobileDataStateChanged;
private boolean mOnDataActivityCalled;
private boolean mOnDataConnectionStateChangedCalled;
private boolean mOnDataConnectionStateChangedWithNetworkTypeCalled;
private boolean mOnMessageWaitingIndicatorChangedCalled;
private boolean mOnCellInfoChangedCalled;
private boolean mOnServiceStateChangedCalled;
private boolean mOnSignalStrengthChangedCalled;
private boolean mOnPreciseCallStateChangedCalled;
private boolean mOnCallDisconnectCauseChangedCalled;
private boolean mOnImsCallDisconnectCauseChangedCalled;
private ImsReasonInfo mImsReasonInfo;
private boolean mOnPreciseDataConnectionStateChanged;
private boolean mOnRadioPowerStateChangedCalled;
private boolean mVoiceActivationStateChangedCalled;
private boolean mSrvccStateChangedCalled;
private boolean mOnBarringInfoChangedCalled;
private boolean mOnRegistrationFailedCalled;
private boolean mOnTelephonyDisplayInfoChanged;
@RadioPowerState
private int mRadioPowerState;
@SimActivationState
private int mVoiceActivationState;
private BarringInfo mBarringInfo;
private PreciseDataConnectionState mPreciseDataConnectionState;
private PreciseCallState mPreciseCallState;
private SignalStrength mSignalStrength;
private TelephonyManager mTelephonyManager;
private PhoneStateListener mListener;
private final Object mLock = new Object();
private static final String TAG = "android.telephony.cts.PhoneStateListenerTest";
private static ConnectivityManager mCm;
private HandlerThread mHandlerThread;
private Handler mHandler;
private PackageManager mPackageManager;
private static final List<Integer> DATA_CONNECTION_STATE = Arrays.asList(
TelephonyManager.DATA_CONNECTED,
TelephonyManager.DATA_DISCONNECTED,
TelephonyManager.DATA_CONNECTING,
TelephonyManager.DATA_UNKNOWN,
TelephonyManager.DATA_SUSPENDED
);
private static final List<Integer> PRECISE_CALL_STATE = Arrays.asList(
PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
PreciseCallState.PRECISE_CALL_STATE_ALERTING,
PreciseCallState.PRECISE_CALL_STATE_DIALING,
PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING,
PreciseCallState.PRECISE_CALL_STATE_HOLDING,
PreciseCallState.PRECISE_CALL_STATE_IDLE,
PreciseCallState.PRECISE_CALL_STATE_INCOMING,
PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
PreciseCallState.PRECISE_CALL_STATE_WAITING
);
private Executor mSimpleExecutor = new Executor() {
@Override
public void execute(Runnable r) {
r.run();
}
};
@Before
public void setUp() throws Exception {
mPackageManager = getContext().getPackageManager();
assumeTrue("Skipping test that requires FEATURE_TELEPHONY",
mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY));
mTelephonyManager =
(TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
mHandlerThread = new HandlerThread("PhoneStateListenerTest");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
@After
public void tearDown() throws Exception {
if (mListener != null) {
// unregister the listener
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
}
if (mHandlerThread != null) {
mHandlerThread.quitSafely();
}
}
@Test
public void testPhoneStateListener() {
Looper.prepare();
new PhoneStateListener();
}
@Test
public void testOnServiceStateChanged() throws Throwable {
assertFalse(mOnServiceStateChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
synchronized (mLock) {
mOnServiceStateChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
});
synchronized (mLock) {
if (!mOnServiceStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnServiceStateChangedCalled);
}
@Test
public void testOnUnRegisterFollowedByRegister() throws Throwable {
assertFalse(mOnServiceStateChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
synchronized (mLock) {
mOnServiceStateChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
});
synchronized (mLock) {
if (!mOnServiceStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnServiceStateChangedCalled);
// reset and un-register
mOnServiceStateChangedCalled = false;
if (mListener != null) {
// un-register the listener
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
}
synchronized (mLock) {
if (!mOnServiceStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertFalse(mOnServiceStateChangedCalled);
// re-register the listener
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SERVICE_STATE);
synchronized (mLock) {
if (!mOnServiceStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnServiceStateChangedCalled);
}
@Test
public void testOnSignalStrengthChanged() throws Throwable {
assertFalse(mOnSignalStrengthChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onSignalStrengthChanged(int asu) {
synchronized (mLock) {
mOnSignalStrengthChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTH);
});
synchronized (mLock) {
if (!mOnSignalStrengthChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnSignalStrengthChangedCalled);
}
/**
* Due to the corresponding API is hidden in R and will be public in S, this test
* is commented and will be un-commented in Android S.
*
@Test
public void testOnAlwaysReportedSignalStrengthChanged() throws Throwable {
assertTrue(mSignalStrength == null);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
synchronized (mLock) {
mSignalStrength = signalStrength;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH));
});
synchronized (mLock) {
if (mSignalStrength == null) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mSignalStrength != null);
// Call SignalStrength methods to make sure they do not throw any exceptions
mSignalStrength.getCdmaDbm();
mSignalStrength.getCdmaEcio();
mSignalStrength.getEvdoDbm();
mSignalStrength.getEvdoEcio();
mSignalStrength.getEvdoSnr();
mSignalStrength.getGsmBitErrorRate();
mSignalStrength.getGsmSignalStrength();
mSignalStrength.isGsm();
mSignalStrength.getLevel();
}
*/
@Test
public void testOnSignalStrengthsChanged() throws Throwable {
assertTrue(mSignalStrength == null);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
synchronized (mLock) {
mSignalStrength = signalStrength;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
});
synchronized (mLock) {
if (mSignalStrength == null) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mSignalStrength != null);
// Call SignalStrength methods to make sure they do not throw any exceptions
mSignalStrength.getCdmaDbm();
mSignalStrength.getCdmaEcio();
mSignalStrength.getEvdoDbm();
mSignalStrength.getEvdoEcio();
mSignalStrength.getEvdoSnr();
mSignalStrength.getGsmBitErrorRate();
mSignalStrength.getGsmSignalStrength();
mSignalStrength.isGsm();
mSignalStrength.getLevel();
}
/**
* Due to the corresponding API is hidden in R and will be public in S, this test
* is commented and will be un-commented in Android S.
*
* Validate that SecurityException should be thrown when listen
* with LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH without LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH
* permission.
*
@Test
public void testOnAlwaysReportedSignalStrengthChangedWithoutPermission() throws Throwable {
assertTrue(mSignalStrength == null);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
synchronized (mLock) {
mSignalStrength = signalStrength;
mLock.notify();
}
}
};
try {
mTelephonyManager.listen(mListener,
PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH);
} catch (SecurityException se) {
synchronized (mLock) {
mSecurityExceptionThrown = true;
mLock.notify();
}
}
});
synchronized (mLock) {
if (!mSecurityExceptionThrown) {
mLock.wait(WAIT_TIME);
}
}
assertThat(mSecurityExceptionThrown).isTrue();
assertTrue(mSignalStrength == null);
}
*/
@Test
public void testOnMessageWaitingIndicatorChanged() throws Throwable {
assertFalse(mOnMessageWaitingIndicatorChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onMessageWaitingIndicatorChanged(boolean mwi) {
synchronized (mLock) {
mOnMessageWaitingIndicatorChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(
mListener, PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR);
});
synchronized (mLock) {
if (!mOnMessageWaitingIndicatorChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnMessageWaitingIndicatorChangedCalled);
}
@Test
public void testOnPreciseCallStateChanged() throws Throwable {
assertThat(mOnPreciseCallStateChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onPreciseCallStateChanged(PreciseCallState preciseCallState) {
synchronized (mLock) {
mOnPreciseCallStateChangedCalled = true;
mPreciseCallState = preciseCallState;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_PRECISE_CALL_STATE));
});
synchronized (mLock) {
if (!mOnPreciseCallStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
Log.d(TAG, "testOnPreciseCallStateChanged: " + mOnPreciseCallStateChangedCalled);
assertThat(mOnPreciseCallStateChangedCalled).isTrue();
assertThat(mPreciseCallState.getForegroundCallState()).isIn(PRECISE_CALL_STATE);
assertThat(mPreciseCallState.getBackgroundCallState()).isIn(PRECISE_CALL_STATE);
assertThat(mPreciseCallState.getRingingCallState()).isIn(PRECISE_CALL_STATE);
}
@Test
public void testOnCallDisconnectCauseChanged() throws Throwable {
assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onCallDisconnectCauseChanged(int disconnectCause,
int preciseDisconnectCause) {
synchronized (mLock) {
mOnCallDisconnectCauseChangedCalled = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_CALL_DISCONNECT_CAUSES));
});
synchronized (mLock) {
if (!mOnCallDisconnectCauseChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertThat(mOnCallDisconnectCauseChangedCalled).isTrue();
}
@Test
public void testOnImsCallDisconnectCauseChanged() throws Throwable {
assertThat(mOnImsCallDisconnectCauseChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onImsCallDisconnectCauseChanged(ImsReasonInfo imsReason) {
synchronized (mLock) {
mOnImsCallDisconnectCauseChangedCalled = true;
mImsReasonInfo = imsReason;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_IMS_CALL_DISCONNECT_CAUSES));
});
synchronized (mLock) {
if (!mOnImsCallDisconnectCauseChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertThat(mOnImsCallDisconnectCauseChangedCalled).isTrue();
assertNotNull(mImsReasonInfo);
}
@Test
public void testOnPhoneStateListenerExecutorWithSrvccChanged() throws Throwable {
assertThat(mSrvccStateChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener(mSimpleExecutor) {
@Override
public void onSrvccStateChanged(int state) {
synchronized (mLock) {
mSrvccStateChangedCalled = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_SRVCC_STATE_CHANGED));
});
synchronized (mLock) {
if (!mSrvccStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
Log.d(TAG, "testOnPhoneStateListenerExecutorWithSrvccChanged");
assertThat(mSrvccStateChangedCalled).isTrue();
}
@Test
public void testOnRadioPowerStateChanged() throws Throwable {
assertThat(mOnRadioPowerStateChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onRadioPowerStateChanged(int state) {
synchronized (mLock) {
mRadioPowerState = state;
mOnRadioPowerStateChangedCalled = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_RADIO_POWER_STATE_CHANGED));
});
synchronized (mLock) {
if (!mOnRadioPowerStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
Log.d(TAG, "testOnRadioPowerStateChanged: " + mRadioPowerState);
assertThat(mTelephonyManager.getRadioPowerState()).isEqualTo(mRadioPowerState);
}
@Test
public void testOnVoiceActivationStateChanged() throws Throwable {
assertThat(mVoiceActivationStateChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onVoiceActivationStateChanged(int state) {
synchronized (mLock) {
mVoiceActivationState = state;
mVoiceActivationStateChangedCalled = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE));
});
synchronized (mLock) {
if (!mVoiceActivationStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
Log.d(TAG, "onVoiceActivationStateChanged: " + mVoiceActivationState);
int state = ShellIdentityUtils.invokeMethodWithShellPermissions(mTelephonyManager,
(tm) -> tm.getVoiceActivationState());
assertEquals(state, mVoiceActivationState);
}
@Test
public void testOnPreciseDataConnectionStateChanged() throws Throwable {
assertThat(mOnCallDisconnectCauseChangedCalled).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onPreciseDataConnectionStateChanged(
PreciseDataConnectionState state) {
synchronized (mLock) {
mOnPreciseDataConnectionStateChanged = true;
mPreciseDataConnectionState = state;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE));
});
synchronized (mLock) {
if (!mOnPreciseDataConnectionStateChanged) {
mLock.wait(WAIT_TIME);
}
}
assertThat(mOnPreciseDataConnectionStateChanged).isTrue();
assertThat(mPreciseDataConnectionState.getState())
.isIn(DATA_CONNECTION_STATE);
// Ensure that no exceptions are thrown
mPreciseDataConnectionState.getNetworkType();
mPreciseDataConnectionState.getLinkProperties();
mPreciseDataConnectionState.getLastCauseCode();
mPreciseDataConnectionState.getLinkProperties();
mPreciseDataConnectionState.getApnSetting();
mPreciseDataConnectionState.getTransportType();
mPreciseDataConnectionState.getId();
// Deprecated in R
assertEquals(mPreciseDataConnectionState.getDataConnectionState(),
mPreciseDataConnectionState.getState());
assertEquals(mPreciseDataConnectionState.getDataConnectionFailCause(),
mPreciseDataConnectionState.getLastCauseCode());
// Superseded in R by getApnSetting()
mPreciseDataConnectionState.getDataConnectionApnTypeBitMask();
mPreciseDataConnectionState.getDataConnectionApn();
}
@Test
public void testOnDisplayInfoChanged() throws Exception {
assertThat(mOnTelephonyDisplayInfoChanged).isFalse();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) {
synchronized (mLock) {
mOnTelephonyDisplayInfoChanged = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED));
});
synchronized (mLock) {
if (!mOnTelephonyDisplayInfoChanged) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnTelephonyDisplayInfoChanged);
}
@Test
public void testOnCallForwardingIndicatorChanged() throws Throwable {
assertFalse(mOnCallForwardingIndicatorChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onCallForwardingIndicatorChanged(boolean cfi) {
synchronized (mLock) {
mOnCallForwardingIndicatorChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(
mListener, PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
});
synchronized (mLock) {
if (!mOnCallForwardingIndicatorChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnCallForwardingIndicatorChangedCalled);
}
@Test
public void testOnCellLocationChanged() throws Throwable {
assertFalse(mOnCellLocationChangedCalled);
TelephonyManagerTest.grantLocationPermissions();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onCellLocationChanged(CellLocation location) {
synchronized (mLock) {
mOnCellLocationChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_LOCATION);
});
synchronized (mLock) {
if (!mOnCellLocationChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnCellLocationChangedCalled);
}
@Test
public void testOnCallStateChanged() throws Throwable {
assertFalse(mOnCallStateChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
synchronized (mLock) {
mOnCallStateChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);
});
synchronized (mLock) {
if (!mOnCallStateChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnCallStateChangedCalled);
}
@Test
public void testOnDataConnectionStateChanged() throws Throwable {
assertFalse(mOnDataConnectionStateChangedCalled);
assertFalse(mOnDataConnectionStateChangedWithNetworkTypeCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onDataConnectionStateChanged(int state) {
synchronized (mLock) {
mOnDataConnectionStateChangedCalled = true;
if (mOnDataConnectionStateChangedCalled
&& mOnDataConnectionStateChangedWithNetworkTypeCalled) {
mLock.notify();
}
}
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
synchronized (mLock) {
mOnDataConnectionStateChangedWithNetworkTypeCalled = true;
if (mOnDataConnectionStateChangedCalled
&& mOnDataConnectionStateChangedWithNetworkTypeCalled) {
mLock.notify();
}
}
}
};
mTelephonyManager.listen(
mListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
});
synchronized (mLock) {
if (!mOnDataConnectionStateChangedCalled ||
!mOnDataConnectionStateChangedWithNetworkTypeCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnDataConnectionStateChangedCalled);
assertTrue(mOnDataConnectionStateChangedWithNetworkTypeCalled);
}
@Test
public void testOnDataActivity() throws Throwable {
assertFalse(mOnDataActivityCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onDataActivity(int direction) {
synchronized (mLock) {
mOnDataActivityCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_DATA_ACTIVITY);
});
synchronized (mLock) {
if (!mOnDataActivityCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnDataActivityCalled);
}
@Test
public void testOnCellInfoChanged() throws Throwable {
assertFalse(mOnDataActivityCalled);
TelephonyManagerTest.grantLocationPermissions();
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onCellInfoChanged(List<CellInfo> cellInfo) {
synchronized (mLock) {
mOnCellInfoChangedCalled = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_CELL_INFO);
});
synchronized (mLock) {
if (!mOnCellInfoChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnCellInfoChangedCalled);
}
@Test
public void testOnUserMobileDataStateChanged() throws Throwable {
assertFalse(mOnUserMobileDataStateChanged);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onUserMobileDataStateChanged(boolean state) {
synchronized (mLock) {
mOnUserMobileDataStateChanged = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(
mListener, PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE);
});
synchronized (mLock) {
if (!mOnUserMobileDataStateChanged) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnUserMobileDataStateChanged);
}
@Test
public void testOnOutgoingSmsEmergencyNumberChanged() throws Throwable {
TelephonyUtils.addTestEmergencyNumber(
InstrumentationRegistry.getInstrumentation(), TEST_EMERGENCY_NUMBER);
LinkedBlockingQueue<Pair<EmergencyNumber, Integer>> smsCallbackQueue =
new LinkedBlockingQueue<>(1);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onOutgoingEmergencySms(EmergencyNumber emergencyNumber,
int subscriptionId) {
synchronized (mLock) {
Log.i(TAG, "onOutgoingEmergencySms: emergencyNumber=" + emergencyNumber);
smsCallbackQueue.offer(Pair.create(emergencyNumber, subscriptionId));
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_OUTGOING_EMERGENCY_SMS));
SmsManager smsManager = SmsManager.getDefault();
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(smsManager,
(sm) -> sm.sendTextMessage(TEST_EMERGENCY_NUMBER, null,
"testOutgoingSmsListenerCts", null, null));
});
try {
Pair<EmergencyNumber, Integer> emergencySmsInfo =
smsCallbackQueue.poll(WAIT_TIME, TimeUnit.MILLISECONDS);
assertNotNull("Never got emergency sms callback", emergencySmsInfo);
assertEquals(TEST_EMERGENCY_NUMBER, emergencySmsInfo.first.getNumber());
assertEquals(SubscriptionManager.getDefaultSmsSubscriptionId(),
emergencySmsInfo.second.intValue());
} catch (InterruptedException e) {
Log.e(TAG, "Operation interrupted.");
} finally {
TelephonyUtils.removeTestEmergencyNumber(
InstrumentationRegistry.getInstrumentation(), TEST_EMERGENCY_NUMBER);
}
// Disable suppressing blocking.
TelephonyUtils.endBlockSuppression(InstrumentationRegistry.getInstrumentation());
}
@Test
public void testOnActiveDataSubscriptionIdChanged() throws Throwable {
assertFalse(mOnActiveDataSubscriptionIdChanged);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onActiveDataSubscriptionIdChanged(int subId) {
synchronized (mLock) {
mOnActiveDataSubscriptionIdChanged = true;
mLock.notify();
}
}
};
mTelephonyManager.listen(
mListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
});
synchronized (mLock) {
if (!mOnActiveDataSubscriptionIdChanged) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnActiveDataSubscriptionIdChanged);
}
@Test
public void testOnBarringInfoChanged() throws Throwable {
assertFalse(mOnBarringInfoChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onBarringInfoChanged(BarringInfo barringInfo) {
synchronized (mLock) {
mOnBarringInfoChangedCalled = true;
mBarringInfo = barringInfo;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener, PhoneStateListener.LISTEN_BARRING_INFO));
});
synchronized (mLock) {
if (!mOnBarringInfoChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
assertTrue(mOnBarringInfoChangedCalled);
assertBarringInfoSane(mBarringInfo);
}
private static final int[] sBarringServiceInfoTypes = new int[]{
BarringInfo.BARRING_SERVICE_TYPE_CS_SERVICE,
BarringInfo.BARRING_SERVICE_TYPE_PS_SERVICE,
BarringInfo.BARRING_SERVICE_TYPE_CS_VOICE,
BarringInfo.BARRING_SERVICE_TYPE_MO_SIGNALLING,
BarringInfo.BARRING_SERVICE_TYPE_MO_DATA,
BarringInfo.BARRING_SERVICE_TYPE_CS_FALLBACK,
BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VOICE,
BarringInfo.BARRING_SERVICE_TYPE_MMTEL_VIDEO,
BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY,
BarringInfo.BARRING_SERVICE_TYPE_SMS
};
private static void assertBarringInfoSane(BarringInfo barringInfo) {
assertNotNull(barringInfo);
// Flags to track whether we have had unknown and known barring types reported
boolean hasBarringTypeUnknown = false;
boolean hasBarringTypeKnown = false;
for (int bsiType : sBarringServiceInfoTypes) {
BarringInfo.BarringServiceInfo bsi = barringInfo.getBarringServiceInfo(bsiType);
assertNotNull(bsi);
switch (bsi.getBarringType()) {
case BarringInfo.BarringServiceInfo.BARRING_TYPE_UNKNOWN:
hasBarringTypeUnknown = true;
assertFalse(bsi.isConditionallyBarred());
assertEquals(0, bsi.getConditionalBarringFactor());
assertEquals(0, bsi.getConditionalBarringTimeSeconds());
assertFalse(bsi.isBarred());
break;
case BarringInfo.BarringServiceInfo.BARRING_TYPE_NONE:
hasBarringTypeKnown = true;
// Unless conditional barring is active, all conditional barring fields
// should be "unset".
assertFalse(bsi.isConditionallyBarred());
assertEquals(0, bsi.getConditionalBarringFactor());
assertEquals(0, bsi.getConditionalBarringTimeSeconds());
assertFalse(bsi.isBarred());
break;
case BarringInfo.BarringServiceInfo.BARRING_TYPE_UNCONDITIONAL:
hasBarringTypeKnown = true;
// Unless conditional barring is active, all conditional barring fields
// should be "unset".
assertFalse(bsi.isConditionallyBarred());
assertEquals(0, bsi.getConditionalBarringFactor());
assertEquals(0, bsi.getConditionalBarringTimeSeconds());
assertTrue(bsi.isBarred());
break;
case BarringInfo.BarringServiceInfo.BARRING_TYPE_CONDITIONAL:
hasBarringTypeKnown = true;
// If conditional barring is active, then the barring time and factor must
// be known (set), but the device may or may not be barred at the moment,
// so isConditionallyBarred() can be either true or false (hence not checked).
assertNotEquals(0, bsi.getConditionalBarringFactor());
assertNotEquals(0, bsi.getConditionalBarringTimeSeconds());
assertEquals(bsi.isBarred(), bsi.isConditionallyBarred());
break;
}
}
// If any barring type is unknown, then barring is not supported so all must be
// unknown. If any type is known, then all that are not reported are assumed to
// be not barred.
assertNotEquals(hasBarringTypeUnknown, hasBarringTypeKnown);
}
@Test
public void testOnRegistrationFailed() throws Throwable {
assertFalse(mOnBarringInfoChangedCalled);
mHandler.post(() -> {
mListener = new PhoneStateListener() {
@Override
public void onRegistrationFailed(CellIdentity cid, String chosenPlmn,
int domain, int causeCode,
int additionalCauseCode) {
synchronized (mLock) {
mOnRegistrationFailedCalled = true;
mLock.notify();
}
}
};
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mTelephonyManager,
(tm) -> tm.listen(mListener,
PhoneStateListener.LISTEN_REGISTRATION_FAILURE));
});
synchronized (mLock) {
if (!mOnBarringInfoChangedCalled) {
mLock.wait(WAIT_TIME);
}
}
// Assert that in the WAIT_TIME interval, the listener wasn't invoked. While this is
// **technically** a flaky test, in practice this flake should happen approximately never
// as it would mean that a registered phone is failing to reselect during CTS at this
// exact moment.
//
// What the test is verifying is that there is no "auto" callback for registration
// failure because unlike other PSL registrants, this one is not called upon registration.
assertFalse(mOnRegistrationFailedCalled);
}
}