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