blob: 7c3279f529373c84c06318a154d8b1ea63dec29f [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cellbroadcastservice.tests;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.ContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationRequest;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Telephony;
import android.telephony.AccessNetworkConstants;
import android.telephony.CbGeoUtils;
import android.telephony.CellIdentityLte;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SmsCbCmasInfo;
import android.telephony.SmsCbLocation;
import android.telephony.SmsCbMessage;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.text.format.DateUtils;
import com.android.cellbroadcastservice.CbSendMessageCalculator;
import com.android.cellbroadcastservice.CellBroadcastHandler;
import com.android.cellbroadcastservice.CellBroadcastProvider;
import com.android.cellbroadcastservice.GsmCellBroadcastHandler;
import com.android.cellbroadcastservice.SmsCbConstants;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.List;
import java.util.Map;
import java.util.Random;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class GsmCellBroadcastHandlerTest extends CellBroadcastServiceTestBase {
private static final String TAG = GsmCellBroadcastHandlerTest.class.getSimpleName();
private GsmCellBroadcastHandler mGsmCellBroadcastHandler;
private TestableLooper mTestableLooper;
@Mock
private Map<Integer, Resources> mMockedResourcesCache;
@Mock
private SubscriptionInfo mSubInfo;
private CellBroadcastHandlerTest.CbSendMessageCalculatorFactoryFacade mSendMessageFactory;
private class CellBroadcastContentProvider extends MockContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Assume the message was received 2 hours ago.
long receivedTime = System.currentTimeMillis() - DateUtils.HOUR_IN_MILLIS * 2;
long locationCheckTime = receivedTime;
if (uri.compareTo(Telephony.CellBroadcasts.CONTENT_URI) == 0
&& Long.parseLong(selectionArgs[selectionArgs.length - 1]) <= receivedTime) {
MatrixCursor mc = new MatrixCursor(CellBroadcastProvider.QUERY_COLUMNS);
mc.addRow(new Object[]{
1, // _ID
0, // SLOT_INDEX
1, // SUBSCRIPTION_ID
0, // GEOGRAPHICAL_SCOPE
"311480", // PLMN
0, // LAC
0, // CID
1234, // SERIAL_NUMBER
SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
"en", // LANGUAGE_CODE
1, // DATA_CODING_SCHEME
"Test Message", // MESSAGE_BODY
1, // MESSAGE_FORMAT
3, // MESSAGE_PRIORITY
0, // ETWS_WARNING_TYPE
0, // ETWS_IS_PRIMARY
SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT, // CMAS_MESSAGE_CLASS
0, // CMAS_CATEGORY
0, // CMAS_RESPONSE_TYPE
0, // CMAS_SEVERITY
0, // CMAS_URGENCY
0, // CMAS_CERTAINTY
receivedTime, // RECEIVED_TIME
locationCheckTime, // LOCATION_CHECK_TIME
false, // MESSAGE_BROADCASTED
true, // MESSAGE_DISPLAYED
"", // GEOMETRIES
5, // MAXIMUM_WAIT_TIME
});
return mc;
}
return null;
}
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
return 1;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
}
private class SettingsProvider extends MockContentProvider {
@Override
public Bundle call(String method, String arg, Bundle extras) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return null;
}
}
private CellBroadcastHandler.HandlerHelper mHandlerHelper;
@Before
public void setUp() throws Exception {
super.setUp();
mTestableLooper = TestableLooper.get(GsmCellBroadcastHandlerTest.this);
mSendMessageFactory = new CellBroadcastHandlerTest.CbSendMessageCalculatorFactoryFacade();
mHandlerHelper = mock(CellBroadcastHandler.HandlerHelper.class);
// need to init mocked resources before creating GsmCellBroadcastHandler
((MockContentResolver) mMockedContext.getContentResolver()).addProvider(
Telephony.CellBroadcasts.CONTENT_URI.getAuthority(),
new CellBroadcastContentProvider());
((MockContentResolver) mMockedContext.getContentResolver()).addProvider(
Settings.AUTHORITY, new SettingsProvider());
doReturn(true).when(mMockedResourcesCache).containsKey(anyInt());
doReturn(mMockedResources).when(mMockedResourcesCache).get(anyInt());
putResources(com.android.cellbroadcastservice.R.integer.message_expiration_time, 86400000);
putResources(com.android.cellbroadcastservice.R.array
.additional_cell_broadcast_receiver_packages, new String[]{});
putResources(com.android.cellbroadcastservice.R.array.area_info_channels, new int[]{});
putResources(
com.android.cellbroadcastservice.R.array.config_area_info_receiver_packages,
new String[]{"fake.inforeceiver.pkg"});
putResources(com.android.cellbroadcastservice.R.bool.reset_area_info_on_oos, true);
doReturn(1).when(mMockedTelephonyManager).getActiveModemCount();
doReturn(mSubInfo).when(mMockedSubscriptionManager)
.getActiveSubscriptionInfoForSimSlotIndex(anyInt());
doReturn(FAKE_SUBID).when(mSubInfo).getSubscriptionId();
mGsmCellBroadcastHandler = new GsmCellBroadcastHandler(mMockedContext,
mTestableLooper.getLooper(), mSendMessageFactory, mHandlerHelper, mMockedResources,
FAKE_SUBID);
// after mGsmCellBroadcastHandler's constructor has run, now we can replace the
// mResourcesCache instance
replaceInstance(CellBroadcastHandler.class, "mResourcesCache",
mGsmCellBroadcastHandler, mMockedResourcesCache);
doAnswer(invocation -> {
Runnable r = invocation.getArgument(0);
mGsmCellBroadcastHandler.getHandler().post(r);
return null;
}).when(mHandlerHelper).post(any());
doReturn(mGsmCellBroadcastHandler.getHandler()).when(mHandlerHelper).getHandler();
mGsmCellBroadcastHandler.start();
}
@After
public void tearDown() throws Exception {
super.tearDown();
}
@Test
@SmallTest
public void testTriggerMessage() throws Exception {
final byte[] pdu = hexStringToBytes("0001113001010010C0111204D2");
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
LocationListener listener = getLocationCallback();
listener.onLocationChanged(mock(Location.class));
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockedContext).sendOrderedBroadcast(intentCaptor.capture(), any(),
(Bundle) any(), any(), any(), anyInt(), any(), any());
Intent intent = intentCaptor.getValue();
assertEquals(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED, intent.getAction());
SmsCbMessage msg = intent.getParcelableExtra("message");
assertEquals(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
msg.getServiceCategory());
assertEquals(1234, msg.getSerialNumber());
assertEquals("Test Message", msg.getMessageBody());
}
@Test
public void testCleanup() throws Exception {
mGsmCellBroadcastHandler.cleanup();
// mGsmReceiver and mReceiver should be unregistered
verify(mMockedContext, times(2)).unregisterReceiver(any());
}
@Test
@SmallTest
public void testAirplaneModeReset() {
putResources(com.android.cellbroadcastservice.R.bool.reset_on_power_cycle_or_airplane_mode,
true);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", true);
// Send fake airplane mode on event.
sendBroadcast(intent);
final byte[] pdu = hexStringToBytes("0001113001010010C0111204D2");
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
verify(mMockedContext, never()).sendOrderedBroadcast(any(), anyString(), anyString(),
any(), any(), anyInt(), any(), any());
}
@Test
@SmallTest
public void testGeofencingAlertOutOfPolygon() {
final byte[] pdu = hexStringToBytes("01111D7090010254747A0E4ACF416110B538A582DE6650906AA28"
+ "2AE6979995D9ECF41C576597E2EBBC77950905D96D3D3EE33689A9FD3CB6D1708CA2E87E76550FAE"
+ "C7ECBCB203ABA0C6A97E7F3F0B9EC02C15CB5769A5D0652A030FB1ECECF5D5076393C2F83C8E9B9B"
+ "C7C0ECBC9203A3A3D07B5CBF379F85C06E16030580D660BB662B51A0D57CC3500000000000000000"
+ "0000000000000000000000000000000000000000000000000003021002078B53B6CA4B84B53988A4"
+ "B86B53958A4C2DB53B54A4C28B53B6CA4B840100CFF");
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
LocationListener listener = getLocationCallback();
listener.onLocationChanged(mock(Location.class));
verify(mMockedContext, never()).sendOrderedBroadcast(any(), anyString(), anyString(),
any(), any(), anyInt(), any(), any());
}
@Test
@SmallTest
public void testSmsCbLocation() {
final byte[] pdu = hexStringToBytes("01111B40110101C366701A09368545692408000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000B");
final String fakePlmn = "310999";
final int fakeTac = 1234;
final int fakeCid = 5678;
doReturn(fakePlmn).when(mMockedTelephonyManager).getNetworkOperator();
ServiceState ss = mock(ServiceState.class);
doReturn(ss).when(mMockedTelephonyManager).getServiceState();
NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
.setDomain(NetworkRegistrationInfo.DOMAIN_CS)
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
.setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.setCellIdentity(new CellIdentityLte(0, 0, fakeCid, 0, fakeTac))
.build();
doReturn(nri).when(ss).getNetworkRegistrationInfo(anyInt(), anyInt());
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockedContext).sendOrderedBroadcast(intentCaptor.capture(), any(),
(Bundle) any(), any(), any(), anyInt(), any(), any());
Intent intent = intentCaptor.getValue();
assertEquals(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED, intent.getAction());
SmsCbMessage msg = intent.getParcelableExtra("message");
SmsCbLocation location = msg.getLocation();
assertEquals(fakePlmn, location.getPlmn());
assertEquals(fakeTac, location.getLac());
assertEquals(fakeCid, location.getCid());
}
@Test
@SmallTest
public void testGeofencingAmbiguousWithMockCalculator() {
// Create Mock calculator
CbSendMessageCalculator mockCalculator = createMockCalculatorAndSendCellBroadcast();
ArgumentCaptor<List<CbGeoUtils.Geometry>> geosCaptor =
ArgumentCaptor.forClass((Class) List.class);
verify(mSendMessageFactory.getUnderlyingFactory()).createNew(any(), geosCaptor.capture());
List<CbGeoUtils.Geometry> geos = geosCaptor.getValue();
assertEquals(1, geos.size());
doReturn(geos).when(mockCalculator).getFences();
// Set location to be ambiguous
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_AMBIGUOUS,
false, true);
// Set location again to be ambiguous
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_AMBIGUOUS,
false, true);
// Run location unavailable
runLocationUnavailableWhenMaxTimeReached();
// Verify mark as sent and the right kind of broadcast has been sent
verify(mockCalculator, times(1)).markAsSent();
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockedContext).sendOrderedBroadcast(intentCaptor.capture(), any(),
(Bundle) any(), any(), any(), anyInt(), any(), any());
Intent intent = intentCaptor.getValue();
assertEquals(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED, intent.getAction());
}
@Test
@SmallTest
public void testGeofencingNoCoordinatesWithMockCalculator() {
CbSendMessageCalculator mockCalculator = createMockCalculatorAndSendCellBroadcast();
ArgumentCaptor<List<CbGeoUtils.Geometry>> geosCaptor =
ArgumentCaptor.forClass((Class) List.class);
verify(mSendMessageFactory.getUnderlyingFactory()).createNew(any(), geosCaptor.capture());
List<CbGeoUtils.Geometry> geos = geosCaptor.getValue();
assertEquals(1, geos.size());
doReturn(geos).when(mockCalculator).getFences();
runLocationUnavailableWhenMaxTimeReached();
verifyBroadcastSent(mockCalculator);
}
@Test
@SmallTest
public void testGeofencingSendImmediatelyWithMockCalculator() {
CbSendMessageCalculator mockCalculator = createMockCalculatorAndSendCellBroadcast();
ArgumentCaptor<List<CbGeoUtils.Geometry>> geosCaptor =
ArgumentCaptor.forClass((Class) List.class);
verify(mSendMessageFactory.getUnderlyingFactory()).createNew(any(), geosCaptor.capture());
List<CbGeoUtils.Geometry> geos = geosCaptor.getValue();
assertEquals(1, geos.size());
doReturn(geos).when(mockCalculator).getFences();
// Set location to AMBIGUOUS
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_AMBIGUOUS,
false, true);
// Set location to SEND
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_SEND,
true, true);
// Make sure we don't send again
doReturn(CbSendMessageCalculator.SEND_MESSAGE_ACTION_SENT).when(mockCalculator).getAction();
// Check location request was cancelled
assertLocationRequestCancelled();
// This should never hit since the was cancelled
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_SENT,
false, false);
// Not sent
verifyBroadcastNotSent(mockCalculator);
}
@Test
@SmallTest
public void testGeofencingDontSendWithMockCalculator() {
// Create Mock calculator
CbSendMessageCalculator mockCalculator = createMockCalculatorAndSendCellBroadcast();
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_DONT_SEND,
false, true);
// This method is copied form #testSmsCbLocation that sends out a message. Except, in
// this case, we are overriding the calculator with DONT_SEND and so our verification is
// is that no broadcast was sent.
final byte[] pdu = hexStringToBytes("01111B40110101C366701A09368545692408000000000000000"
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ "000000000000000000000000000000000000000000000000B");
final String fakePlmn = "310999";
final int fakeTac = 1234;
final int fakeCid = 5678;
doReturn(fakePlmn).when(mMockedTelephonyManager).getNetworkOperator();
ServiceState ss = mock(ServiceState.class);
doReturn(ss).when(mMockedTelephonyManager).getServiceState();
NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
.setDomain(NetworkRegistrationInfo.DOMAIN_CS)
.setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
.setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
.setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
.setCellIdentity(new CellIdentityLte(0, 0, fakeCid, 0, fakeTac))
.build();
doReturn(nri).when(ss).getNetworkRegistrationInfo(anyInt(), anyInt());
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
verifyBroadcastNotSent(mockCalculator);
assertLocationRequestCancelled();
verifyBroadcastNotSent(mockCalculator);
}
@Test
@SmallTest
public void testConsecutiveGeofencingTriggerMessages() throws Exception {
final byte[] pdu = hexStringToBytes("0001113001010010C0111204D2");
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
LocationListener listener = getLocationCallback();
mGsmCellBroadcastHandler.sendMessageBroadcastNotRequired();
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
listener.onLocationChanged(mock(Location.class));
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockedContext, times(2)).sendOrderedBroadcast(intentCaptor.capture(), any(),
(Bundle) any(), any(), any(), anyInt(), any(), any());
Intent intent = intentCaptor.getValue();
assertEquals(Telephony.Sms.Intents.ACTION_SMS_EMERGENCY_CB_RECEIVED, intent.getAction());
SmsCbMessage msg = intent.getParcelableExtra("message");
assertEquals(SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
msg.getServiceCategory());
assertEquals(1234, msg.getSerialNumber());
assertEquals("Test Message", msg.getMessageBody());
}
@Test
@SmallTest
public void testConsecutiveGeoFencingMessages() throws Exception {
CbSendMessageCalculator mockCalculator = createMockCalculatorAndSendCellBroadcast();
mGsmCellBroadcastHandler.sendMessageBroadcastNotRequired();
CbSendMessageCalculator mockCalculator2 = createMockCalculatorAndSendCellBroadcast();
ArgumentCaptor<List<CbGeoUtils.Geometry>> geosCaptor =
ArgumentCaptor.forClass((Class) List.class);
verify(mSendMessageFactory.getUnderlyingFactory()).createNew(any(), geosCaptor.capture());
List<CbGeoUtils.Geometry> geos = geosCaptor.getValue();
assertEquals(1, geos.size());
doReturn(geos).when(mockCalculator).getFences();
// Set the new action to return
doReturn(CbSendMessageCalculator.SEND_MESSAGE_ACTION_DONT_SEND).when(mockCalculator2)
.getAction();
// Set location to SEND
setMockCalculation(mockCalculator, CbSendMessageCalculator.SEND_MESSAGE_ACTION_SEND,
true, true);
}
@Test
@SmallTest
public void testResetAreaInfoOnOutOfService() {
String areaInfo = "0000000000000000";
mGsmCellBroadcastHandler.setCellBroadcastAreaInfo(0, areaInfo);
assertEquals(areaInfo, mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(0));
ArgumentCaptor<PhoneStateListener> listenerCaptor =
ArgumentCaptor.forClass(PhoneStateListener.class);
verify(mMockedTelephonyManager).listen(listenerCaptor.capture(), anyInt());
PhoneStateListener listener = listenerCaptor.getValue();
ServiceState ss = mock(ServiceState.class);
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(ss).getState();
listener.onServiceStateChanged(ss);
assertEquals("", mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(0));
}
@Test
@SmallTest
public void testResetAreaInfoWithDefaultSubChanged() {
String areaInfo = "0000000000000000";
mGsmCellBroadcastHandler.setCellBroadcastAreaInfo(0, areaInfo);
assertEquals(areaInfo, mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(0));
TelephonyManager tm2 = mock(TelephonyManager.class);
doReturn(tm2).when(mMockedTelephonyManager).createForSubscriptionId(FAKE_SUBID + 1);
SubscriptionInfo subInfo = mock(SubscriptionInfo.class);
doReturn(subInfo).when(mMockedSubscriptionManager)
.getActiveSubscriptionInfoForSimSlotIndex(anyInt());
doReturn(FAKE_SUBID + 1).when(subInfo).getSubscriptionId();
Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, FAKE_SUBID + 1);
sendBroadcast(intent);
ArgumentCaptor<PhoneStateListener> listenerCaptor =
ArgumentCaptor.forClass(PhoneStateListener.class);
mTestableLooper.processAllMessages();
verify(tm2).listen(listenerCaptor.capture(), anyInt());
PhoneStateListener listener = listenerCaptor.getValue();
ServiceState ss = mock(ServiceState.class);
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(ss).getState();
listener.onServiceStateChanged(ss);
assertEquals("", mGsmCellBroadcastHandler.getCellBroadcastAreaInfo(0));
}
@Test
@SmallTest
public void testDoNotResetAreaInfoWithInvalidSubId() {
new GsmCellBroadcastHandler(mMockedContext,
mTestableLooper.getLooper(), mSendMessageFactory, mHandlerHelper, mMockedResources,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
verify(mMockedContext, never()).getResources();
}
/* Below are helper methods for setting up mocks, verifying actions, etc. */
private void verifyBroadcastSent(CbSendMessageCalculator mockCalculator) {
verify(mMockedContext).sendOrderedBroadcast(any(), any(),
(Bundle) any(), any(), any(), anyInt(), any(), any());
clearInvocations(mMockedContext);
verify(mockCalculator, times(1)).markAsSent();
clearInvocations(mockCalculator);
}
private void verifyBroadcastNotSent(CbSendMessageCalculator mockCalculator) {
verify(mockCalculator, times(0)).markAsSent();
verify(mMockedContext, never()).sendOrderedBroadcast(any(), anyString(), anyString(),
any(), any(), anyInt(), any(), any());
}
private CbSendMessageCalculator createMockCalculatorAndSendCellBroadcast() {
CbSendMessageCalculator calculator = createMockCalculator();
final byte[] pdu = hexStringToBytes("01111D7090010254747A0E4ACF416110B538A582DE6650906AA28"
+ "2AE6979995D9ECF41C576597E2EBBC77950905D96D3D3EE33689A9FD3CB6D1708CA2E87E76550FAE"
+ "C7ECBCB203ABA0C6A97E7F3F0B9EC02C15CB5769A5D0652A030FB1ECECF5D5076393C2F83C8E9B9B"
+ "C7C0ECBC9203A3A3D07B5CBF379F85C06E16030580D660BB662B51A0D57CC3500000000000000000"
+ "0000000000000000000000000000000000000000000000000003021002078B53B6CA4B84B53988A4"
+ "B86B53958A4C2DB53B54A4C28B53B6CA4B840100CFF");
mGsmCellBroadcastHandler.onGsmCellBroadcastSms(0, pdu);
mTestableLooper.processAllMessages();
return calculator;
}
private CbSendMessageCalculator createMockCalculator() {
CbSendMessageCalculator mockCalculator = mock(CbSendMessageCalculator.class);
CellBroadcastHandler.CbSendMessageCalculatorFactory factory = mock(
CellBroadcastHandler.CbSendMessageCalculatorFactory.class);
mSendMessageFactory.setUnderlyingFactory(factory);
doReturn(mockCalculator).when(factory).createNew(any(), any());
doReturn(CbSendMessageCalculator.SEND_MESSAGE_ACTION_NO_COORDINATES)
.when(mockCalculator).getAction();
return mockCalculator;
}
Random mRandom = new Random(10);
void setMockCalculation(CbSendMessageCalculator mockCalculator,
@CbSendMessageCalculator.SendMessageAction int newAction,
boolean broadcastShouldBeSent, boolean addCoordinateShouldBeCalled) {
// Create a random location and accuracy. The values are ignored since the calculator
// is a mock.
CbGeoUtils.LatLng latLng = new CbGeoUtils.LatLng(mRandom.nextFloat() % 150 + 1,
mRandom.nextFloat() % 150 + 1);
float accuracy = mRandom.nextFloat() % 3000 + 1;
// Create location based off of specified coordinates and accuracy
Location location = createMockLocation(latLng, accuracy);
// Set the new action to return
doReturn(newAction).when(mockCalculator).getAction();
// Send the new location through location manager
LocationListener locationListener = getLocationCallback();
locationListener.onLocationChanged(location);
// Verify that the correct coordinate was sent to calculator
ArgumentCaptor<CbGeoUtils.LatLng> acLatLng =
ArgumentCaptor.forClass(CbGeoUtils.LatLng.class);
verify(mockCalculator, times(addCoordinateShouldBeCalled ? 1 : 0))
.addCoordinate(acLatLng.capture(), eq(accuracy));
if (addCoordinateShouldBeCalled) {
assertEquals(acLatLng.getValue().lat, latLng.lat);
assertEquals(acLatLng.getValue().lng, latLng.lng);
}
if (broadcastShouldBeSent) {
verifyBroadcastSent(mockCalculator);
} else {
verifyBroadcastNotSent(mockCalculator);
}
}
Location createMockLocation(CbGeoUtils.LatLng latLng, float accuracy) {
Location location = mock(Location.class);
doReturn(latLng.lat).when(location).getLatitude();
doReturn(latLng.lng).when(location).getLongitude();
doReturn(accuracy).when(location).getAccuracy();
return location;
}
private void runLocationUnavailableWhenMaxTimeReached() {
ArgumentCaptor<Runnable> onLocationUnavailableCaptor =
ArgumentCaptor.forClass(Runnable.class);
verify(mHandlerHelper).postDelayed(onLocationUnavailableCaptor.capture(), anyLong());
// Before running location unavailable, we check that the callback wasn't removed.
// Similar to assertLocationRequestCancelled
verify(mHandlerHelper, times(0))
.removeCallbacks(onLocationUnavailableCaptor.getValue());
onLocationUnavailableCaptor.getValue().run();
}
private void assertLocationRequestCancelled() {
ArgumentCaptor<Runnable> onLocationUnavailableCaptor =
ArgumentCaptor.forClass(Runnable.class);
verify(mHandlerHelper).postDelayed(onLocationUnavailableCaptor.capture(), anyLong());
verify(mHandlerHelper, times(1))
.removeCallbacks(onLocationUnavailableCaptor.getValue());
}
private LocationListener getLocationCallback() {
ArgumentCaptor<LocationListener> locationListenerCaptor =
ArgumentCaptor.forClass(LocationListener.class);
verify(mMockedLocationManager).requestLocationUpdates(
any(LocationRequest.class), any(), locationListenerCaptor.capture());
return locationListenerCaptor.getValue();
}
}