1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 package com.android.providers.blockednumber;
17 
18 import static org.mockito.Matchers.anyInt;
19 import static org.mockito.Matchers.anyString;
20 import static org.mockito.Matchers.eq;
21 import static org.mockito.Mockito.doReturn;
22 import static org.mockito.Mockito.reset;
23 import static org.mockito.Mockito.spy;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.app.AppOpsManager;
29 import android.content.ContentResolver;
30 import android.content.ContentUris;
31 import android.content.ContentValues;
32 import android.content.pm.PackageManager;
33 import android.database.ContentObserver;
34 import android.database.Cursor;
35 import android.database.sqlite.SQLiteException;
36 import android.location.Country;
37 import android.net.Uri;
38 import android.os.Bundle;
39 import android.os.PersistableBundle;
40 import android.os.SystemProperties;
41 import android.provider.BlockedNumberContract;
42 import android.provider.BlockedNumberContract.BlockedNumbers;
43 import android.provider.BlockedNumberContract.SystemContract;
44 import android.telecom.TelecomManager;
45 import android.telephony.CarrierConfigManager;
46 import android.telephony.TelephonyManager;
47 import android.test.AndroidTestCase;
48 import android.test.MoreAsserts;
49 import android.test.suitebuilder.annotation.MediumTest;
50 
51 import junit.framework.Assert;
52 
53 import java.util.concurrent.CountDownLatch;
54 import java.util.concurrent.TimeUnit;
55 
56 /**
57  * runtest --path packages/providers/BlockedNumberProvider/tests
58  */
59 @MediumTest
60 public class BlockedNumberProviderTest extends AndroidTestCase {
61     private MyMockContext mMockContext;
62     private ContentResolver mResolver;
63 
64     @Override
setUp()65     protected void setUp() throws Exception {
66         super.setUp();
67         BlockedNumberProvider.ALLOW_SELF_CALL = false;
68 
69         mMockContext = spy(new MyMockContext(getContext()));
70         mMockContext.initializeContext();
71         mResolver = mMockContext.getContentResolver();
72 
73         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(true);
74         when(mMockContext.mCountryDetector.detectCountry())
75                 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_LOCATION));
76         when(mMockContext.mAppOpsManager.noteOp(
77                 eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
78                 .thenReturn(AppOpsManager.MODE_ERRORED);
79     }
80 
81     @Override
tearDown()82     protected void tearDown() throws Exception {
83         mMockContext.shutdown();
84 
85         super.tearDown();
86     }
87 
cv(Object... namesAndValues)88     private static ContentValues cv(Object... namesAndValues) {
89         Assert.assertTrue((namesAndValues.length % 2) == 0);
90 
91         final ContentValues ret = new ContentValues();
92         for (int i = 1; i < namesAndValues.length; i += 2) {
93             final String name = namesAndValues[i - 1].toString();
94             final Object value = namesAndValues[i];
95             if (value == null) {
96                 ret.putNull(name);
97             } else if (value instanceof String) {
98                 ret.put(name, (String) value);
99             } else if (value instanceof Integer) {
100                 ret.put(name, (Integer) value);
101             } else if (value instanceof Long) {
102                 ret.put(name, (Long) value);
103             } else {
104                 Assert.fail("Unsupported type: " + value.getClass().getSimpleName());
105             }
106         }
107         return ret;
108     }
109 
assertRowCount(int count, Uri uri)110     private void assertRowCount(int count, Uri uri) {
111         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
112             assertEquals(count, c.getCount());
113         }
114     }
115 
testGetType()116     public void testGetType() {
117         assertEquals(BlockedNumbers.CONTENT_TYPE, mResolver.getType(
118                 BlockedNumbers.CONTENT_URI));
119 
120         assertEquals(BlockedNumbers.CONTENT_ITEM_TYPE, mResolver.getType(
121                 ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, 1)));
122 
123         assertNull(mResolver.getType(
124                 Uri.withAppendedPath(BlockedNumberContract.AUTHORITY_URI, "invalid")));
125     }
126 
testInsert()127     public void testInsert() {
128         insertExpectingFailure(cv());
129         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, null));
130         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, ""));
131         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ID, 1));
132         insertExpectingFailure(cv(BlockedNumbers.COLUMN_E164_NUMBER, "1"));
133 
134         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
135         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
136         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
137         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
138         // Re-inserting the same number should be ok, but the E164 number is replaced.
139         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222",
140                 BlockedNumbers.COLUMN_E164_NUMBER, "+814084542222"));
141 
142         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-4542222"));
143 
144         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
145                 BlockedNumbers.COLUMN_E164_NUMBER, "+81453811111"));
146 
147         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "12345"));
148 
149 
150 
151         assertRowCount(7, BlockedNumbers.CONTENT_URI);
152 
153         assertContents(1, "123", "");
154         assertContents(2, "+1-2-3", "");
155         assertContents(3, "+1-408-454-1111", "+14084541111");
156         // Missing 4 due to re-insertion of the same number.
157         assertContents(5, "1-408-454-2222", "+814084542222");
158         assertContents(6, "1-408-4542222", "+14084542222");
159         assertContents(7, "045-381-1111", "+81453811111");
160         assertContents(8, "12345", "");
161     }
162 
testChangesNotified()163     public void testChangesNotified() throws Exception {
164         Cursor c = mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
165 
166         final CountDownLatch latch = new CountDownLatch(2);
167         ContentObserver contentObserver = new ContentObserver(null) {
168             @Override
169             public void onChange(boolean selfChange) {
170                 Assert.assertFalse(selfChange);
171                 latch.notify();
172             }
173         };
174         c.registerContentObserver(contentObserver);
175 
176         try {
177             Uri uri = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "14506507000"));
178             mResolver.delete(uri, null, null);
179             latch.await(10, TimeUnit.SECONDS);
180             verify(mMockContext.mBackupManager, times(2)).dataChanged();
181         } catch (Exception e) {
182             fail(e.toString());
183         } finally {
184             c.unregisterContentObserver(contentObserver);
185         }
186     }
187 
insert(ContentValues cv)188     private Uri insert(ContentValues cv) {
189         final Uri uri = mResolver.insert(BlockedNumbers.CONTENT_URI, cv);
190         assertNotNull(uri);
191 
192         // Make sure the URI exists.
193         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
194             assertEquals(1, c.getCount());
195         }
196         return uri;
197     }
198 
insertExpectingFailure(ContentValues cv)199     private void insertExpectingFailure(ContentValues cv) {
200         try {
201             mResolver.insert(
202                     BlockedNumbers.CONTENT_URI, cv);
203             fail();
204         } catch (IllegalArgumentException expected) {
205         }
206     }
207 
testDelete()208     public void testDelete() {
209         // Prepare test data
210         Uri u1 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
211         Uri u2 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
212         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
213         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
214 
215         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
216                 BlockedNumbers.COLUMN_E164_NUMBER, "12345"));
217 
218         assertRowCount(5, BlockedNumbers.CONTENT_URI);
219 
220         // Delete and check the # of remaining rows.
221 
222         mResolver.delete(u1, null, null);
223         assertRowCount(4, BlockedNumbers.CONTENT_URI);
224 
225         try {
226             mResolver.delete(u2, "1=1", null);
227             fail();
228         } catch (IllegalArgumentException expected) {
229             MoreAsserts.assertContainsRegex("selection must be null", expected.getMessage());
230         }
231 
232         mResolver.delete(u2, null, null);
233         assertRowCount(3, BlockedNumbers.CONTENT_URI);
234 
235         mResolver.delete(BlockedNumbers.CONTENT_URI,
236                 BlockedNumbers.COLUMN_E164_NUMBER + "=?",
237                 new String[]{"12345"});
238         assertRowCount(2, BlockedNumbers.CONTENT_URI);
239 
240         // SQL injection should be detected.
241         try {
242             mResolver.delete(BlockedNumbers.CONTENT_URI, "; DROP TABLE blocked; ", null);
243             fail();
244         } catch (SQLiteException expected) {
245         }
246         assertRowCount(2, BlockedNumbers.CONTENT_URI);
247 
248         mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
249         assertRowCount(0, BlockedNumbers.CONTENT_URI);
250     }
251 
testUpdate()252     public void testUpdate() {
253         try {
254             mResolver.update(BlockedNumbers.CONTENT_URI, cv(),
255                     /* selection =*/ null, /* args =*/ null);
256             fail();
257         } catch (UnsupportedOperationException expected) {
258             MoreAsserts.assertContainsRegex("Update is not supported", expected.getMessage());
259         }
260     }
261 
testBlockSuppressionAfterEmergencyContact()262     public void testBlockSuppressionAfterEmergencyContact() {
263         int blockSuppressionSeconds = 1000;
264         when(mMockContext.mCarrierConfigManager.getConfig())
265                 .thenReturn(getBundleWithInt(blockSuppressionSeconds));
266 
267         String phoneNumber = "5004541111";
268         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
269 
270         // No emergency contact: Blocks should not be suppressed.
271         assertIsBlocked(true, phoneNumber);
272         assertShouldSystemBlock(true, phoneNumber, null);
273         verifyBlocksNotSuppressed();
274         assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
275 
276         // No emergency contact yet: Ending block suppression should be a no-op.
277         SystemContract.endBlockSuppression(mMockContext);
278         assertIsBlocked(true, phoneNumber);
279         assertShouldSystemBlock(true, phoneNumber, null);
280         verifyBlocksNotSuppressed();
281         assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
282 
283         // After emergency contact blocks should be suppressed.
284         long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
285         SystemContract.notifyEmergencyContact(mMockContext);
286         assertIsBlocked(true, phoneNumber);
287         assertShouldSystemBlock(false, phoneNumber, null);
288         SystemContract.BlockSuppressionStatus status =
289                 SystemContract.getBlockSuppressionStatus(mMockContext);
290         assertTrue(status.isSuppressed);
291         assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
292                 blockSuppressionSeconds, status.untilTimestampMillis);
293         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
294         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
295                 mMockContext.mIntentsBroadcasted.get(0));
296         mMockContext.mIntentsBroadcasted.clear();
297 
298         // Ending block suppression should work.
299         SystemContract.endBlockSuppression(mMockContext);
300         assertIsBlocked(true, phoneNumber);
301         assertShouldSystemBlock(true, phoneNumber, null);
302         verifyBlocksNotSuppressed();
303         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
304         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
305                 mMockContext.mIntentsBroadcasted.get(0));
306     }
307 
testBlockSuppressionAfterEmergencyContact_invalidCarrierConfigDefaultValueUsed()308     public void testBlockSuppressionAfterEmergencyContact_invalidCarrierConfigDefaultValueUsed() {
309         int invalidBlockSuppressionSeconds = 700000; // > 1 week
310         when(mMockContext.mCarrierConfigManager.getConfig())
311                 .thenReturn(getBundleWithInt(invalidBlockSuppressionSeconds));
312 
313         String phoneNumber = "5004541111";
314         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
315 
316         long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
317         SystemContract.notifyEmergencyContact(mMockContext);
318         assertIsBlocked(true, phoneNumber);
319         assertShouldSystemBlock(false, phoneNumber, null);
320         SystemContract.BlockSuppressionStatus status =
321                 SystemContract.getBlockSuppressionStatus(mMockContext);
322         assertTrue(status.isSuppressed);
323         assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
324                 7200 /* Default value of 2 hours */, status.untilTimestampMillis);
325         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
326         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
327                 mMockContext.mIntentsBroadcasted.get(0));
328     }
329 
testEnhancedBlock()330     public void testEnhancedBlock() {
331         String phoneNumber = "5004541111";
332 
333         // Check whether block numbers not in contacts setting works well
334         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
335         assertShouldSystemBlock(true, phoneNumber,
336                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
337         assertShouldSystemBlock(false, phoneNumber,
338                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, true));
339         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, false);
340         assertShouldSystemBlock(false, phoneNumber,
341                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
342 
343         // Check whether block private number calls setting works well
344         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
345         assertShouldSystemBlock(true, phoneNumber,
346                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
347         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, false);
348         assertShouldSystemBlock(false, phoneNumber,
349                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
350 
351         // Check whether block payphone calls setting works well
352         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
353         assertShouldSystemBlock(true, phoneNumber,
354                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
355         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, false);
356         assertShouldSystemBlock(false, phoneNumber,
357                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
358 
359         // Check whether block unknown calls setting works well
360         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
361         assertShouldSystemBlock(true, phoneNumber,
362                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
363         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, false);
364         assertShouldSystemBlock(false, phoneNumber,
365                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
366     }
367 
testEnhancedBlockSuppressionAfterEmergencyContact()368     public void testEnhancedBlockSuppressionAfterEmergencyContact() {
369         String phoneNumber = "5004541111";
370 
371         int blockSuppressionSeconds = 1000;
372         when(mMockContext.mCarrierConfigManager.getConfig())
373                 .thenReturn(getBundleWithInt(blockSuppressionSeconds));
374 
375         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
376         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
377         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
378         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
379 
380         // After emergency contact blocks should be suppressed.
381         long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
382         SystemContract.notifyEmergencyContact(mMockContext);
383 
384         assertShouldSystemBlock(false, phoneNumber,
385                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
386         assertShouldSystemBlock(false, phoneNumber,
387                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
388         assertShouldSystemBlock(false, phoneNumber,
389                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
390         assertShouldSystemBlock(false, phoneNumber,
391                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
392 
393         SystemContract.BlockSuppressionStatus status =
394                 SystemContract.getBlockSuppressionStatus(mMockContext);
395         assertTrue(status.isSuppressed);
396         assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
397                 blockSuppressionSeconds, status.untilTimestampMillis);
398         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
399         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
400                 mMockContext.mIntentsBroadcasted.get(0));
401         mMockContext.mIntentsBroadcasted.clear();
402 
403         // Ending block suppression should work.
404         SystemContract.endBlockSuppression(mMockContext);
405         assertShouldSystemBlock(true, phoneNumber,
406                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false));
407         assertShouldSystemBlock(true, phoneNumber,
408                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false));
409         assertShouldSystemBlock(true, phoneNumber,
410                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false));
411         assertShouldSystemBlock(true, phoneNumber,
412                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false));
413 
414         verifyBlocksNotSuppressed();
415         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
416         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
417                 mMockContext.mIntentsBroadcasted.get(0));
418     }
419 
testRegularAppCannotAccessApis()420     public void testRegularAppCannotAccessApis() {
421         doReturn(PackageManager.PERMISSION_DENIED)
422                 .when(mMockContext).checkCallingPermission(anyString());
423 
424         try {
425             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
426             fail("SecurityException expected");
427         } catch (SecurityException expected) {
428         }
429 
430         try {
431             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
432             fail("SecurityException expected");
433         } catch (SecurityException expected) {
434         }
435 
436         try {
437             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
438             fail("SecurityException expected");
439         } catch (SecurityException expected) {
440         }
441 
442         try {
443             BlockedNumberContract.isBlocked(mMockContext, "123");
444             fail("SecurityException expected");
445         } catch (SecurityException expected) {
446         }
447 
448         try {
449             BlockedNumberContract.unblock(mMockContext, "123");
450             fail("SecurityException expected");
451         } catch (SecurityException expected) {
452         }
453 
454         try {
455             SystemContract.notifyEmergencyContact(mMockContext);
456             fail("SecurityException expected");
457         } catch (SecurityException expected) {
458         }
459 
460         try {
461             SystemContract.endBlockSuppression(mMockContext);
462             fail("SecurityException expected");
463         } catch (SecurityException expected) {
464         }
465 
466         try {
467             SystemContract.shouldSystemBlockNumber(mMockContext, "123", null);
468             fail("SecurityException expected");
469         } catch (SecurityException expected) {
470         }
471 
472         try {
473             SystemContract.getBlockSuppressionStatus(mMockContext);
474             fail("SecurityException expected");
475         } catch (SecurityException expected) {
476         }
477     }
478 
testCarrierAppCanAccessApis()479     public void testCarrierAppCanAccessApis() {
480         doReturn(PackageManager.PERMISSION_DENIED)
481                 .when(mMockContext).checkCallingPermission(anyString());
482         when(mMockContext.mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(anyString()))
483                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
484 
485         mResolver.insert(
486                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
487         assertIsBlocked(true, "123");
488 
489 
490         // Dialer check is executed twice: once for insert, and once for isBlocked.
491         verify(mMockContext.mTelephonyManager, times(2))
492                 .checkCarrierPrivilegesForPackageAnyPhone(anyString());
493     }
494 
testSelfCanAccessApis()495     public void testSelfCanAccessApis() {
496         BlockedNumberProvider.ALLOW_SELF_CALL = true;
497         doReturn(PackageManager.PERMISSION_DENIED)
498                 .when(mMockContext).checkCallingPermission(anyString());
499 
500         mResolver.insert(
501                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
502         assertIsBlocked(true, "123");
503     }
504 
testDefaultDialerCanAccessApis()505     public void testDefaultDialerCanAccessApis() {
506         doReturn(PackageManager.PERMISSION_DENIED)
507                 .when(mMockContext).checkCallingPermission(anyString());
508         when(mMockContext.mTelecomManager.getDefaultDialerPackage())
509                 .thenReturn(getContext().getPackageName());
510 
511         mResolver.insert(
512                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
513         assertIsBlocked(true, "123");
514 
515         // Dialer check is executed twice: once for insert, and once for isBlocked.
516         verify(mMockContext.mTelecomManager, times(2)).getDefaultDialerPackage();
517     }
518 
testPrivilegedAppCannotUseSystemApis()519     public void testPrivilegedAppCannotUseSystemApis() {
520         reset(mMockContext.mAppOpsManager);
521         doReturn(PackageManager.PERMISSION_DENIED)
522                 .when(mMockContext).checkCallingPermission(anyString());
523 
524         // Pretend to be the Default SMS app.
525         when(mMockContext.mAppOpsManager.noteOp(
526                 eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
527                 .thenReturn(AppOpsManager.MODE_ALLOWED);
528 
529         // Public APIs should work.
530         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
531         assertIsBlocked(true, "123");
532 
533         try {
534             SystemContract.notifyEmergencyContact(mMockContext);
535             fail("SecurityException expected");
536         } catch (SecurityException expected) {
537         }
538 
539         try {
540             SystemContract.endBlockSuppression(mMockContext);
541             fail("SecurityException expected");
542         } catch (SecurityException expected) {
543         }
544 
545         try {
546             SystemContract.shouldSystemBlockNumber(mMockContext, "123", null);
547             fail("SecurityException expected");
548         } catch (SecurityException expected) {
549         }
550 
551         try {
552             SystemContract.getBlockSuppressionStatus(mMockContext);
553             fail("SecurityException expected");
554         } catch (SecurityException expected) {
555         }
556     }
557 
testIsBlocked()558     public void testIsBlocked() {
559         assertTrue(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
560 
561         // Prepare test data
562         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
563         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1.2-3"));
564         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
565         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-500-454-2222"));
566 
567         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-111-2222",
568                 BlockedNumbers.COLUMN_E164_NUMBER, "+81451112222"));
569 
570         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
571 
572         // Check
573         assertIsBlocked(false, "");
574         assertIsBlocked(false, null);
575         assertIsBlocked(true, "123");
576         assertIsBlocked(false, "1234");
577         assertIsBlocked(true, "+81451112222");
578         assertIsBlocked(true, "+81 45 111 2222");
579         assertIsBlocked(true, "045-111-2222");
580         assertIsBlocked(false, "045 111 2222");
581 
582         assertIsBlocked(true, "500-454 1111");
583         assertIsBlocked(true, "500-454 2222");
584         assertIsBlocked(true, "+1 500-454 1111");
585         assertIsBlocked(true, "1 500-454 1111");
586 
587         assertIsBlocked(true, "abc.def@gmail.com");
588         assertIsBlocked(false, "abc.def@gmail.co");
589         assertIsBlocked(false, "bc.def@gmail.com");
590         assertIsBlocked(false, "abcdef@gmail.com");
591     }
592 
testUnblock()593     public void testUnblock() {
594         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
595         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1500-454-1111"));
596         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
597 
598         // Unblocking non-existent number is a no-op.
599         assertEquals(0, BlockedNumberContract.unblock(mMockContext, "12345"));
600 
601         // Both rows which map to the same E164 number are deleted.
602         assertEquals(2, BlockedNumberContract.unblock(mMockContext, "5004541111"));
603         assertIsBlocked(false, "1-500-454-1111");
604 
605         assertEquals(1, BlockedNumberContract.unblock(mMockContext, "abc.def@gmail.com"));
606         assertIsBlocked(false, "abc.def@gmail.com");
607     }
608 
testEmergencyNumbersAreNotBlockedBySystem()609     public void testEmergencyNumbersAreNotBlockedBySystem() {
610         String emergencyNumber = getEmergencyNumberFromSystemPropertiesOrDefault();
611         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, emergencyNumber));
612 
613         assertIsBlocked(true, emergencyNumber);
614         assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
615                 SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber, null));
616 
617         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED, true);
618         assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
619                 SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
620                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_ALLOWED, false)));
621         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE, true);
622         assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
623                 SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
624                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_RESTRICTED, false)));
625         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE, true);
626         assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
627                 SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
628                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_PAYPHONE, false)));
629         setEnhancedBlockSetting(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN, true);
630         assertEquals(BlockedNumberContract.STATUS_NOT_BLOCKED,
631                 SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber,
632                 createBundleForEnhancedBlocking(TelecomManager.PRESENTATION_UNKNOWN, false)));
633     }
634 
testPrivilegedAppAccessingApisAsSecondaryUser()635     public void testPrivilegedAppAccessingApisAsSecondaryUser() {
636         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
637 
638         assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
639 
640         try {
641             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
642             fail("SecurityException expected");
643         } catch (SecurityException expected) {
644             assertTrue(expected.getMessage().contains("current user"));
645         }
646 
647         try {
648             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
649             fail("SecurityException expected");
650         } catch (SecurityException expected) {
651         }
652 
653         try {
654             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
655             fail("SecurityException expected");
656         } catch (SecurityException expected) {
657         }
658 
659         try {
660             BlockedNumberContract.isBlocked(mMockContext, "123");
661             fail("SecurityException expected");
662         } catch (SecurityException expected) {
663         }
664 
665         try {
666             BlockedNumberContract.unblock(mMockContext, "123");
667             fail("SecurityException expected");
668         } catch (SecurityException expected) {
669         }
670     }
671 
testRegularAppAccessingApisAsSecondaryUser()672     public void testRegularAppAccessingApisAsSecondaryUser() {
673         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
674         doReturn(PackageManager.PERMISSION_DENIED)
675                 .when(mMockContext).checkCallingPermission(anyString());
676 
677         assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
678 
679         try {
680             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
681             fail("SecurityException expected");
682         } catch (SecurityException expected) {
683         }
684 
685         try {
686             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
687             fail("SecurityException expected");
688         } catch (SecurityException expected) {
689         }
690 
691         try {
692             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
693             fail("SecurityException expected");
694         } catch (SecurityException expected) {
695         }
696 
697         try {
698             BlockedNumberContract.isBlocked(mMockContext, "123");
699             fail("SecurityException expected");
700         } catch (SecurityException expected) {
701         }
702 
703         try {
704             BlockedNumberContract.unblock(mMockContext, "123");
705             fail("SecurityException expected");
706         } catch (SecurityException expected) {
707         }
708     }
709 
assertIsBlocked(boolean expected, String phoneNumber)710     private void assertIsBlocked(boolean expected, String phoneNumber) {
711         assertEquals(expected, BlockedNumberContract.isBlocked(mMockContext, phoneNumber));
712     }
713 
assertShouldSystemBlock(boolean expected, String phoneNumber, Bundle extras)714     private void assertShouldSystemBlock(boolean expected, String phoneNumber, Bundle extras) {
715         assertEquals(expected,
716                 SystemContract.shouldSystemBlockNumber(mMockContext, phoneNumber, extras)
717                         != BlockedNumberContract.STATUS_NOT_BLOCKED);
718     }
719 
setEnhancedBlockSetting(String key, boolean value)720     private void setEnhancedBlockSetting(String key, boolean value) {
721         SystemContract.setEnhancedBlockSetting(mMockContext, key, value);
722     }
723 
createBundleForEnhancedBlocking(int presentation, boolean contactExist)724     private Bundle createBundleForEnhancedBlocking(int presentation, boolean contactExist) {
725         Bundle extras = new Bundle();
726         extras.putInt(BlockedNumberContract.EXTRA_CALL_PRESENTATION, presentation);
727         extras.putBoolean(BlockedNumberContract.EXTRA_CONTACT_EXIST, contactExist);
728         return extras;
729     }
730 
getBundleWithInt(int value)731     private PersistableBundle getBundleWithInt(int value) {
732         PersistableBundle bundle = new PersistableBundle();
733         bundle.putInt(
734                 CarrierConfigManager.KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, value);
735         return bundle;
736     }
737 
verifyBlocksNotSuppressed()738     private void verifyBlocksNotSuppressed() {
739         SystemContract.BlockSuppressionStatus status =
740                 SystemContract.getBlockSuppressionStatus(mMockContext);
741         assertFalse(status.isSuppressed);
742         assertEquals(0, status.untilTimestampMillis);
743     }
744 
assertValidBlockSuppressionExpiration(long timestampMillisBeforeEmergencyContact, int blockSuppressionSeconds, long actualExpirationMillis)745     private void assertValidBlockSuppressionExpiration(long timestampMillisBeforeEmergencyContact,
746                                                        int blockSuppressionSeconds,
747                                                        long actualExpirationMillis) {
748         assertTrue(actualExpirationMillis
749                 >= timestampMillisBeforeEmergencyContact + blockSuppressionSeconds * 1000);
750         assertTrue(actualExpirationMillis < timestampMillisBeforeEmergencyContact +
751                 2 * blockSuppressionSeconds * 1000);
752     }
753 
754     private void assertContents(int rowId, String originalNumber, String e164Number) {
755         Uri uri = ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, rowId);
756         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
757             assertEquals(1, c.getCount());
758             c.moveToNext();
759             assertEquals(3, c.getColumnCount());
760             assertEquals(rowId, c.getInt(c.getColumnIndex(BlockedNumbers.COLUMN_ID)));
761             assertEquals(originalNumber,
762                     c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_ORIGINAL_NUMBER)));
763             assertEquals(e164Number,
764                     c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_E164_NUMBER)));
765         }
766     }
767 
768     private String getEmergencyNumberFromSystemPropertiesOrDefault() {
769         String systemEmergencyNumbers = SystemProperties.get("ril.ecclist");
770         if (systemEmergencyNumbers == null) {
771             return "911";
772         } else {
773             return systemEmergencyNumbers.split(",")[0];
774         }
775     }
776 }
777