1 /*
2  * Copyright (C) 2015 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 
17 package com.android.cts.usepermission;
18 
19 import static junit.framework.Assert.assertEquals;
20 
21 import static org.junit.Assert.fail;
22 
23 import android.Manifest;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.pm.PackageManager;
27 import android.database.Cursor;
28 import android.net.Uri;
29 import android.os.Build;
30 import android.provider.CalendarContract;
31 
32 import androidx.test.InstrumentationRegistry;
33 
34 import org.junit.Before;
35 import org.junit.Test;
36 
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 
40 /**
41  * Runtime permission behavior tests for apps targeting API 23
42  */
43 public class UsePermissionTest23 extends BasePermissionsTest {
44     private static final int REQUEST_CODE_PERMISSIONS = 42;
45 
46     private final Context mContext = getInstrumentation().getContext();
47 
48     private boolean mLeanback;
49     private boolean mWatch;
50 
51     @Before
initialize()52     public void initialize() {
53         PackageManager pm = getInstrumentation().getContext().getPackageManager();
54         mLeanback = pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
55         mWatch = pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
56     }
57 
58     @Test
testFail()59     public void testFail() throws Exception {
60         fail("Expected");
61     }
62 
63     @Test
testKill()64     public void testKill() throws Exception {
65         android.os.Process.killProcess(android.os.Process.myPid());
66     }
67 
68     @Test
testDefault()69     public void testDefault() throws Exception {
70         // New permission model is denied by default
71         assertAllPermissionsRevoked();
72     }
73 
74     @Test
testGranted()75     public void testGranted() throws Exception {
76         grantPermission(Manifest.permission.READ_CALENDAR);
77 
78         // Read/write access should be allowed
79         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
80                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
81         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
82                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
83         final Uri uri = insertCalendarItem();
84         try (Cursor c = mContext.getContentResolver().query(uri, null, null, null)) {
85             assertEquals(1, c.getCount());
86         }
87     }
88 
89     @Test
testInteractiveGrant()90     public void testInteractiveGrant() throws Exception {
91         // Start out without permission
92         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
93                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
94         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
95                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
96         try {
97             insertCalendarItem();
98             fail();
99         } catch (SecurityException expected) {
100         }
101         try (Cursor c = mContext.getContentResolver().query(
102                 CalendarContract.Calendars.CONTENT_URI, null, null, null)) {
103             fail();
104         } catch (SecurityException expected) {
105         }
106 
107         // Go through normal grant flow
108         BasePermissionActivity.Result result = requestPermissions(new String[] {
109                 Manifest.permission.READ_CALENDAR,
110                 Manifest.permission.WRITE_CALENDAR},
111                 REQUEST_CODE_PERMISSIONS,
112                 BasePermissionActivity.class,
113                 () -> {
114                     try {
115                         clickAllowButton();
116                         getUiDevice().waitForIdle();
117                     } catch (Exception e) {
118                         throw new RuntimeException(e);
119                     }
120                 });
121 
122         assertEquals(REQUEST_CODE_PERMISSIONS, result.requestCode);
123         assertEquals(Manifest.permission.READ_CALENDAR, result.permissions[0]);
124         assertEquals(Manifest.permission.WRITE_CALENDAR, result.permissions[1]);
125         assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[0]);
126         assertEquals(PackageManager.PERMISSION_GRANTED, result.grantResults[1]);
127 
128         // We should have permission now!
129         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
130                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
131         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
132                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
133         final Uri uri = insertCalendarItem();
134         try (Cursor c = mContext.getContentResolver().query(uri, null, null, null)) {
135             assertEquals(1, c.getCount());
136         }
137     }
138 
139     @Test
testRuntimeGroupGrantSpecificity()140     public void testRuntimeGroupGrantSpecificity() throws Exception {
141         // Start out without permission
142         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
143                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
144         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
145                 .checkSelfPermission(Manifest.permission.READ_CONTACTS));
146 
147         String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
148 
149         // request only one permission from the 'contacts' permission group
150         BasePermissionActivity.Result result = requestPermissions(permissions,
151                 REQUEST_CODE_PERMISSIONS,
152                 BasePermissionActivity.class,
153                 () -> {
154                     try {
155                         clickAllowButton();
156                         getUiDevice().waitForIdle();
157                     } catch (Exception e) {
158                         throw new RuntimeException(e);
159                     }
160                 });
161 
162         // Expect the permission is granted
163         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
164                 permissions, new boolean[] {true});
165 
166         // Make sure no undeclared as used permissions are granted
167         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
168                 .checkSelfPermission(Manifest.permission.READ_CONTACTS));
169     }
170 
171     @Test
testRuntimeGroupGrantExpansion()172     public void testRuntimeGroupGrantExpansion() throws Exception {
173         // Start out without permission
174         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
175                 .checkSelfPermission(Manifest.permission.RECEIVE_SMS));
176         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
177                 .checkSelfPermission(Manifest.permission.SEND_SMS));
178 
179         String[] permissions = new String[] {Manifest.permission.RECEIVE_SMS};
180 
181         // request only one permission from the 'SMS' permission group at runtime,
182         // but two from this group are <uses-permission> in the manifest
183         // request only one permission from the 'contacts' permission group
184         BasePermissionActivity.Result result = requestPermissions(permissions,
185                 REQUEST_CODE_PERMISSIONS,
186                 BasePermissionActivity.class,
187                 () -> {
188                     try {
189                         clickAllowButton();
190                         getUiDevice().waitForIdle();
191                     } catch (Exception e) {
192                         throw new RuntimeException(e);
193                     }
194                 });
195 
196         // Expect the permission is granted
197         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
198                 permissions, new boolean[] {true});
199 
200         // We should now have been granted both of the permissions from this group.
201         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
202                 .checkSelfPermission(Manifest.permission.SEND_SMS));
203     }
204 
205     @Test
testCancelledPermissionRequest()206     public void testCancelledPermissionRequest() throws Exception {
207         // Make sure we don't have the permission
208         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
209                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
210 
211         String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
212 
213         // Request the permission and cancel the request
214         BasePermissionActivity.Result result = requestPermissions(permissions,
215                 REQUEST_CODE_PERMISSIONS,
216                 BasePermissionActivity.class,
217                 () -> {
218                     try {
219                         clickDenyButton();
220                         getUiDevice().waitForIdle();
221                     } catch (Exception e) {
222                         throw new RuntimeException(e);
223                     }
224                 });
225 
226         // Expect the permission is not granted
227         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
228                 permissions, new boolean[] {false});
229     }
230 
231     @Test
testRequestGrantedPermission()232     public void testRequestGrantedPermission() throws Exception {
233         // Make sure we don't have the permission
234         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
235                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
236 
237         String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
238 
239         // Request the permission and allow it
240         BasePermissionActivity.Result firstResult = requestPermissions(permissions,
241                 REQUEST_CODE_PERMISSIONS,
242                 BasePermissionActivity.class, () -> {
243                     try {
244                         clickAllowButton();
245                         getUiDevice().waitForIdle();
246                     } catch (Exception e) {
247                         throw new RuntimeException(e);
248                     }
249                 });
250 
251         // Expect the permission is granted
252         assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
253                 permissions, new boolean[] {true});
254 
255         // Request the permission and do nothing
256         BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
257                 Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
258                 BasePermissionActivity.class, null);
259 
260         // Expect the permission is granted
261         assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
262                 permissions, new boolean[] {true});
263     }
264 
265     @Test
testDenialWithPrejudice()266     public void testDenialWithPrejudice() throws Exception {
267         // Make sure we don't have the permission
268         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
269                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
270 
271         String[] permissions = new String[] {Manifest.permission.WRITE_CONTACTS};
272 
273         // Request the permission and deny it
274         BasePermissionActivity.Result firstResult = requestPermissions(
275                 permissions, REQUEST_CODE_PERMISSIONS,
276                 BasePermissionActivity.class, () -> {
277                     try {
278                         clickDenyButton();
279                         getUiDevice().waitForIdle();
280                     } catch (Exception e) {
281                         throw new RuntimeException(e);
282                     }
283                 });
284 
285         // Expect the permission is not granted
286         assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
287                 permissions, new boolean[] {false});
288 
289         // Request the permission and choose don't ask again
290         BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
291                         Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 1,
292                 BasePermissionActivity.class, () -> {
293                     try {
294                         denyWithPrejudice();
295                         getUiDevice().waitForIdle();
296                     } catch (Exception e) {
297                         throw new RuntimeException(e);
298                     }
299                 });
300 
301         // Expect the permission is not granted
302         assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
303                 permissions, new boolean[] {false});
304 
305         // Request the permission and do nothing
306         BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
307                         Manifest.permission.WRITE_CONTACTS}, REQUEST_CODE_PERMISSIONS + 2,
308                 BasePermissionActivity.class, null);
309 
310         // Expect the permission is not granted
311         assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
312                 permissions, new boolean[] {false});
313     }
314 
315     @Test
testRevokeAffectsWholeGroup_part1()316     public void testRevokeAffectsWholeGroup_part1() throws Exception {
317         // Grant the group
318         grantPermission(Manifest.permission.READ_CALENDAR);
319 
320         // Make sure we have the permissions
321         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
322                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
323         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
324                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
325 
326         // Revoke the group
327         revokePermission(Manifest.permission.READ_CALENDAR);
328 
329         // We just committed a suicide by revoking the permission. See part2 below...
330     }
331 
332     @Test
testRevokeAffectsWholeGroup_part2()333     public void testRevokeAffectsWholeGroup_part2() throws Exception {
334         // Make sure we don't have the permissions
335         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
336                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
337         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
338                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
339     }
340 
341     @Test
testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1()342     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1() throws Exception {
343         // Make sure we don't have the permission
344         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
345                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
346 
347         String[] permissions = new String[] {Manifest.permission.READ_CALENDAR};
348 
349         // Request the permission and deny it
350         BasePermissionActivity.Result firstResult = requestPermissions(
351                 permissions, REQUEST_CODE_PERMISSIONS,
352                 BasePermissionActivity.class, () -> {
353                     try {
354                         clickDenyButton();
355                         getUiDevice().waitForIdle();
356                     } catch (Exception e) {
357                         throw new RuntimeException(e);
358                     }
359                 });
360 
361         // Expect the permission is not granted
362         assertPermissionRequestResult(firstResult, REQUEST_CODE_PERMISSIONS,
363                 permissions, new boolean[] {false});
364 
365         // Request the permission and choose don't ask again
366         BasePermissionActivity.Result secondResult = requestPermissions(new String[] {
367                         Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 1,
368                 BasePermissionActivity.class, () -> {
369                     try {
370                         denyWithPrejudice();
371                         getUiDevice().waitForIdle();
372                     } catch (Exception e) {
373                         throw new RuntimeException(e);
374                     }
375                 });
376 
377         // Expect the permission is not granted
378         assertPermissionRequestResult(secondResult, REQUEST_CODE_PERMISSIONS + 1,
379                 permissions, new boolean[] {false});
380 
381         // Clear the denial with prejudice
382         grantPermission(Manifest.permission.READ_CALENDAR);
383         revokePermission(Manifest.permission.READ_CALENDAR);
384 
385         // We just committed a suicide by revoking the permission. See part2 below...
386     }
387 
388     @Test
testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part2()389     public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part2() throws Exception {
390         // Make sure we don't have the permission
391         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
392                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
393 
394         // Request the permission and allow it
395         BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
396                         Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS + 2,
397                 BasePermissionActivity.class, () -> {
398                     try {
399                         clickAllowButton();
400                         getUiDevice().waitForIdle();
401                     } catch (Exception e) {
402                         throw new RuntimeException(e);
403                     }
404                 });
405 
406         // Make sure the permission is granted
407         assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS + 2,
408                 new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
409     }
410 
411     @Test
testRequestNonRuntimePermission()412     public void testRequestNonRuntimePermission() throws Exception {
413         // Make sure we don't have the permission
414         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
415                 .checkSelfPermission(Manifest.permission.BIND_PRINT_SERVICE));
416 
417         String[] permissions = new String[] {Manifest.permission.BIND_PRINT_SERVICE};
418 
419         // Request the permission and do nothing
420         BasePermissionActivity.Result result = requestPermissions(permissions,
421                 REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
422 
423         // Expect the permission is not granted
424         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
425                 permissions, new boolean[] {false});
426     }
427 
428     @Test
testRequestNonExistentPermission()429     public void testRequestNonExistentPermission() throws Exception {
430         // Make sure we don't have the permission
431         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
432                 .checkSelfPermission("permission.does.not.exist"));
433 
434         String[] permissions = new String[] {"permission.does.not.exist"};
435 
436         // Request the permission and do nothing
437         BasePermissionActivity.Result result = requestPermissions(permissions,
438                 REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, null);
439 
440         // Expect the permission is not granted
441         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
442                 permissions, new boolean[] {false});
443     }
444 
445     @Test
testRequestPermissionFromTwoGroups()446     public void testRequestPermissionFromTwoGroups() throws Exception {
447         // Make sure we don't have the permissions
448         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
449                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
450         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
451                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
452 
453         String[] permissions = new String[] {
454                 Manifest.permission.WRITE_CONTACTS,
455                 Manifest.permission.WRITE_CALENDAR
456         };
457 
458         // Request the permission and allow it
459         BasePermissionActivity.Result result = requestPermissions(permissions,
460                 REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, () -> {
461             try {
462                 clickAllowButton();
463                 getUiDevice().waitForIdle();
464                 clickAllowButton();
465                 getUiDevice().waitForIdle();
466             } catch (Exception e) {
467                 throw new RuntimeException(e);
468             }
469         });
470 
471         // Expect the permission are reported as granted
472         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
473                 permissions, new boolean[] {true, true});
474 
475         // The permissions are granted
476         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
477                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
478         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
479                 .checkSelfPermission(Manifest.permission.WRITE_CALENDAR));
480 
481         // In API < N_MR1 all permissions of a group are granted. I.e. the grant was "expanded"
482         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
483                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
484 
485         // Even the contacts group was expanded, the read-calendar permission is not in the
486         // manifest, hence not granted.
487         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
488                 .checkSelfPermission(Manifest.permission.READ_CONTACTS));
489     }
490 
491     @Test
testNoResidualPermissionsOnUninstall_part1()492     public void testNoResidualPermissionsOnUninstall_part1() throws Exception {
493         ArrayList<String> perms = new ArrayList<>(Arrays.asList(
494                 Manifest.permission.WRITE_CALENDAR,
495                 Manifest.permission.WRITE_CONTACTS,
496                 Manifest.permission.READ_SMS,
497                 Manifest.permission.CALL_PHONE,
498                 Manifest.permission.RECORD_AUDIO,
499                 Manifest.permission.BODY_SENSORS,
500                 Manifest.permission.CAMERA
501         ));
502 
503         perms.add(Manifest.permission.READ_EXTERNAL_STORAGE);
504 
505         // Grant all permissions
506         grantPermissions(perms.toArray(new String[perms.size()]));
507 
508         // Don't use UI for granting location permission as this shows another dialog
509         String packageName = InstrumentationRegistry.getTargetContext().getPackageName();
510         getInstrumentation().getUiAutomation().grantRuntimePermission(packageName,
511                 Manifest.permission.ACCESS_FINE_LOCATION);
512         getInstrumentation().getUiAutomation().grantRuntimePermission(packageName,
513                 Manifest.permission.ACCESS_COARSE_LOCATION);
514         getInstrumentation().getUiAutomation().grantRuntimePermission(packageName,
515                 Manifest.permission.ACCESS_BACKGROUND_LOCATION);
516     }
517 
518     @Test
testNoResidualPermissionsOnUninstall_part2()519     public void testNoResidualPermissionsOnUninstall_part2() throws Exception {
520         // Make no permissions are granted after uninstalling and installing the app
521         assertAllPermissionsRevoked();
522     }
523 
524     @Test
testRevokePropagatedOnUpgradeOldToNewModel_part2()525     public void testRevokePropagatedOnUpgradeOldToNewModel_part2() throws Exception {
526         assertPermissionsGrantState(new String[] {Manifest.permission.WRITE_CALENDAR},
527                 PackageManager.PERMISSION_DENIED);
528     }
529 
530     @Test
testRevokePropagatedOnUpgradeNewToNewModel_part1()531     public void testRevokePropagatedOnUpgradeNewToNewModel_part1() throws Exception {
532         // Make sure we don't have the permission
533         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
534                 .checkSelfPermission(Manifest.permission.READ_CALENDAR));
535 
536         // Request the permission and allow it
537         BasePermissionActivity.Result thirdResult = requestPermissions(new String[] {
538                         Manifest.permission.READ_CALENDAR}, REQUEST_CODE_PERMISSIONS,
539                 BasePermissionActivity.class, () -> {
540                     try {
541                         clickAllowButton();
542                         getUiDevice().waitForIdle();
543                     } catch (Exception e) {
544                         throw new RuntimeException(e);
545                     }
546                 });
547 
548         // Make sure the permission is granted
549         assertPermissionRequestResult(thirdResult, REQUEST_CODE_PERMISSIONS,
550                 new String[] {Manifest.permission.READ_CALENDAR}, new boolean[] {true});
551     }
552 
553     @Test
testRevokePropagatedOnUpgradeNewToNewModel_part2()554     public void testRevokePropagatedOnUpgradeNewToNewModel_part2() throws Exception {
555         // Make sure the permission is still granted after the upgrade
556         assertPermissionsGrantState(new String[] {Manifest.permission.READ_CALENDAR},
557                 PackageManager.PERMISSION_GRANTED);
558         // Also make sure one of the not granted permissions is still not granted
559         assertPermissionsGrantState(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE},
560                 PackageManager.PERMISSION_DENIED);
561     }
562 
563     @Test
testAllPermissionsGrantedOnUpgrade()564     public void testAllPermissionsGrantedOnUpgrade() throws Exception {
565         assertAllPermissionsGrantState(PackageManager.PERMISSION_GRANTED);
566     }
567 
568     @Test
testNullPermissionRequest()569     public void testNullPermissionRequest() throws Exception {
570         String[] permissions = new String[] {null};
571 
572         // Go through normal grant flow
573         BasePermissionActivity.Result result = requestPermissions(permissions,
574                 REQUEST_CODE_PERMISSIONS,
575                 BasePermissionActivity.class,
576                 () -> { /* empty */ });
577 
578         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
579                 permissions, new boolean[] {false});
580     }
581 
582     @Test
testNullAndRealPermission()583     public void testNullAndRealPermission() throws Exception {
584         // Make sure we don't have the permissions
585         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
586                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
587         assertEquals(PackageManager.PERMISSION_DENIED, getInstrumentation().getContext()
588                 .checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));
589 
590         String[] permissions = new String[] {
591                 null,
592                 Manifest.permission.WRITE_CONTACTS,
593                 null,
594                 Manifest.permission.RECORD_AUDIO
595         };
596 
597         // Request the permission and allow it
598         BasePermissionActivity.Result result = requestPermissions(permissions,
599                 REQUEST_CODE_PERMISSIONS, BasePermissionActivity.class, () -> {
600                     try {
601                         clickAllowButton();
602                         getUiDevice().waitForIdle();
603                         clickAllowButton();
604                         getUiDevice().waitForIdle();
605                     } catch (Exception e) {
606                         throw new RuntimeException(e);
607                     }
608                 });
609 
610         // Expect the permission are reported as granted
611         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
612                 permissions, new boolean[] {false, true, false, true});
613 
614         // The permissions are granted
615         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
616                 .checkSelfPermission(Manifest.permission.WRITE_CONTACTS));
617         assertEquals(PackageManager.PERMISSION_GRANTED, getInstrumentation().getContext()
618                 .checkSelfPermission(Manifest.permission.RECORD_AUDIO));
619     }
620 
621     @Test
testInvalidPermission()622     public void testInvalidPermission() throws Exception {
623         String[] permissions = new String[] {
624                 getInstrumentation().getContext().getPackageName() + ".abadname"
625         };
626 
627         // Request the permission and allow it
628         BasePermissionActivity.Result result = requestPermissions(permissions,
629                 REQUEST_CODE_PERMISSIONS,
630                 BasePermissionActivity.class,
631                 () -> { /* empty */ });
632 
633         // Expect the permissions is not granted
634         assertPermissionRequestResult(result, REQUEST_CODE_PERMISSIONS,
635                 permissions, new boolean[] {false});
636     }
637 
assertAllPermissionsRevoked()638     private void assertAllPermissionsRevoked() {
639         assertAllPermissionsGrantState(PackageManager.PERMISSION_DENIED);
640     }
641 
assertAllPermissionsGrantState(int grantState)642     private void assertAllPermissionsGrantState(int grantState) {
643         ArrayList<String> perms = new ArrayList<>(Arrays.asList(
644                 Manifest.permission.SEND_SMS,
645                 Manifest.permission.RECEIVE_SMS,
646                 Manifest.permission.RECEIVE_WAP_PUSH,
647                 Manifest.permission.RECEIVE_MMS,
648                 Manifest.permission.READ_CALENDAR,
649                 Manifest.permission.WRITE_CALENDAR,
650                 Manifest.permission.WRITE_CONTACTS,
651                 Manifest.permission.READ_SMS,
652                 Manifest.permission.READ_PHONE_STATE,
653                 Manifest.permission.READ_CALL_LOG,
654                 Manifest.permission.WRITE_CALL_LOG,
655                 Manifest.permission.ADD_VOICEMAIL,
656                 Manifest.permission.CALL_PHONE,
657                 Manifest.permission.USE_SIP,
658                 Manifest.permission.PROCESS_OUTGOING_CALLS,
659                 Manifest.permission.RECORD_AUDIO,
660                 Manifest.permission.ACCESS_FINE_LOCATION,
661                 Manifest.permission.ACCESS_COARSE_LOCATION,
662                 Manifest.permission.CAMERA,
663                 Manifest.permission.BODY_SENSORS,
664                 Manifest.permission.READ_CELL_BROADCASTS,
665 
666                 // Split permissions
667                 Manifest.permission.ACCESS_BACKGROUND_LOCATION
668         ));
669 
670         perms.add(Manifest.permission.READ_EXTERNAL_STORAGE);
671         perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
672         assertPermissionsGrantState(perms.toArray(new String[perms.size()]), grantState);
673     }
674 
assertPermissionsGrantState(String[] permissions, int grantState)675     private void assertPermissionsGrantState(String[] permissions, int grantState) {
676         for (String permission : permissions) {
677             assertEquals(grantState, getInstrumentation().getContext()
678                     .checkSelfPermission(permission));
679         }
680     }
681 
denyWithPrejudice()682     private void denyWithPrejudice() throws Exception {
683         if (mLeanback || mWatch) {
684             clickDontAskAgainButton();
685         } else {
686             clickDenyAndDontAskAgainButton();
687         }
688     }
689 
690     /**
691      * Attempt to insert a new unique calendar item; this might be ignored if
692      * this legacy app has its permission revoked.
693      */
insertCalendarItem()694     private Uri insertCalendarItem() {
695         final ContentValues values = new ContentValues();
696         values.put(CalendarContract.Calendars.NAME, "cts" + System.nanoTime());
697         values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "cts");
698         values.put(CalendarContract.Calendars.CALENDAR_COLOR, 0xffff0000);
699         return mContext.getContentResolver().insert(CalendarContract.Calendars.CONTENT_URI, values);
700     }
701 }
702