Wade
Wade

Reputation: 150

AndroidTest with PACKAGE_USAGE_STATS permission

Our goal is to use AndroidTest(AndroidJUnit4) to run automatic tests.

We have used this code to grant permissions when SDK >= 23

public static void grantPermission(String permission) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (!hasPermission(permission))
            getInstrumentation().getUiAutomation()
                                .executeShellCommand("pm grant " + getTargetContext().getPackageName() + " " + permission);
    }
}

@Before
public void setUp() throws Exception {
    grantPermission("android.permission.ACCESS_NETWORK_STATE");
    grantPermission("android.permission.CHANGE_NETWORK_STATE");
    grantPermission("android.permission.CAMERA ");
    grantPermission("android.permission.INTERNET");
    grantPermission("android.permission.READ_EXTERNAL_STORAGE ");
    grantPermission("android.permission.WRITE_EXTERNAL_STORAGE");        
    grantPermission("android.permission.PACKAGE_USAGE_STATS");       
}

The method is fine for

android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.CAMERA

Although in the Settings/Security/Apps with usage access, our app is on, but when we use this code to check permission, it still doesn't have that permission.

AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);

// return MODE_DEFAULT, not MODE_ALLOWED
int result = appOps.checkOpNoThrow("android:get_usage_stats", android.os.Process.myUid(), context.getPackageName())

How can I do to succeed this goal?

Upvotes: 1

Views: 1426

Answers (2)

Wade
Wade

Reputation: 150

We have tried many approved. Finally, we succeeded.

The approved was use "adb shell input tap [x], [y]" to simulate tap, so it is like human tap the screen to trigger the switch.

This is the code us use.

private void grantPermission() throws InterruptedException {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Context context = InstrumentationRegistry.getTargetContext();
        final AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

        // check if the app doesn't have permission
        if (appOps.checkOpNoThrow("android:get_usage_stats", android.os.Process.myUid(), context.getPackageName()) != AppOpsManager.MODE_ALLOWED) {
            UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();

            //Open UsageAccessSettingsActivity
            automation.executeShellCommand("am start com.android.settings/.Settings$UsageAccessSettingsActivity");
            Thread.sleep(1000);

            //Open the setting of the first app
            automation.executeShellCommand(String.format("input tap %s %s", dpToPx(100), dpToPx(138)));
            Thread.sleep(1000);

            //Tap permit usage access
            automation.executeShellCommand(String.format("input tap %s %s", dpToPx(100), dpToPx(164)));
            Thread.sleep(1000);
        }
    }
}

public static int dpToPx(int dp) {
    return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

We have tried 6 AVDs on SDK 23 and 24 with hdip, xhdip and xxhdip. All works.

UPDATED[2/10]:

We found another easier way to do it. use "adb shell appops" commend. This is ours code.

@Before
public void setUp() throws Exception {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Context context = InstrumentationRegistry.getTargetContext();
        final AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);

        if (appOps.checkOpNoThrow("android:get_usage_stats", android.os.Process.myUid(), context.getPackageName()) != AppOpsManager.MODE_ALLOWED) {
            InstrumentationRegistry
                    .getInstrumentation()
                    .getUiAutomation()
                    .executeShellCommand("appops set " + context.getPackageName() + " android:get_usage_stats allow");
        }
    }
}

Upvotes: 4

Kenny Gunderman
Kenny Gunderman

Reputation: 500

Make sure your app has usage stats enabled. You can check this by launching the Usage Stats Activity. add this to your code on your onCreate method or possible on a button click:

Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);

Upvotes: 0

Related Questions