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.PersistableBundle;
39 import android.os.SystemProperties;
40 import android.provider.BlockedNumberContract;
41 import android.provider.BlockedNumberContract.BlockedNumbers;
42 import android.provider.BlockedNumberContract.SystemContract;
43 import android.telephony.CarrierConfigManager;
44 import android.telephony.TelephonyManager;
45 import android.test.AndroidTestCase;
46 import android.test.MoreAsserts;
47 import android.test.suitebuilder.annotation.MediumTest;
48 
49 import junit.framework.Assert;
50 
51 import java.util.concurrent.CountDownLatch;
52 import java.util.concurrent.TimeUnit;
53 
54 /**
55  * runtest --path packages/providers/BlockedNumberProvider/tests
56  */
57 @MediumTest
58 public class BlockedNumberProviderTest extends AndroidTestCase {
59     private MyMockContext mMockContext;
60     private ContentResolver mResolver;
61 
62     @Override
setUp()63     protected void setUp() throws Exception {
64         super.setUp();
65         BlockedNumberProvider.ALLOW_SELF_CALL = false;
66 
67         mMockContext = spy(new MyMockContext(getContext()));
68         mMockContext.initializeContext();
69         mResolver = mMockContext.getContentResolver();
70 
71         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(true);
72         when(mMockContext.mCountryDetector.detectCountry())
73                 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_LOCATION));
74         when(mMockContext.mAppOpsManager.noteOp(
75                 eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
76                 .thenReturn(AppOpsManager.MODE_ERRORED);
77     }
78 
79     @Override
tearDown()80     protected void tearDown() throws Exception {
81         mMockContext.shutdown();
82 
83         super.tearDown();
84     }
85 
cv(Object... namesAndValues)86     private static ContentValues cv(Object... namesAndValues) {
87         Assert.assertTrue((namesAndValues.length % 2) == 0);
88 
89         final ContentValues ret = new ContentValues();
90         for (int i = 1; i < namesAndValues.length; i += 2) {
91             final String name = namesAndValues[i - 1].toString();
92             final Object value = namesAndValues[i];
93             if (value == null) {
94                 ret.putNull(name);
95             } else if (value instanceof String) {
96                 ret.put(name, (String) value);
97             } else if (value instanceof Integer) {
98                 ret.put(name, (Integer) value);
99             } else if (value instanceof Long) {
100                 ret.put(name, (Long) value);
101             } else {
102                 Assert.fail("Unsupported type: " + value.getClass().getSimpleName());
103             }
104         }
105         return ret;
106     }
107 
assertRowCount(int count, Uri uri)108     private void assertRowCount(int count, Uri uri) {
109         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
110             assertEquals(count, c.getCount());
111         }
112     }
113 
testGetType()114     public void testGetType() {
115         assertEquals(BlockedNumbers.CONTENT_TYPE, mResolver.getType(
116                 BlockedNumbers.CONTENT_URI));
117 
118         assertEquals(BlockedNumbers.CONTENT_ITEM_TYPE, mResolver.getType(
119                 ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, 1)));
120 
121         assertNull(mResolver.getType(
122                 Uri.withAppendedPath(BlockedNumberContract.AUTHORITY_URI, "invalid")));
123     }
124 
testInsert()125     public void testInsert() {
126         insertExpectingFailure(cv());
127         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, null));
128         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, ""));
129         insertExpectingFailure(cv(BlockedNumbers.COLUMN_ID, 1));
130         insertExpectingFailure(cv(BlockedNumbers.COLUMN_E164_NUMBER, "1"));
131 
132         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
133         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
134         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
135         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
136         // Re-inserting the same number should be ok, but the E164 number is replaced.
137         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222",
138                 BlockedNumbers.COLUMN_E164_NUMBER, "+814084542222"));
139 
140         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-4542222"));
141 
142         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
143                 BlockedNumbers.COLUMN_E164_NUMBER, "+81453811111"));
144 
145         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "12345"));
146 
147 
148 
149         assertRowCount(7, BlockedNumbers.CONTENT_URI);
150 
151         assertContents(1, "123", "");
152         assertContents(2, "+1-2-3", "");
153         assertContents(3, "+1-408-454-1111", "+14084541111");
154         // Missing 4 due to re-insertion of the same number.
155         assertContents(5, "1-408-454-2222", "+814084542222");
156         assertContents(6, "1-408-4542222", "+14084542222");
157         assertContents(7, "045-381-1111", "+81453811111");
158         assertContents(8, "12345", "");
159     }
160 
testChangesNotified()161     public void testChangesNotified() throws Exception {
162         Cursor c = mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
163 
164         final CountDownLatch latch = new CountDownLatch(2);
165         ContentObserver contentObserver = new ContentObserver(null) {
166             @Override
167             public void onChange(boolean selfChange) {
168                 Assert.assertFalse(selfChange);
169                 latch.notify();
170             }
171         };
172         c.registerContentObserver(contentObserver);
173 
174         try {
175             Uri uri = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "14506507000"));
176             mResolver.delete(uri, null, null);
177             latch.await(10, TimeUnit.SECONDS);
178             verify(mMockContext.mBackupManager, times(2)).dataChanged();
179         } catch (Exception e) {
180             fail(e.toString());
181         } finally {
182             c.unregisterContentObserver(contentObserver);
183         }
184     }
185 
insert(ContentValues cv)186     private Uri insert(ContentValues cv) {
187         final Uri uri = mResolver.insert(BlockedNumbers.CONTENT_URI, cv);
188         assertNotNull(uri);
189 
190         // Make sure the URI exists.
191         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
192             assertEquals(1, c.getCount());
193         }
194         return uri;
195     }
196 
insertExpectingFailure(ContentValues cv)197     private void insertExpectingFailure(ContentValues cv) {
198         try {
199             mResolver.insert(
200                     BlockedNumbers.CONTENT_URI, cv);
201             fail();
202         } catch (IllegalArgumentException expected) {
203         }
204     }
205 
testDelete()206     public void testDelete() {
207         // Prepare test data
208         Uri u1 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
209         Uri u2 = insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-2-3"));
210         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-408-454-1111"));
211         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-408-454-2222"));
212 
213         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-381-1111",
214                 BlockedNumbers.COLUMN_E164_NUMBER, "12345"));
215 
216         assertRowCount(5, BlockedNumbers.CONTENT_URI);
217 
218         // Delete and check the # of remaining rows.
219 
220         mResolver.delete(u1, null, null);
221         assertRowCount(4, BlockedNumbers.CONTENT_URI);
222 
223         try {
224             mResolver.delete(u2, "1=1", null);
225             fail();
226         } catch (IllegalArgumentException expected) {
227             MoreAsserts.assertContainsRegex("selection must be null", expected.getMessage());
228         }
229 
230         mResolver.delete(u2, null, null);
231         assertRowCount(3, BlockedNumbers.CONTENT_URI);
232 
233         mResolver.delete(BlockedNumbers.CONTENT_URI,
234                 BlockedNumbers.COLUMN_E164_NUMBER + "=?",
235                 new String[]{"12345"});
236         assertRowCount(2, BlockedNumbers.CONTENT_URI);
237 
238         // SQL injection should be detected.
239         try {
240             mResolver.delete(BlockedNumbers.CONTENT_URI, "; DROP TABLE blocked; ", null);
241             fail();
242         } catch (SQLiteException expected) {
243         }
244         assertRowCount(2, BlockedNumbers.CONTENT_URI);
245 
246         mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
247         assertRowCount(0, BlockedNumbers.CONTENT_URI);
248     }
249 
testUpdate()250     public void testUpdate() {
251         try {
252             mResolver.update(BlockedNumbers.CONTENT_URI, cv(),
253                     /* selection =*/ null, /* args =*/ null);
254             fail();
255         } catch (UnsupportedOperationException expected) {
256             MoreAsserts.assertContainsRegex("Update is not supported", expected.getMessage());
257         }
258     }
259 
testBlockSuppressionAfterEmergencyContact()260     public void testBlockSuppressionAfterEmergencyContact() {
261         int blockSuppressionSeconds = 1000;
262         when(mMockContext.mCarrierConfigManager.getConfig())
263                 .thenReturn(getBundleWithInt(blockSuppressionSeconds));
264 
265         String phoneNumber = "5004541111";
266         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
267 
268         // No emergency contact: Blocks should not be suppressed.
269         assertIsBlocked(true, phoneNumber);
270         assertShouldSystemBlock(true, phoneNumber);
271         verifyBlocksNotSuppressed();
272         assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
273 
274         // No emergency contact yet: Ending block suppression should be a no-op.
275         SystemContract.endBlockSuppression(mMockContext);
276         assertIsBlocked(true, phoneNumber);
277         assertShouldSystemBlock(true, phoneNumber);
278         verifyBlocksNotSuppressed();
279         assertTrue(mMockContext.mIntentsBroadcasted.isEmpty());
280 
281         // After emergency contact blocks should be suppressed.
282         long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
283         SystemContract.notifyEmergencyContact(mMockContext);
284         assertIsBlocked(true, phoneNumber);
285         assertShouldSystemBlock(false, phoneNumber);
286         SystemContract.BlockSuppressionStatus status =
287                 SystemContract.getBlockSuppressionStatus(mMockContext);
288         assertTrue(status.isSuppressed);
289         assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
290                 blockSuppressionSeconds, status.untilTimestampMillis);
291         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
292         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
293                 mMockContext.mIntentsBroadcasted.get(0));
294         mMockContext.mIntentsBroadcasted.clear();
295 
296         // Ending block suppression should work.
297         SystemContract.endBlockSuppression(mMockContext);
298         assertIsBlocked(true, phoneNumber);
299         assertShouldSystemBlock(true, phoneNumber);
300         verifyBlocksNotSuppressed();
301         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
302         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
303                 mMockContext.mIntentsBroadcasted.get(0));
304     }
305 
testBlockSuppressionAfterEmergencyContact_invalidCarrierConfigDefaultValueUsed()306     public void testBlockSuppressionAfterEmergencyContact_invalidCarrierConfigDefaultValueUsed() {
307         int invalidBlockSuppressionSeconds = 700000; // > 1 week
308         when(mMockContext.mCarrierConfigManager.getConfig())
309                 .thenReturn(getBundleWithInt(invalidBlockSuppressionSeconds));
310 
311         String phoneNumber = "5004541111";
312         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber));
313 
314         long timestampMillisBeforeEmergencyContact = System.currentTimeMillis();
315         SystemContract.notifyEmergencyContact(mMockContext);
316         assertIsBlocked(true, phoneNumber);
317         assertShouldSystemBlock(false, phoneNumber);
318         SystemContract.BlockSuppressionStatus status =
319                 SystemContract.getBlockSuppressionStatus(mMockContext);
320         assertTrue(status.isSuppressed);
321         assertValidBlockSuppressionExpiration(timestampMillisBeforeEmergencyContact,
322                 7200 /* Default value of 2 hours */, status.untilTimestampMillis);
323         assertEquals(1, mMockContext.mIntentsBroadcasted.size());
324         assertEquals(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED,
325                 mMockContext.mIntentsBroadcasted.get(0));
326     }
327 
testRegularAppCannotAccessApis()328     public void testRegularAppCannotAccessApis() {
329         doReturn(PackageManager.PERMISSION_DENIED)
330                 .when(mMockContext).checkCallingPermission(anyString());
331 
332         try {
333             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
334             fail("SecurityException expected");
335         } catch (SecurityException expected) {
336         }
337 
338         try {
339             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
340             fail("SecurityException expected");
341         } catch (SecurityException expected) {
342         }
343 
344         try {
345             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
346             fail("SecurityException expected");
347         } catch (SecurityException expected) {
348         }
349 
350         try {
351             BlockedNumberContract.isBlocked(mMockContext, "123");
352             fail("SecurityException expected");
353         } catch (SecurityException expected) {
354         }
355 
356         try {
357             BlockedNumberContract.unblock(mMockContext, "123");
358             fail("SecurityException expected");
359         } catch (SecurityException expected) {
360         }
361 
362         try {
363             SystemContract.notifyEmergencyContact(mMockContext);
364             fail("SecurityException expected");
365         } catch (SecurityException expected) {
366         }
367 
368         try {
369             SystemContract.endBlockSuppression(mMockContext);
370             fail("SecurityException expected");
371         } catch (SecurityException expected) {
372         }
373 
374         try {
375             SystemContract.shouldSystemBlockNumber(mMockContext, "123");
376             fail("SecurityException expected");
377         } catch (SecurityException expected) {
378         }
379 
380         try {
381             SystemContract.getBlockSuppressionStatus(mMockContext);
382             fail("SecurityException expected");
383         } catch (SecurityException expected) {
384         }
385     }
386 
testCarrierAppCanAccessApis()387     public void testCarrierAppCanAccessApis() {
388         doReturn(PackageManager.PERMISSION_DENIED)
389                 .when(mMockContext).checkCallingPermission(anyString());
390         when(mMockContext.mTelephonyManager.checkCarrierPrivilegesForPackage(anyString()))
391                 .thenReturn(TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS);
392 
393         mResolver.insert(
394                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
395         assertIsBlocked(true, "123");
396 
397 
398         // Dialer check is executed twice: once for insert, and once for isBlocked.
399         verify(mMockContext.mTelephonyManager, times(2))
400                 .checkCarrierPrivilegesForPackage(anyString());
401     }
402 
testSelfCanAccessApis()403     public void testSelfCanAccessApis() {
404         BlockedNumberProvider.ALLOW_SELF_CALL = true;
405         doReturn(PackageManager.PERMISSION_DENIED)
406                 .when(mMockContext).checkCallingPermission(anyString());
407 
408         mResolver.insert(
409                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
410         assertIsBlocked(true, "123");
411     }
412 
testDefaultDialerCanAccessApis()413     public void testDefaultDialerCanAccessApis() {
414         doReturn(PackageManager.PERMISSION_DENIED)
415                 .when(mMockContext).checkCallingPermission(anyString());
416         when(mMockContext.mTelecomManager.getDefaultDialerPackage())
417                 .thenReturn(getContext().getPackageName());
418 
419         mResolver.insert(
420                 BlockedNumbers.CONTENT_URI, cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
421         assertIsBlocked(true, "123");
422 
423         // Dialer check is executed twice: once for insert, and once for isBlocked.
424         verify(mMockContext.mTelecomManager, times(2)).getDefaultDialerPackage();
425     }
426 
testPrivilegedAppCannotUseSystemApis()427     public void testPrivilegedAppCannotUseSystemApis() {
428         reset(mMockContext.mAppOpsManager);
429         doReturn(PackageManager.PERMISSION_DENIED)
430                 .when(mMockContext).checkCallingPermission(anyString());
431 
432         // Pretend to be the Default SMS app.
433         when(mMockContext.mAppOpsManager.noteOp(
434                 eq(AppOpsManager.OP_WRITE_SMS), anyInt(), anyString()))
435                 .thenReturn(AppOpsManager.MODE_ALLOWED);
436 
437         // Public APIs should work.
438         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
439         assertIsBlocked(true, "123");
440 
441         try {
442             SystemContract.notifyEmergencyContact(mMockContext);
443             fail("SecurityException expected");
444         } catch (SecurityException expected) {
445         }
446 
447         try {
448             SystemContract.endBlockSuppression(mMockContext);
449             fail("SecurityException expected");
450         } catch (SecurityException expected) {
451         }
452 
453         try {
454             SystemContract.shouldSystemBlockNumber(mMockContext, "123");
455             fail("SecurityException expected");
456         } catch (SecurityException expected) {
457         }
458 
459         try {
460             SystemContract.getBlockSuppressionStatus(mMockContext);
461             fail("SecurityException expected");
462         } catch (SecurityException expected) {
463         }
464     }
465 
testIsBlocked()466     public void testIsBlocked() {
467         assertTrue(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
468 
469         // Prepare test data
470         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
471         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1.2-3"));
472         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
473         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1-500-454-2222"));
474 
475         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "045-111-2222",
476                 BlockedNumbers.COLUMN_E164_NUMBER, "+81451112222"));
477 
478         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
479 
480         // Check
481         assertIsBlocked(false, "");
482         assertIsBlocked(false, null);
483         assertIsBlocked(true, "123");
484         assertIsBlocked(false, "1234");
485         assertIsBlocked(true, "+81451112222");
486         assertIsBlocked(true, "+81 45 111 2222");
487         assertIsBlocked(true, "045-111-2222");
488         assertIsBlocked(false, "045 111 2222");
489 
490         assertIsBlocked(true, "500-454 1111");
491         assertIsBlocked(true, "500-454 2222");
492         assertIsBlocked(true, "+1 500-454 1111");
493         assertIsBlocked(true, "1 500-454 1111");
494 
495         assertIsBlocked(true, "abc.def@gmail.com");
496         assertIsBlocked(false, "abc.def@gmail.co");
497         assertIsBlocked(false, "bc.def@gmail.com");
498         assertIsBlocked(false, "abcdef@gmail.com");
499     }
500 
testUnblock()501     public void testUnblock() {
502         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "+1-500-454-1111"));
503         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1500-454-1111"));
504         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "abc.def@gmail.com"));
505 
506         // Unblocking non-existent number is a no-op.
507         assertEquals(0, BlockedNumberContract.unblock(mMockContext, "12345"));
508 
509         // Both rows which map to the same E164 number are deleted.
510         assertEquals(2, BlockedNumberContract.unblock(mMockContext, "5004541111"));
511         assertIsBlocked(false, "1-500-454-1111");
512 
513         assertEquals(1, BlockedNumberContract.unblock(mMockContext, "abc.def@gmail.com"));
514         assertIsBlocked(false, "abc.def@gmail.com");
515     }
516 
testEmergencyNumbersAreNotBlockedBySystem()517     public void testEmergencyNumbersAreNotBlockedBySystem() {
518         String emergencyNumber = getEmergencyNumberFromSystemPropertiesOrDefault();
519         insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, emergencyNumber));
520 
521         assertIsBlocked(true, emergencyNumber);
522         assertFalse(SystemContract.shouldSystemBlockNumber(mMockContext, emergencyNumber));
523     }
524 
testPrivilegedAppAccessingApisAsSecondaryUser()525     public void testPrivilegedAppAccessingApisAsSecondaryUser() {
526         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
527 
528         assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
529 
530         try {
531             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
532             fail("SecurityException expected");
533         } catch (SecurityException expected) {
534             assertTrue(expected.getMessage().contains("current user"));
535         }
536 
537         try {
538             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
539             fail("SecurityException expected");
540         } catch (SecurityException expected) {
541         }
542 
543         try {
544             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
545             fail("SecurityException expected");
546         } catch (SecurityException expected) {
547         }
548 
549         try {
550             BlockedNumberContract.isBlocked(mMockContext, "123");
551             fail("SecurityException expected");
552         } catch (SecurityException expected) {
553         }
554 
555         try {
556             BlockedNumberContract.unblock(mMockContext, "123");
557             fail("SecurityException expected");
558         } catch (SecurityException expected) {
559         }
560     }
561 
testRegularAppAccessingApisAsSecondaryUser()562     public void testRegularAppAccessingApisAsSecondaryUser() {
563         when(mMockContext.mUserManager.isPrimaryUser()).thenReturn(false);
564         doReturn(PackageManager.PERMISSION_DENIED)
565                 .when(mMockContext).checkCallingPermission(anyString());
566 
567         assertFalse(BlockedNumberContract.canCurrentUserBlockNumbers(mMockContext));
568 
569         try {
570             insert(cv(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "123"));
571             fail("SecurityException expected");
572         } catch (SecurityException expected) {
573         }
574 
575         try {
576             mResolver.query(BlockedNumbers.CONTENT_URI, null, null, null, null);
577             fail("SecurityException expected");
578         } catch (SecurityException expected) {
579         }
580 
581         try {
582             mResolver.delete(BlockedNumbers.CONTENT_URI, null, null);
583             fail("SecurityException expected");
584         } catch (SecurityException expected) {
585         }
586 
587         try {
588             BlockedNumberContract.isBlocked(mMockContext, "123");
589             fail("SecurityException expected");
590         } catch (SecurityException expected) {
591         }
592 
593         try {
594             BlockedNumberContract.unblock(mMockContext, "123");
595             fail("SecurityException expected");
596         } catch (SecurityException expected) {
597         }
598     }
599 
assertIsBlocked(boolean expected, String phoneNumber)600     private void assertIsBlocked(boolean expected, String phoneNumber) {
601         assertEquals(expected, BlockedNumberContract.isBlocked(mMockContext, phoneNumber));
602     }
603 
assertShouldSystemBlock(boolean expected, String phoneNumber)604     private void assertShouldSystemBlock(boolean expected, String phoneNumber) {
605         assertEquals(expected, SystemContract.shouldSystemBlockNumber(mMockContext, phoneNumber));
606     }
607 
getBundleWithInt(int value)608     private PersistableBundle getBundleWithInt(int value) {
609         PersistableBundle bundle = new PersistableBundle();
610         bundle.putInt(
611                 CarrierConfigManager.KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT, value);
612         return bundle;
613     }
614 
verifyBlocksNotSuppressed()615     private void verifyBlocksNotSuppressed() {
616         SystemContract.BlockSuppressionStatus status =
617                 SystemContract.getBlockSuppressionStatus(mMockContext);
618         assertFalse(status.isSuppressed);
619         assertEquals(0, status.untilTimestampMillis);
620     }
621 
assertValidBlockSuppressionExpiration(long timestampMillisBeforeEmergencyContact, int blockSuppressionSeconds, long actualExpirationMillis)622     private void assertValidBlockSuppressionExpiration(long timestampMillisBeforeEmergencyContact,
623                                                        int blockSuppressionSeconds,
624                                                        long actualExpirationMillis) {
625         assertTrue(actualExpirationMillis
626                 >= timestampMillisBeforeEmergencyContact + blockSuppressionSeconds * 1000);
627         assertTrue(actualExpirationMillis < timestampMillisBeforeEmergencyContact +
628                 2 * blockSuppressionSeconds * 1000);
629     }
630 
631     private void assertContents(int rowId, String originalNumber, String e164Number) {
632         Uri uri = ContentUris.withAppendedId(BlockedNumbers.CONTENT_URI, rowId);
633         try (Cursor c = mResolver.query(uri, null, null, null, null)) {
634             assertEquals(1, c.getCount());
635             c.moveToNext();
636             assertEquals(3, c.getColumnCount());
637             assertEquals(rowId, c.getInt(c.getColumnIndex(BlockedNumbers.COLUMN_ID)));
638             assertEquals(originalNumber,
639                     c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_ORIGINAL_NUMBER)));
640             assertEquals(e164Number,
641                     c.getString(c.getColumnIndex(BlockedNumbers.COLUMN_E164_NUMBER)));
642         }
643     }
644 
645     private String getEmergencyNumberFromSystemPropertiesOrDefault() {
646         String systemEmergencyNumbers = SystemProperties.get("ril.ecclist");
647         if (systemEmergencyNumbers == null) {
648             return "911";
649         } else {
650             return systemEmergencyNumbers.split(",")[0];
651         }
652     }
653 }
654