• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 android.app.role.cts;
18 
19 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
20 import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
21 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.junit.Assert.fail;
25 
26 import android.app.Activity;
27 import android.app.AppOpsManager;
28 import android.app.Instrumentation;
29 import android.app.role.OnRoleHoldersChangedListener;
30 import android.app.role.RoleManager;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PermissionInfo;
36 import android.os.Process;
37 import android.os.UserHandle;
38 import android.support.test.uiautomator.By;
39 import android.support.test.uiautomator.UiDevice;
40 import android.support.test.uiautomator.UiObject2;
41 import android.support.test.uiautomator.Until;
42 import android.util.Log;
43 import android.util.Pair;
44 
45 import androidx.annotation.NonNull;
46 import androidx.annotation.Nullable;
47 import androidx.test.InstrumentationRegistry;
48 import androidx.test.filters.FlakyTest;
49 import androidx.test.rule.ActivityTestRule;
50 import androidx.test.runner.AndroidJUnit4;
51 
52 import com.android.compatibility.common.util.AppOpsUtils;
53 import com.android.compatibility.common.util.ThrowingRunnable;
54 
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 
61 import java.io.ByteArrayOutputStream;
62 import java.io.IOException;
63 import java.nio.charset.StandardCharsets;
64 import java.util.Collections;
65 import java.util.List;
66 import java.util.Objects;
67 import java.util.concurrent.CompletableFuture;
68 import java.util.concurrent.TimeUnit;
69 import java.util.concurrent.TimeoutException;
70 import java.util.function.Consumer;
71 
72 /**
73  * Tests {@link RoleManager}.
74  */
75 @RunWith(AndroidJUnit4.class)
76 public class RoleManagerTest {
77 
78     private static final String LOG_TAG = "RoleManagerTest";
79 
80     private static final long TIMEOUT_MILLIS = 15 * 1000;
81 
82     private static final long UNEXPECTED_TIMEOUT_MILLIS = 1000;
83 
84     private static final String ROLE_NAME = RoleManager.ROLE_BROWSER;
85 
86     private static final String APP_APK_PATH = "/data/local/tmp/cts/role/CtsRoleTestApp.apk";
87     private static final String APP_PACKAGE_NAME = "android.app.role.cts.app";
88     private static final String APP_IS_ROLE_HELD_ACTIVITY_NAME = APP_PACKAGE_NAME
89             + ".IsRoleHeldActivity";
90     private static final String APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD = APP_PACKAGE_NAME
91             + ".extra.IS_ROLE_HELD";
92     private static final String APP_REQUEST_ROLE_ACTIVITY_NAME = APP_PACKAGE_NAME
93             + ".RequestRoleActivity";
94 
95     private static final String PERMISSION_MANAGE_ROLES_FROM_CONTROLLER =
96             "com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER";
97 
98     private static final Instrumentation sInstrumentation =
99             InstrumentationRegistry.getInstrumentation();
100     private static final Context sContext = InstrumentationRegistry.getTargetContext();
101     private static final PackageManager sPackageManager = sContext.getPackageManager();
102     private static final RoleManager sRoleManager = sContext.getSystemService(RoleManager.class);
103     private static final UiDevice sUiDevice = UiDevice.getInstance(sInstrumentation);
104 
105     @Rule
106     public ActivityTestRule<WaitForResultActivity> mActivityRule =
107             new ActivityTestRule<>(WaitForResultActivity.class);
108 
109     private String mRoleHolder;
110     private int mCurrentUserId;
111 
112     @Before
saveRoleHolder()113     public void saveRoleHolder() throws Exception {
114         List<String> roleHolders = getRoleHolders(ROLE_NAME);
115         mRoleHolder = !roleHolders.isEmpty() ? roleHolders.get(0) : null;
116 
117         if (Objects.equals(mRoleHolder, APP_PACKAGE_NAME)) {
118             removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
119             mRoleHolder = null;
120         }
121     }
122 
123     @After
restoreRoleHolder()124     public void restoreRoleHolder() throws Exception {
125         removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
126 
127         if (mRoleHolder != null) {
128             addRoleHolder(ROLE_NAME, mRoleHolder);
129         }
130 
131         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
132     }
133 
134     @Before
installApp()135     public void installApp() throws Exception {
136         mCurrentUserId = Process.myUserHandle().getIdentifier();
137         installPackage(APP_APK_PATH);
138     }
139 
140     @After
uninstallApp()141     public void uninstallApp() throws Exception {
142         uninstallPackage(APP_PACKAGE_NAME);
143     }
144 
145     @Before
wakeUpScreen()146     public void wakeUpScreen() throws IOException {
147         runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP");
148     }
149 
150     @Test
requestRoleIntentHasPermissionControllerPackage()151     public void requestRoleIntentHasPermissionControllerPackage() throws Exception {
152         Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME);
153 
154         assertThat(intent.getPackage()).isEqualTo(
155                 sPackageManager.getPermissionControllerPackageName());
156     }
157 
158     @Test
requestRoleIntentHasExtraRoleName()159     public void requestRoleIntentHasExtraRoleName() throws Exception {
160         Intent intent = sRoleManager.createRequestRoleIntent(ROLE_NAME);
161 
162         assertThat(intent.getStringExtra(Intent.EXTRA_ROLE_NAME)).isEqualTo(ROLE_NAME);
163     }
164 
165     @FlakyTest
166     @Test
requestRoleAndDenyThenIsNotRoleHolder()167     public void requestRoleAndDenyThenIsNotRoleHolder() throws Exception {
168         requestRole(ROLE_NAME);
169         respondToRoleRequest(false);
170 
171         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
172     }
173 
174     @FlakyTest
175     @Test
requestRoleAndAllowThenIsRoleHolder()176     public void requestRoleAndAllowThenIsRoleHolder() throws Exception {
177         requestRole(ROLE_NAME);
178         respondToRoleRequest(true);
179 
180         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
181     }
182 
183     @FlakyTest
184     @Test
requestRoleFirstTimeNoDontAskAgain()185     public void requestRoleFirstTimeNoDontAskAgain() throws Exception {
186         requestRole(ROLE_NAME);
187         UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
188 
189         assertThat(dontAskAgainCheck).isNull();
190 
191         respondToRoleRequest(false);
192     }
193 
194     @FlakyTest
195     @Test
requestRoleAndDenyThenHasDontAskAgain()196     public void requestRoleAndDenyThenHasDontAskAgain() throws Exception {
197         requestRole(ROLE_NAME);
198         respondToRoleRequest(false);
199 
200         requestRole(ROLE_NAME);
201         UiObject2 dontAskAgainCheck = findDontAskAgainCheck();
202 
203         assertThat(dontAskAgainCheck).isNotNull();
204 
205         respondToRoleRequest(false);
206     }
207 
208     @FlakyTest
209     @Test
requestRoleAndDenyWithDontAskAgainReturnsCanceled()210     public void requestRoleAndDenyWithDontAskAgainReturnsCanceled() throws Exception {
211         requestRole(ROLE_NAME);
212         respondToRoleRequest(false);
213 
214         requestRole(ROLE_NAME);
215         findDontAskAgainCheck().click();
216         Pair<Integer, Intent> result = clickButtonAndWaitForResult(true);
217 
218         assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
219     }
220 
221     @FlakyTest
222     @Test
requestRoleAndDenyWithDontAskAgainThenDeniedAutomatically()223     public void requestRoleAndDenyWithDontAskAgainThenDeniedAutomatically() throws Exception {
224         requestRole(ROLE_NAME);
225         respondToRoleRequest(false);
226 
227         requestRole(ROLE_NAME);
228         findDontAskAgainCheck().click();
229         clickButtonAndWaitForResult(true);
230 
231         requestRole(ROLE_NAME);
232         Pair<Integer, Intent> result = waitForResult();
233 
234         assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
235     }
236 
237     @FlakyTest
238     @Test
requestRoleAndDenyWithDontAskAgainAndClearDataThenShowsUiWithoutDontAskAgain()239     public void requestRoleAndDenyWithDontAskAgainAndClearDataThenShowsUiWithoutDontAskAgain()
240             throws Exception {
241         requestRole(ROLE_NAME);
242         respondToRoleRequest(false);
243 
244         requestRole(ROLE_NAME);
245         findDontAskAgainCheck().click();
246         clickButtonAndWaitForResult(true);
247 
248         clearPackageData(APP_PACKAGE_NAME);
249         // Wait for the don't ask again to be forgotten.
250         Thread.sleep(2000);
251 
252         requestRole(ROLE_NAME);
253         UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
254 
255         assertThat(dontAskAgainCheck).isNull();
256 
257         respondToRoleRequest(false);
258     }
259 
260     @FlakyTest
261     @Test
requestRoleAndDenyWithDontAskAgainAndReinstallThenShowsUiWithoutDontAskAgain()262     public void requestRoleAndDenyWithDontAskAgainAndReinstallThenShowsUiWithoutDontAskAgain()
263             throws Exception {
264         requestRole(ROLE_NAME);
265         respondToRoleRequest(false);
266 
267         requestRole(ROLE_NAME);
268         findDontAskAgainCheck().click();
269         clickButtonAndWaitForResult(true);
270 
271         uninstallPackage(APP_PACKAGE_NAME);
272         // Wait for the don't ask again to be forgotten.
273         Thread.sleep(2000);
274         installPackage(APP_APK_PATH);
275 
276         requestRole(ROLE_NAME);
277         UiObject2 dontAskAgainCheck = findDontAskAgainCheck(false);
278 
279         assertThat(dontAskAgainCheck).isNull();
280 
281         respondToRoleRequest(false);
282     }
283 
284     @Test
requestAssistantRoleThenDeniedAutomatically()285     public void requestAssistantRoleThenDeniedAutomatically() throws InterruptedException {
286         requestRole(RoleManager.ROLE_ASSISTANT);
287         Pair<Integer, Intent> result = waitForResult();
288 
289         assertThat(result.first).isEqualTo(Activity.RESULT_CANCELED);
290     }
291 
requestRole(@onNull String roleName)292     private void requestRole(@NonNull String roleName) {
293         Intent intent = new Intent()
294                 .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_REQUEST_ROLE_ACTIVITY_NAME))
295                 .putExtra(Intent.EXTRA_ROLE_NAME, roleName);
296         mActivityRule.getActivity().startActivityToWaitForResult(intent);
297     }
298 
respondToRoleRequest(boolean allow)299     private void respondToRoleRequest(boolean allow) throws InterruptedException, IOException {
300         if (allow) {
301             UiObject2 item = sUiDevice.wait(Until.findObject(By.text(APP_PACKAGE_NAME)),
302                     TIMEOUT_MILLIS);
303             if (item == null) {
304                 dumpWindowHierarchy();
305                 fail("Cannot find item to click");
306             }
307             item.click();
308         }
309         Pair<Integer, Intent> result = clickButtonAndWaitForResult(allow);
310         int expectedResult = allow ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
311 
312         assertThat(result.first).isEqualTo(expectedResult);
313     }
314 
315     @Nullable
findDontAskAgainCheck(boolean expected)316     private UiObject2 findDontAskAgainCheck(boolean expected) {
317         return sUiDevice.wait(Until.findObject(By.text("Don\u2019t ask again")), expected
318                 ? TIMEOUT_MILLIS : UNEXPECTED_TIMEOUT_MILLIS);
319     }
320 
321     @Nullable
findDontAskAgainCheck()322     private UiObject2 findDontAskAgainCheck() {
323         return findDontAskAgainCheck(true);
324     }
325 
326     @NonNull
clickButtonAndWaitForResult(boolean positive)327     private Pair<Integer, Intent> clickButtonAndWaitForResult(boolean positive) throws IOException,
328             InterruptedException {
329         String buttonId = positive ? "android:id/button1" : "android:id/button2";
330         UiObject2 button = sUiDevice.wait(Until.findObject(By.res(buttonId)), TIMEOUT_MILLIS);
331         if (button == null) {
332             dumpWindowHierarchy();
333             fail("Cannot find button to click");
334         }
335         button.click();
336         return waitForResult();
337     }
338 
dumpWindowHierarchy()339     private void dumpWindowHierarchy() throws InterruptedException, IOException {
340         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
341         sUiDevice.dumpWindowHierarchy(outputStream);
342         String windowHierarchy = outputStream.toString(StandardCharsets.UTF_8.name());
343 
344         Log.w(LOG_TAG, "Window hierarchy:");
345         for (String line : windowHierarchy.split("\n")) {
346             Thread.sleep(10);
347             Log.w(LOG_TAG, line);
348         }
349     }
350 
351     @NonNull
waitForResult()352     private Pair<Integer, Intent> waitForResult() throws InterruptedException {
353         return mActivityRule.getActivity().waitForActivityResult(TIMEOUT_MILLIS);
354     }
355 
clearPackageData(@onNull String packageName)356     private void clearPackageData(@NonNull String packageName) {
357         runShellCommand("pm clear --user " + mCurrentUserId + " " + packageName);
358     }
359 
installPackage(@onNull String apkPath)360     private void installPackage(@NonNull String apkPath) {
361         runShellCommand("pm install -r --user " + mCurrentUserId + " " + apkPath);
362     }
363 
uninstallPackage(@onNull String packageName)364     private void uninstallPackage(@NonNull String packageName) {
365         runShellCommand("pm uninstall --user " + mCurrentUserId + " " + packageName);
366     }
367 
368     @Test
roleIsAvailable()369     public void roleIsAvailable() {
370         assertThat(sRoleManager.isRoleAvailable(ROLE_NAME)).isTrue();
371     }
372 
373     @Test
dontAddRoleHolderThenRoleIsNotHeld()374     public void dontAddRoleHolderThenRoleIsNotHeld() throws Exception {
375         assertRoleIsHeld(ROLE_NAME, false);
376     }
377 
378     @Test
addRoleHolderThenRoleIsHeld()379     public void addRoleHolderThenRoleIsHeld() throws Exception {
380         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
381 
382         assertRoleIsHeld(ROLE_NAME, true);
383     }
384 
385     @Test
addAndRemoveRoleHolderThenRoleIsNotHeld()386     public void addAndRemoveRoleHolderThenRoleIsNotHeld() throws Exception {
387         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
388         removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
389 
390         assertRoleIsHeld(ROLE_NAME, false);
391     }
392 
assertRoleIsHeld(@onNull String roleName, boolean isHeld)393     private void assertRoleIsHeld(@NonNull String roleName, boolean isHeld)
394             throws InterruptedException {
395         Intent intent = new Intent()
396                 .setComponent(new ComponentName(APP_PACKAGE_NAME, APP_IS_ROLE_HELD_ACTIVITY_NAME))
397                 .putExtra(Intent.EXTRA_ROLE_NAME, roleName);
398         WaitForResultActivity activity = mActivityRule.getActivity();
399         activity.startActivityToWaitForResult(intent);
400         Pair<Integer, Intent> result = activity.waitForActivityResult(TIMEOUT_MILLIS);
401 
402         assertThat(result.first).isEqualTo(Activity.RESULT_OK);
403         assertThat(result.second).isNotNull();
404         assertThat(result.second.hasExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD)).isTrue();
405         assertThat(result.second.getBooleanExtra(APP_IS_ROLE_HELD_EXTRA_IS_ROLE_HELD, false))
406                 .isEqualTo(isHeld);
407     }
408 
409     @Test
dontAddRoleHolderThenIsNotRoleHolder()410     public void dontAddRoleHolderThenIsNotRoleHolder() throws Exception {
411         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
412     }
413 
414     @Test
addRoleHolderThenIsRoleHolder()415     public void addRoleHolderThenIsRoleHolder() throws Exception {
416         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
417 
418         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, true);
419     }
420 
421     @Test
addAndRemoveRoleHolderThenIsNotRoleHolder()422     public void addAndRemoveRoleHolderThenIsNotRoleHolder() throws Exception {
423         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
424         removeRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
425 
426         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
427     }
428 
429     @Test
addAndClearRoleHoldersThenIsNotRoleHolder()430     public void addAndClearRoleHoldersThenIsNotRoleHolder() throws Exception {
431         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
432         clearRoleHolders(ROLE_NAME);
433 
434         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
435     }
436 
437     @Test
addOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotified()438     public void addOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotified() throws Exception {
439         assertOnRoleHoldersChangedListenerIsNotified(() -> addRoleHolder(ROLE_NAME,
440                 APP_PACKAGE_NAME));
441     }
442 
443     @Test
addOnRoleHoldersChangedListenerAndRemoveRoleHolderThenIsNotified()444     public void addOnRoleHoldersChangedListenerAndRemoveRoleHolderThenIsNotified()
445             throws Exception {
446         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
447 
448         assertOnRoleHoldersChangedListenerIsNotified(() -> removeRoleHolder(ROLE_NAME,
449                 APP_PACKAGE_NAME));
450     }
451 
452     @Test
addOnRoleHoldersChangedListenerAndClearRoleHoldersThenIsNotified()453     public void addOnRoleHoldersChangedListenerAndClearRoleHoldersThenIsNotified()
454             throws Exception {
455         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
456 
457         assertOnRoleHoldersChangedListenerIsNotified(() -> clearRoleHolders(ROLE_NAME));
458     }
459 
assertOnRoleHoldersChangedListenerIsNotified(@onNull ThrowingRunnable runnable)460     private void assertOnRoleHoldersChangedListenerIsNotified(@NonNull ThrowingRunnable runnable)
461             throws Exception {
462         ListenerFuture future = new ListenerFuture();
463         UserHandle user = Process.myUserHandle();
464         runWithShellPermissionIdentity(() -> sRoleManager.addOnRoleHoldersChangedListenerAsUser(
465                 sContext.getMainExecutor(), future, user));
466         Pair<String, UserHandle> result;
467         try {
468             runnable.run();
469             result = future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
470         } finally {
471             runWithShellPermissionIdentity(() ->
472                     sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user));
473         }
474 
475         assertThat(result.first).isEqualTo(ROLE_NAME);
476         assertThat(result.second).isEqualTo(user);
477     }
478 
479     @Test
addAndRemoveOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotNotified()480     public void addAndRemoveOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotNotified()
481             throws Exception {
482         ListenerFuture future = new ListenerFuture();
483         UserHandle user = Process.myUserHandle();
484         runWithShellPermissionIdentity(() -> {
485             sRoleManager.addOnRoleHoldersChangedListenerAsUser(sContext.getMainExecutor(), future,
486                     user);
487             sRoleManager.removeOnRoleHoldersChangedListenerAsUser(future, user);
488         });
489         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
490 
491         try {
492             future.get(UNEXPECTED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
493         } catch (TimeoutException e) {
494             // Expected
495             return;
496         }
497         throw new AssertionError("OnRoleHoldersChangedListener was notified after removal");
498     }
499 
500     @Test
setRoleNamesFromControllerShouldRequireManageRolesFromControllerPermission()501     public void setRoleNamesFromControllerShouldRequireManageRolesFromControllerPermission() {
502         assertRequiresManageRolesFromControllerPermission(
503                 () -> sRoleManager.setRoleNamesFromController(Collections.emptyList()),
504                 "setRoleNamesFromController");
505     }
506 
507     @Test
addRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission()508     public void addRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
509         assertRequiresManageRolesFromControllerPermission(
510                 () -> sRoleManager.addRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
511                 "addRoleHolderFromController");
512     }
513 
514     @Test
removeRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission()515     public void removeRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
516         assertRequiresManageRolesFromControllerPermission(
517                 () -> sRoleManager.removeRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
518                 "removeRoleHolderFromController");
519     }
520 
521     @Test
getHeldRolesFromControllerShouldRequireManageRolesFromControllerPermission()522     public void getHeldRolesFromControllerShouldRequireManageRolesFromControllerPermission() {
523         assertRequiresManageRolesFromControllerPermission(
524                 () -> sRoleManager.getHeldRolesFromController(APP_PACKAGE_NAME),
525                 "getHeldRolesFromController");
526     }
527 
assertRequiresManageRolesFromControllerPermission(@onNull Runnable runnable, @NonNull String methodName)528     private void assertRequiresManageRolesFromControllerPermission(@NonNull Runnable runnable,
529             @NonNull String methodName) {
530         try {
531             runnable.run();
532         } catch (SecurityException e) {
533             if (e.getMessage().contains(PERMISSION_MANAGE_ROLES_FROM_CONTROLLER)) {
534                 // Expected
535                 return;
536             }
537             throw e;
538         }
539         fail("RoleManager." + methodName + "() should require "
540                 + PERMISSION_MANAGE_ROLES_FROM_CONTROLLER);
541     }
542 
543     @Test
manageRoleFromsFromControllerPermissionShouldBeDeclaredByPermissionController()544     public void manageRoleFromsFromControllerPermissionShouldBeDeclaredByPermissionController()
545             throws PackageManager.NameNotFoundException {
546         PermissionInfo permissionInfo = sPackageManager.getPermissionInfo(
547                 PERMISSION_MANAGE_ROLES_FROM_CONTROLLER, 0);
548 
549         assertThat(permissionInfo.packageName).isEqualTo(
550                 sPackageManager.getPermissionControllerPackageName());
551         assertThat(permissionInfo.getProtection()).isEqualTo(PermissionInfo.PROTECTION_SIGNATURE);
552         assertThat(permissionInfo.getProtectionFlags()).isEqualTo(0);
553     }
554 
555     @Test
removeSmsRoleHolderThenDialerRoleAppOpIsNotDenied()556     public void removeSmsRoleHolderThenDialerRoleAppOpIsNotDenied() throws Exception {
557         if (!(sRoleManager.isRoleAvailable(RoleManager.ROLE_DIALER)
558                 && sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS))) {
559             return;
560         }
561 
562         addRoleHolder(RoleManager.ROLE_DIALER, APP_PACKAGE_NAME);
563         addRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
564         removeRoleHolder(RoleManager.ROLE_SMS, APP_PACKAGE_NAME);
565 
566         assertThat(AppOpsUtils.getOpMode(APP_PACKAGE_NAME, AppOpsManager.OPSTR_SEND_SMS))
567                 .isEqualTo(AppOpsManager.MODE_ALLOWED);
568     }
569 
570     @Test
smsRoleHasHolder()571     public void smsRoleHasHolder() throws Exception {
572         if (!sRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)) {
573             return;
574         }
575 
576         assertThat(getRoleHolders(RoleManager.ROLE_SMS)).isNotEmpty();
577     }
578 
getRoleHolders(@onNull String roleName)579     private List<String> getRoleHolders(@NonNull String roleName) throws Exception {
580         return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName));
581     }
582 
assertIsRoleHolder(@onNull String roleName, @NonNull String packageName, boolean shouldBeRoleHolder)583     private void assertIsRoleHolder(@NonNull String roleName, @NonNull String packageName,
584             boolean shouldBeRoleHolder) throws Exception {
585         List<String> packageNames = getRoleHolders(roleName);
586 
587         if (shouldBeRoleHolder) {
588             assertThat(packageNames).contains(packageName);
589         } else {
590             assertThat(packageNames).doesNotContain(packageName);
591         }
592      }
593 
addRoleHolder(@onNull String roleName, @NonNull String packageName)594     private void addRoleHolder(@NonNull String roleName, @NonNull String packageName)
595             throws Exception {
596         CallbackFuture future = new CallbackFuture();
597         runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
598                 packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future));
599         future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
600     }
601 
removeRoleHolder(@onNull String roleName, @NonNull String packageName)602     private void removeRoleHolder(@NonNull String roleName, @NonNull String packageName)
603             throws Exception {
604         CallbackFuture future = new CallbackFuture();
605         runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
606                 packageName, 0, Process.myUserHandle(), sContext.getMainExecutor(), future));
607         future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
608     }
609 
clearRoleHolders(@onNull String roleName)610     private void clearRoleHolders(@NonNull String roleName) throws Exception {
611         CallbackFuture future = new CallbackFuture();
612         runWithShellPermissionIdentity(() -> sRoleManager.clearRoleHoldersAsUser(roleName, 0,
613                 Process.myUserHandle(), sContext.getMainExecutor(), future));
614         future.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
615     }
616 
617     private static class ListenerFuture extends CompletableFuture<Pair<String, UserHandle>>
618             implements OnRoleHoldersChangedListener {
619 
620         @Override
onRoleHoldersChanged(@onNull String roleName, @NonNull UserHandle user)621         public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
622             complete(new Pair<>(roleName, user));
623         }
624     }
625 
626     private static class CallbackFuture extends CompletableFuture<Void>
627             implements Consumer<Boolean> {
628 
629         @Override
accept(Boolean successful)630         public void accept(Boolean successful) {
631             if (successful) {
632                 complete(null);
633             } else {
634                 completeExceptionally(new RuntimeException());
635             }
636         }
637     }
638 }
639