blob: ed480709078939bc21b26cfcd7884c69dee16e3c [file] [log] [blame]
/*
* Copyright (C) 2016 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.providers.blockednumber;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.location.Country;
import android.net.Uri;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.SystemProperties;
import android.provider.BlockedNumberContract;
import android.provider.BlockedNumberContract.BlockedNumbers;
import android.provider.BlockedNumberContract.SystemContract;
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.MediumTest;
import junit.framework.Assert;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* runtest --path packages/providers/BlockedNumberProvider/tests
*/
@MediumTest
public class BlockedNumberProviderTest extends AndroidTestCase {
private MyMockContext mMockContext;
private ContentResolver mResolver;
@Override
protected void setUp() throws Exception {
super.setUp();
BlockedNumberProvider.ALLOW_SELF_CALL = false;
mMockContext = spy(new MyMockContext(getContext()));
mMockContext.initializeContext();
mResolver = mMockContext.getContentResolver();
when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(true);
when(mMockContext.mCountryDetector.detectCountry())
.thenReturn(new Country("US", Country.COUNTRY_SOURCE_LOCATION));
when(mMockContext.mAppOpsManager.noteOp(
eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
.thenReturn(AppOpsManager.MODE_ERRORED);
}
@Override
protected void tearDown() throws Exception {
mMockContext.shutdown();
super.tearDown();
}
private static ContentValues cv(Object... namesAndValues) {
Assert.assertTrue((namesAndValues.length % 2) == 0);
final ContentValues ret = new ContentValues();
for (int i = 1; i < namesAndValues.length; i += 2) {
final String name = namesAndValues[i - 1].toString();
final Object value = namesAndValues[i];
if (value == null) {
ret.putNull(name);
} else if (value instanceof String) {
ret.put(name, (String) value);
} else if (value instanceof Integer) {
ret.put(name, (Integer) value);
} else if (value instanceof Long) {
ret.put(name, (Long) value);
} else {
Assert.fail("Unsupported type: " + value.getClass().getSimpleName());
}
}
return ret;
}
private void assertRowCount(int count, Uri uri) {
try (Cursor c = mResolver.query(uri, null, null, null, null)) {
assertEquals(count, c.getCount());
}
}
public void testGetType() {
assertEquals(BlockedNumbers.CONTENT_TYPE, mResolver.getType(
BlockedNumbers.CONTENT_URI));
assertEquals(BlockedNumbers.CONTENT_ITEM_TYPE, mResolver.getType(
ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, 1)));
assertNull(mResolver.getType(
Uri.withAppendedPath(BlockedNumberContract.AUTHORITY_URI, "invalid")));
}
public void testInsert() {
insertExpectingFailure(cv());
insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, null));
insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, ""));
insertExpectingFailure(cv(BlockedNumbers.COLUMN_ID, 1));
insertExpectingFailure(cv(BlockedNumbers.COLUMN_E164_NUMBER, "1"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
// Re-inserting the same number should be ok, but the E164 number is replaced.
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222",
BlockedNumbers.COLUMN_E164_NUMBER, "+814084542222"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-4542222"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
BlockedNumbers.COLUMN_E164_NUMBER, "+81453811111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "12345"));
assertRowCount(7, BlockedNumbers.CONTENT_URI);
assertContents(1, "123", "");
assertContents(2, "+1-2-3", "");
assertContents(3, "+1-408-454-1111", "+14084541111");
// Missing 4 due to re-insertion of the same number.
assertContents(5, "1-408-454-2222", "+814084542222");
assertContents(6, "1-408-4542222", "+14084542222");
assertContents(7, "045-381-1111", "+81453811111");
assertContents(8, "12345", "");
}
public void testChangesNotified() throws Exception {
Cursor c = mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
final CountDownLatch latch = new CountDownLatch(2);
ContentObserver contentObserver = new ContentObserver(null) {
@Override
public void onChange(boolean selfChange) {
Assert.assertFalse(selfChange);
latch.notify();
}
};
c.registerContentObserver(contentObserver);
try {
Uri uri = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "14506507000"));
mResolver.delete(uri, null, null);
latch.await(10, TimeUnit.SECONDS);
verify(mMockContext.mBackupManager, times(2)).dataChanged();
} catch (Exception e) {
fail(e.toString());
} finally {
c.unregisterContentObserver(contentObserver);
}
}
private Uri insert(ContentValues cv) {
final Uri uri = mResolver.insert(BlockedNumbers.CONTENT_URI, cv);
assertNotNull(uri);
// Make sure the URI exists.
try (Cursor c = mResolver.query(uri, null, null, null, null)) {
assertEquals(1, c.getCount());
}
return uri;
}
private void insertExpectingFailure(ContentValues cv) {
try {
mResolver.insert(
BlockedNumbers.CONTENT_URI, cv);
fail();
} catch (IllegalArgumentException expected) {
}
}
public void testDelete() {
// Prepare test data
Uri u1 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
Uri u2 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
BlockedNumbers.COLUMN_E164_NUMBER, "12345"));
assertRowCount(5, BlockedNumbers.CONTENT_URI);
// Delete and check the # of remaining rows.
mResolver.delete(u1, null, null);
assertRowCount(4, BlockedNumbers.CONTENT_URI);
try {
mResolver.delete(u2, "1=1", null);
fail();
} catch (IllegalArgumentException expected) {
MoreAsserts.assertContainsRegex("selection must be null", expected.getMessage());
}
mResolver.delete(u2, null, null);
assertRowCount(3, BlockedNumbers.CONTENT_URI);
mResolver.delete(BlockedNumbers.CONTENT_URI,
BlockedNumbers.COLUMN_E164_NUMBER + "=?",
new String[]{"12345"});
assertRowCount(2, BlockedNumbers.CONTENT_URI);
// SQL injection should be detected.
try {
mResolver.delete(BlockedNumbers.CONTENT_URI, "; DROP TABLE blocked; ", null);
fail();
} catch (SQLiteException expected) {
}
assertRowCount(2, BlockedNumbers.CONTENT_URI);
mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
assertRowCount(0, BlockedNumbers.CONTENT_URI);
}
public void testUpdate() {
try {
mResolver.update(BlockedNumbers.CONTENT_URI, cv(),
/* selection =*/ null, /* args =*/ null);
fail();
} catch (UnsupportedOperationException expected) {
MoreAsserts.assertContainsRegex("Update is not supported", expected.getMessage());
}
}
public void testBlockSuppressionAfterEmergencyContact() {
int blockSuppressionSeconds = 1000;
when(mMockContext.mCarrierConfigManager.getConfig())
.thenReturn(getBundleWithInt(blockSuppressionSeconds));
String phoneNumber = "5004541111";
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
// No emergency contact: Blocks should not be suppressed.
assertIsBlocked(true, phoneNumber);
assertShouldSystemBlock(true, phoneNumber, null);
verifyBlocksNotSuppressed();
assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
// No emergency contact yet: Ending block suppression should be a no-op.
SystemContract.endBlockSuppression(mMockContext);
assertIsBlocked(true, phoneNumber);
assertShouldSystemBlock(true, phoneNumber, null);
verifyBlocksNotSuppressed();
assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
// After emergency contact blocks should be suppressed.
long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
SystemContract.notifyEmergencyContact(mMockContext);
assertIsBlocked(true, phoneNumber);
assertShouldSystemBlock(false, phoneNumber, null);
SystemContract.BlockSuppressionStatus status =
SystemContract.getBlockSuppressionStatus(mMockContext);
assertTrue(status.isSuppressed);
assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
blockSuppressionSeconds, status.untilTimestampMillis);
assertEquals(1, mMockContext.mIntentsBroadcasted.size());
assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
mMockContext.mIntentsBroadcasted.get(0));
mMockContext.mIntentsBroadcasted.clear();
// Ending block suppression should work.
SystemContract.endBlockSuppression(mMockContext);
assertIsBlocked(true, phoneNumber);
assertShouldSystemBlock(true, phoneNumber, null);
verifyBlocksNotSuppressed();
assertEquals(1, mMockContext.mIntentsBroadcasted.size());
assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
mMockContext.mIntentsBroadcasted.get(0));
}
public void testBlockSuppressionAfterEmergencyContact_invalidCarrierConfigDefaultValueUsed() {
int invalidBlockSuppressionSeconds = 700000; // > 1 week
when(mMockContext.mCarrierConfigManager.getConfig())
.thenReturn(getBundleWithInt(invalidBlockSuppressionSeconds));
String phoneNumber = "5004541111";
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
SystemContract.notifyEmergencyContact(mMockContext);
assertIsBlocked(true, phoneNumber);
assertShouldSystemBlock(false, phoneNumber, null);
SystemContract.BlockSuppressionStatus status =
SystemContract.getBlockSuppressionStatus(mMockContext);
assertTrue(status.isSuppressed);
assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
7200 /* Default value of 2 hours */, status.untilTimestampMillis);
assertEquals(1, mMockContext.mIntentsBroadcasted.size());
assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
mMockContext.mIntentsBroadcasted.get(0));
}
public void testEnhancedBlock() {
String phoneNumber = "5004541111";
// Check whether block numbers not in contacts setting works well
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, true));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, false);
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
// Check whether block private number calls setting works well
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, false);
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
// Check whether block payphone calls setting works well
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, false);
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
// Check whether block unknown calls setting works well
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, false);
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
}
public void testEnhancedBlockSuppressionAfterEmergencyContact() {
String phoneNumber = "5004541111";
int blockSuppressionSeconds = 1000;
when(mMockContext.mCarrierConfigManager.getConfig())
.thenReturn(getBundleWithInt(blockSuppressionSeconds));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
// After emergency contact blocks should be suppressed.
long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
SystemContract.notifyEmergencyContact(mMockContext);
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
assertShouldSystemBlock(false, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
SystemContract.BlockSuppressionStatus status =
SystemContract.getBlockSuppressionStatus(mMockContext);
assertTrue(status.isSuppressed);
assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
blockSuppressionSeconds, status.untilTimestampMillis);
assertEquals(1, mMockContext.mIntentsBroadcasted.size());
assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
mMockContext.mIntentsBroadcasted.get(0));
mMockContext.mIntentsBroadcasted.clear();
// Ending block suppression should work.
SystemContract.endBlockSuppression(mMockContext);
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
assertShouldSystemBlock(true, phoneNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
verifyBlocksNotSuppressed();
assertEquals(1, mMockContext.mIntentsBroadcasted.size());
assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
mMockContext.mIntentsBroadcasted.get(0));
}
public void testRegularAppCannotAccessApis() {
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
try {
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.isBlocked(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.unblock(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.notifyEmergencyContact(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.endBlockSuppression(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.shouldSystemBlockNumber(mMockContext, "123", null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.getBlockSuppressionStatus(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
}
public void testCarrierAppCanAccessApis() {
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
when(mMockContext.mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(anyString()))
.thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
mResolver.insert(
BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
assertIsBlocked(true, "123");
// Dialer check is executed twice: once for insert, and once for isBlocked.
verify(mMockContext.mTelephonyManager, times(2))
.checkCarrierPrivilegesForPackageAnyPhone(anyString());
}
public void testSelfCanAccessApis() {
BlockedNumberProvider.ALLOW_SELF_CALL = true;
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
mResolver.insert(
BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
assertIsBlocked(true, "123");
}
public void testDefaultDialerCanAccessApis() {
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
when(mMockContext.mTelecomManager.getDefaultDialerPackage())
.thenReturn(getContext().getPackageName());
mResolver.insert(
BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
assertIsBlocked(true, "123");
// Dialer check is executed twice: once for insert, and once for isBlocked.
verify(mMockContext.mTelecomManager, times(2)).getDefaultDialerPackage();
}
public void testPrivilegedAppCannotUseSystemApis() {
reset(mMockContext.mAppOpsManager);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
// Pretend to be the Default SMS app.
when(mMockContext.mAppOpsManager.noteOp(
eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
.thenReturn(AppOpsManager.MODE_ALLOWED);
// Public APIs should work.
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
assertIsBlocked(true, "123");
try {
SystemContract.notifyEmergencyContact(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.endBlockSuppression(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.shouldSystemBlockNumber(mMockContext, "123", null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
SystemContract.getBlockSuppressionStatus(mMockContext);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
}
public void testIsBlocked() {
assertTrue(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
// Prepare test data
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1.2-3"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-500-454-2222"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-111-2222",
BlockedNumbers.COLUMN_E164_NUMBER, "+81451112222"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
// Check
assertIsBlocked(false, "");
assertIsBlocked(false, null);
assertIsBlocked(true, "123");
assertIsBlocked(false, "1234");
assertIsBlocked(true, "+81451112222");
assertIsBlocked(true, "+81 45 111 2222");
assertIsBlocked(true, "045-111-2222");
assertIsBlocked(false, "045 111 2222");
assertIsBlocked(true, "500-454 1111");
assertIsBlocked(true, "500-454 2222");
assertIsBlocked(true, "+1 500-454 1111");
assertIsBlocked(true, "1 500-454 1111");
assertIsBlocked(true, "abc.def@gmail.com");
assertIsBlocked(false, "abc.def@gmail.co");
assertIsBlocked(false, "bc.def@gmail.com");
assertIsBlocked(false, "abcdef@gmail.com");
}
public void testUnblock() {
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1500-454-1111"));
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
// Unblocking non-existent number is a no-op.
assertEquals(0, BlockedNumberContract.unblock(mMockContext, "12345"));
// Both rows which map to the same E164 number are deleted.
assertEquals(2, BlockedNumberContract.unblock(mMockContext, "5004541111"));
assertIsBlocked(false, "1-500-454-1111");
assertEquals(1, BlockedNumberContract.unblock(mMockContext, "abc.def@gmail.com"));
assertIsBlocked(false, "abc.def@gmail.com");
}
public void testEmergencyNumbersAreNotBlockedBySystem() {
String emergencyNumber = getEmergencyNumberFromSystemPropertiesOrDefault();
doReturn(true).when(mMockContext.mTelephonyManager).isEmergencyNumber(emergencyNumber);
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, emergencyNumber));
assertIsBlocked(true, emergencyNumber);
assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber, null));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false)));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false)));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false)));
setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false)));
}
public void testPrivilegedAppAccessingApisAsSecondaryUser() {
when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
try {
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
fail("SecurityException expected");
} catch (SecurityException expected) {
assertTrue(expected.getMessage().contains("current user"));
}
try {
mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.isBlocked(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.unblock(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
}
public void testRegularAppAccessingApisAsSecondaryUser() {
when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mMockContext).checkCallingPermission(anyString());
assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
try {
insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.isBlocked(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
try {
BlockedNumberContract.unblock(mMockContext, "123");
fail("SecurityException expected");
} catch (SecurityException expected) {
}
}
private void assertIsBlocked(boolean expected, String phoneNumber) {
assertEquals(expected, BlockedNumberContract.isBlocked(mMockContext, phoneNumber));
}
private void assertShouldSystemBlock(boolean expected, String phoneNumber, Bundle extras) {
assertEquals(expected,
SystemContract.shouldSystemBlockNumber(mMockContext, phoneNumber, extras)
!= BlockedNumberContract.STATUS_NOT_BLOCKED);
}
private void setEnhancedBlockSetting(String key, boolean value) {
SystemContract.setEnhancedBlockSetting(mMockContext, key, value);
}
private Bundle createBundleForEnhancedBlocking(int presentation, boolean contactExist) {
Bundle extras = new Bundle();
extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION, presentation);
extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST, contactExist);
return extras;
}
private PersistableBundle getBundleWithInt(int value) {
PersistableBundle bundle = new PersistableBundle();
bundle.putInt(
CarrierConfigManager.KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, value);
return bundle;
}
private void verifyBlocksNotSuppressed() {
SystemContract.BlockSuppressionStatus status =
SystemContract.getBlockSuppressionStatus(mMockContext);
assertFalse(status.isSuppressed);
assertEquals(0, status.untilTimestampMillis);
}
private void assertValidBlockSuppressionExpiration(long timestampMillisBeforeEmergencyContact,
int blockSuppressionSeconds,
long actualExpirationMillis) {
assertTrue(actualExpirationMillis
>= timestampMillisBeforeEmergencyContact + blockSuppressionSeconds * 1000);
assertTrue(actualExpirationMillis < timestampMillisBeforeEmergencyContact +
2 * blockSuppressionSeconds * 1000);
}
private void assertContents(int rowId, String originalNumber, String e164Number) {
Uri uri = ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, rowId);
try (Cursor c = mResolver.query(uri, null, null, null, null)) {
assertEquals(1, c.getCount());
c.moveToNext();
assertEquals(3, c.getColumnCount());
assertEquals(rowId, c.getInt(c.getColumnIndex(BlockedNumbers.COLUMN_ID)));
assertEquals(originalNumber,
c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_ORIGINAL_NUMBER)));
assertEquals(e164Number,
c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_E164_NUMBER)));
}
}
private String getEmergencyNumberFromSystemPropertiesOrDefault() {
String systemEmergencyNumbers = SystemProperties.get("ril.ecclist");
if (systemEmergencyNumbers == null) {
return "911";
} else {
return systemEmergencyNumbers.split(",")[0];
}
}
}