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