具有 PACKAGE_USAGE_STATS 权限的 AndroidTest

AndroidTest with PACKAGE_USAGE_STATS permission

我们的目标是使用 AndroidTest(AndroidJUnit4) 运行 自动测试。

当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");       
}

该方法适用于

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

虽然在Settings/Security/Appswith usage access中,我们的应用是开启的,但是当我们使用这段代码来检查权限时,它仍然没有那个权限。

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())

我怎样才能实现这个目标?

确保您的应用启用了使用情况统计信息。您可以通过启动 Usage Stats Activity 来检查这一点。在您的 onCreate 方法中将其添加到您的代码中,或者可能在单击按钮时添加:

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

我们试了很多都认可。终于,我们成功了。

批准的是使用"adb shell input tap [x], [y]"模拟点击,所以就像人类点击屏幕触发开关。

这是我们使用的代码。

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);
}

我们已经在 SDK 23 和 24 上使用 hdip、xhdip 和 xxhdip 尝试了 6 个 AVD。所有作品。

更新[2/10]:

我们找到了另一种更简单的方法。使用 "adb shell appops" 表扬。 这是我们的代码。

@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");
        }
    }
}