Home | History | Annotate | Download | only in cts
      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
    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
    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
    135     public void installApp() throws Exception {
    136         mCurrentUserId = Process.myUserHandle().getIdentifier();
    137         installPackage(APP_APK_PATH);
    138     }
    139 
    140     @After
    141     public void uninstallApp() throws Exception {
    142         uninstallPackage(APP_PACKAGE_NAME);
    143     }
    144 
    145     @Before
    146     public void wakeUpScreen() throws IOException {
    147         runShellCommand(sInstrumentation, "input keyevent KEYCODE_WAKEUP");
    148     }
    149 
    150     @Test
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    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
    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
    322     private UiObject2 findDontAskAgainCheck() {
    323         return findDontAskAgainCheck(true);
    324     }
    325 
    326     @NonNull
    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 
    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
    352     private Pair<Integer, Intent> waitForResult() throws InterruptedException {
    353         return mActivityRule.getActivity().waitForActivityResult(TIMEOUT_MILLIS);
    354     }
    355 
    356     private void clearPackageData(@NonNull String packageName) {
    357         runShellCommand("pm clear --user " + mCurrentUserId + " " + packageName);
    358     }
    359 
    360     private void installPackage(@NonNull String apkPath) {
    361         runShellCommand("pm install -r --user " + mCurrentUserId + " " + apkPath);
    362     }
    363 
    364     private void uninstallPackage(@NonNull String packageName) {
    365         runShellCommand("pm uninstall --user " + mCurrentUserId + " " + packageName);
    366     }
    367 
    368     @Test
    369     public void roleIsAvailable() {
    370         assertThat(sRoleManager.isRoleAvailable(ROLE_NAME)).isTrue();
    371     }
    372 
    373     @Test
    374     public void dontAddRoleHolderThenRoleIsNotHeld() throws Exception {
    375         assertRoleIsHeld(ROLE_NAME, false);
    376     }
    377 
    378     @Test
    379     public void addRoleHolderThenRoleIsHeld() throws Exception {
    380         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
    381 
    382         assertRoleIsHeld(ROLE_NAME, true);
    383     }
    384 
    385     @Test
    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 
    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
    410     public void dontAddRoleHolderThenIsNotRoleHolder() throws Exception {
    411         assertIsRoleHolder(ROLE_NAME, APP_PACKAGE_NAME, false);
    412     }
    413 
    414     @Test
    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
    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
    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
    438     public void addOnRoleHoldersChangedListenerAndAddRoleHolderThenIsNotified() throws Exception {
    439         assertOnRoleHoldersChangedListenerIsNotified(() -> addRoleHolder(ROLE_NAME,
    440                 APP_PACKAGE_NAME));
    441     }
    442 
    443     @Test
    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
    453     public void addOnRoleHoldersChangedListenerAndClearRoleHoldersThenIsNotified()
    454             throws Exception {
    455         addRoleHolder(ROLE_NAME, APP_PACKAGE_NAME);
    456 
    457         assertOnRoleHoldersChangedListenerIsNotified(() -> clearRoleHolders(ROLE_NAME));
    458     }
    459 
    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
    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
    501     public void setRoleNamesFromControllerShouldRequireManageRolesFromControllerPermission() {
    502         assertRequiresManageRolesFromControllerPermission(
    503                 () -> sRoleManager.setRoleNamesFromController(Collections.emptyList()),
    504                 "setRoleNamesFromController");
    505     }
    506 
    507     @Test
    508     public void addRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
    509         assertRequiresManageRolesFromControllerPermission(
    510                 () -> sRoleManager.addRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
    511                 "addRoleHolderFromController");
    512     }
    513 
    514     @Test
    515     public void removeRoleHolderFromControllerShouldRequireManageRolesFromControllerPermission() {
    516         assertRequiresManageRolesFromControllerPermission(
    517                 () -> sRoleManager.removeRoleHolderFromController(ROLE_NAME, APP_PACKAGE_NAME),
    518                 "removeRoleHolderFromController");
    519     }
    520 
    521     @Test
    522     public void getHeldRolesFromControllerShouldRequireManageRolesFromControllerPermission() {
    523         assertRequiresManageRolesFromControllerPermission(
    524                 () -> sRoleManager.getHeldRolesFromController(APP_PACKAGE_NAME),
    525                 "getHeldRolesFromController");
    526     }
    527 
    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
    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
    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
    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 
    579     private List<String> getRoleHolders(@NonNull String roleName) throws Exception {
    580         return callWithShellPermissionIdentity(() -> sRoleManager.getRoleHolders(roleName));
    581     }
    582 
    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 
    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 
    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 
    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
    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
    630         public void accept(Boolean successful) {
    631             if (successful) {
    632                 complete(null);
    633             } else {
    634                 completeExceptionally(new RuntimeException());
    635             }
    636         }
    637     }
    638 }
    639