summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:21:57 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-12-14 00:21:57 +0000
commit7d42b9cd21411a95d5b2a3a8ba01db93825c2394 (patch)
treebc56dca9bcfe376d600a8bb37c73658efc19909b
parent948678c0ac173ea729146b415561bf3bbd37808e (diff)
parent9738805ffd06d07e53d99611cc5647b05bee6e36 (diff)
downloadPermission-7d42b9cd21411a95d5b2a3a8ba01db93825c2394.tar.gz
Snap for 11216811 from 9738805ffd06d07e53d99611cc5647b05bee6e36 to 24Q1-release
Change-Id: I6b3b9cf55878caba018c92d49e49f8ea603370cf
-rw-r--r--PermissionController/res/values/strings.xml5
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java8
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java107
-rw-r--r--PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt42
-rw-r--r--framework-s/api/system-current.txt1
-rw-r--r--framework-s/java/android/app/role/IRoleController.aidl2
-rw-r--r--framework-s/java/android/app/role/RoleControllerManager.java39
-rw-r--r--framework-s/java/android/app/role/RoleControllerService.java28
-rw-r--r--service/java/com/android/role/LocalRoleController.java8
-rw-r--r--service/java/com/android/role/RemoteRoleController.java8
-rw-r--r--service/java/com/android/role/RoleController.java7
-rw-r--r--service/java/com/android/role/RoleService.java34
-rw-r--r--service/java/com/android/role/RoleUserState.java39
-rw-r--r--service/java/com/android/role/persistence/RolesState.java3
-rw-r--r--tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt1
-rw-r--r--tests/cts/permission/Android.bp1
-rw-r--r--tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml1
-rw-r--r--tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java13
-rw-r--r--tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java126
20 files changed, 347 insertions, 178 deletions
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 9daa624f8..d10c6fb90 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -337,11 +337,6 @@
<!-- Title of the permission dialog for accessibility purposes- spoken to the user. [CHAR LIMIT=none] -->
<string name="permission_request_title">Permission request</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] -->
- <string name="wear_not_allowed_dlg_title">Android Wear</string>
- <!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] -->
- <string name="wear_not_allowed_dlg_text">Install/Uninstall actions not supported on Wear.</string>
-
<!-- Review of runtime permissions for legacy apps -->
<!-- Template for the screen title when app permissions are reviewed on install. [CHAR LIMIT=none] -->
diff --git a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java
index d3c099d5e..2a6010c4d 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/service/RoleControllerServiceImpl.java
@@ -32,6 +32,7 @@ import androidx.annotation.WorkerThread;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
import com.android.role.controller.util.CollectionUtils;
+import com.android.role.controller.util.LegacyRoleFallbackEnabledUtils;
import com.android.role.controller.util.PackageUtils;
import com.android.role.controller.util.UserUtils;
@@ -468,6 +469,13 @@ public class RoleControllerServiceImpl extends RoleControllerService {
return role.isVisibleAsUser(mUser, mContext);
}
+ @Override
+ @NonNull
+ public List<String> onGetLegacyFallbackDisabledRoles() {
+ return LegacyRoleFallbackEnabledUtils.getFallbackDisabledRoles(mUser, mContext);
+ }
+
+
private static boolean checkFlags(int flags, int allowedFlags) {
if ((flags & allowedFlags) != flags) {
Log.e(LOG_TAG, "flags is invalid, flags: 0x" + Integer.toHexString(flags)
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java
new file mode 100644
index 000000000..5be10a26a
--- /dev/null
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/LegacyRoleFallbackEnabledUtils.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.role.controller.util;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.UserHandle;
+
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LegacyRoleFallbackEnabledUtils {
+ /**
+ * Name of generic shared preferences file.
+ */
+ private static final String PREFERENCES_FILE = "preferences";
+
+ /**
+ * Key in the generic shared preferences that stores if the user manually selected the "none"
+ * role holder for a role.
+ */
+ private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:";
+
+ /**
+ * Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
+ *
+ * @param context the context to get the shared preferences
+ * @return a device protected storage based shared preferences
+ */
+ @NonNull
+ @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static SharedPreferences getSharedPreferences(@NonNull UserHandle user,
+ @NonNull Context context) {
+ String packageName = context.getPackageManager().getPermissionControllerPackageName();
+ try {
+ context = context.createPackageContextAsUser(packageName, 0, user);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (!context.isDeviceProtectedStorage()) {
+ context = context.createDeviceProtectedStorageContext();
+ }
+ return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Get all role names with fallback disabled, which means their "none" are set to true.
+ *
+ * @return A list of role names with fallback disabled.
+ */
+ public static List<String> getFallbackDisabledRoles(@NonNull UserHandle user,
+ @NonNull Context context) {
+ List<String> fallbackDisabledRoles = new ArrayList<>();
+ SharedPreferences sharedPreferences = getSharedPreferences(user, context);
+ for (String key : sharedPreferences.getAll().keySet()) {
+ if (key.startsWith(IS_NONE_ROLE_HOLDER_SELECTED_KEY)
+ && sharedPreferences.getBoolean(key, false)) {
+ String roleName = key.substring(IS_NONE_ROLE_HOLDER_SELECTED_KEY.length());
+ fallbackDisabledRoles.add(roleName);
+ }
+ }
+ return fallbackDisabledRoles;
+ }
+
+ /**
+ * Check whether the role has the fallback holder enabled.
+ *
+ * @return whether the "none" role holder is not selected
+ */
+ public static boolean isRoleFallbackEnabledAsUser(@NonNull String roleName,
+ @NonNull UserHandle user, @NonNull Context context) {
+ return !getSharedPreferences(user, context)
+ .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName, false);
+ }
+
+ /**
+ * Set whether the role has fallback holder enabled.
+ */
+ public static void setRoleFallbackEnabledAsUser(@NonNull String roleName,
+ boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) {
+ String key = IS_NONE_ROLE_HOLDER_SELECTED_KEY + roleName;
+ if (fallbackEnabled) {
+ getSharedPreferences(user, context).edit().remove(key).apply();
+ } else {
+ getSharedPreferences(user, context).edit().putBoolean(key, true).apply();
+ }
+ }
+}
diff --git a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
index 8a6fd579c..ec63528d1 100644
--- a/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
+++ b/PermissionController/role-controller/java/com/android/role/controller/util/RoleManagerCompat.java
@@ -18,8 +18,8 @@ package com.android.role.controller.util;
import android.app.role.RoleManager;
import android.content.Context;
-import android.content.SharedPreferences;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import androidx.annotation.NonNull;
@@ -31,16 +31,7 @@ import com.android.role.controller.model.Role;
*/
public class RoleManagerCompat {
- /**
- * Key in the generic shared preferences that stores if the user manually selected the "none"
- * role holder for a role.
- */
- private static final String IS_NONE_ROLE_HOLDER_SELECTED_KEY = "is_none_role_holder_selected:";
- /**
- * Name of generic shared preferences file.
- */
- private static final String PREFERENCES_FILE = "preferences";
private RoleManagerCompat() {}
@@ -56,47 +47,34 @@ public class RoleManagerCompat {
}
/**
- * Get a device protected storage based shared preferences. Avoid storing sensitive data in it.
- *
- * @param context the context to get the shared preferences
- * @return a device protected storage based shared preferences
- */
- @NonNull
- private static SharedPreferences getDeviceProtectedSharedPreferences(@NonNull Context context) {
- if (!context.isDeviceProtectedStorage()) {
- context = context.createDeviceProtectedStorageContext();
- }
- return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
- }
-
- /**
* Check whether the role has the fallback holder enabled.
*
* @return whether the "none" role holder is not selected
*/
public static boolean isRoleFallbackEnabledAsUser(@NonNull Role role, @NonNull UserHandle user,
@NonNull Context context) {
- Context userContext = UserUtils.getUserContext(context, user);
- boolean isNoneHolderSelected = getDeviceProtectedSharedPreferences(userContext)
- .getBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), false);
- return !isNoneHolderSelected;
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ return userRoleManager.isRoleFallbackEnabled(role.getName());
+ } else {
+ return LegacyRoleFallbackEnabledUtils.isRoleFallbackEnabledAsUser(role.getName(), user,
+ context);
+ }
}
/**
* Set whether the role has fallback holder enabled.
- *
*/
public static void setRoleFallbackEnabledAsUser(@NonNull Role role,
boolean fallbackEnabled, @NonNull UserHandle user, @NonNull Context context) {
- Context userContext = UserUtils.getUserContext(context, user);
- if (fallbackEnabled) {
- getDeviceProtectedSharedPreferences(userContext).edit()
- .remove(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName())
- .apply();
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ Context userContext = UserUtils.getUserContext(context, user);
+ RoleManager userRoleManager = userContext.getSystemService(RoleManager.class);
+ userRoleManager.setRoleFallbackEnabled(role.getName(), fallbackEnabled);
} else {
- getDeviceProtectedSharedPreferences(userContext).edit()
- .putBoolean(IS_NONE_ROLE_HOLDER_SELECTED_KEY + role.getName(), true)
- .apply();
+ LegacyRoleFallbackEnabledUtils.setRoleFallbackEnabledAsUser(role.getName(),
+ fallbackEnabled, user, context);
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
index df7a56464..3776c596f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/elements/ScrollableScreen.kt
@@ -53,9 +53,11 @@ import androidx.compose.ui.unit.dp
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import androidx.wear.compose.foundation.SwipeToDismissValue
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.ScalingLazyListScope
import androidx.wear.compose.foundation.lazy.ScalingLazyListState
+import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material.CircularProgressIndicator
import androidx.wear.compose.material.MaterialTheme
import androidx.wear.compose.material.PositionIndicator
@@ -87,30 +89,30 @@ fun ScrollableScreen(
) {
var dismissed by remember { mutableStateOf(false) }
val activity = LocalContext.current.findActivity()
+ val state = rememberSwipeToDismissBoxState()
+
+ LaunchedEffect(state.currentValue) {
+ if (state.currentValue == SwipeToDismissValue.Dismissed) {
+ dismiss(activity)
+ dismissed = true
+ state.snapTo(SwipeToDismissValue.Default)
+ }
+ }
// To support Swipe-dismiss effect,
// add the view to SwipeToDismissBox if the screen is not on the top fragment.
if (getBackStackEntryCount(activity) > 0) {
- SwipeToDismissBox(
- onDismissed = {
- dismiss(activity)
- dismissed = true
- }
- ) { isBackground ->
- if (isBackground || dismissed) {
- Box(modifier = Modifier.fillMaxSize())
- } else {
- Scaffold(
- showTimeText,
- title,
- subtitle,
- image,
- isLoading,
- content,
- titleTestTag,
- subtitleTestTag
- )
- }
+ SwipeToDismissBox(state = state) { isBackground ->
+ Scaffold(
+ showTimeText,
+ title,
+ subtitle,
+ image,
+ isLoading = isLoading || isBackground || dismissed,
+ content,
+ titleTestTag,
+ subtitleTestTag
+ )
}
} else {
Scaffold(
diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt
index 1111470d2..b5c379937 100644
--- a/framework-s/api/system-current.txt
+++ b/framework-s/api/system-current.txt
@@ -10,6 +10,7 @@ package android.app.role {
method @Deprecated @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
method @Deprecated @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
method @Deprecated @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
+ method @Deprecated @FlaggedApi("android.permission.flags.system_server_role_controller_enabled") @NonNull public java.util.List<java.lang.String> onGetLegacyFallbackDisabledRoles();
method @Deprecated @WorkerThread public abstract boolean onGrantDefaultRoles();
method @Deprecated public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
method @Deprecated public boolean onIsApplicationVisibleForRole(@NonNull String, @NonNull String);
diff --git a/framework-s/java/android/app/role/IRoleController.aidl b/framework-s/java/android/app/role/IRoleController.aidl
index 8a43d7fa9..948915f8d 100644
--- a/framework-s/java/android/app/role/IRoleController.aidl
+++ b/framework-s/java/android/app/role/IRoleController.aidl
@@ -40,4 +40,6 @@ oneway interface IRoleController {
in RemoteCallback callback);
void isRoleVisible(in String roleName, in RemoteCallback callback);
+
+ void getLegacyFallbackDisabledRoles(in RemoteCallback callback);
}
diff --git a/framework-s/java/android/app/role/RoleControllerManager.java b/framework-s/java/android/app/role/RoleControllerManager.java
index 3b990b315..57da2ccd0 100644
--- a/framework-s/java/android/app/role/RoleControllerManager.java
+++ b/framework-s/java/android/app/role/RoleControllerManager.java
@@ -37,6 +37,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -48,6 +49,12 @@ import java.util.function.Consumer;
*/
public class RoleControllerManager {
+ /**
+ * Bundle key for getting legacy fallback disabled roles
+ */
+ public static final String KEY_LEGACY_FALLBACK_DISABLED_ROLES =
+ "LEGACY_FALLBACK_DISABLED_ROLES";
+
private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
private static final long REQUEST_TIMEOUT_MILLIS = 15 * 1000;
@@ -187,8 +194,7 @@ public class RoleControllerManager {
@RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.onClearRoleHolders(roleName, flags,
- new RemoteCallback(future::complete));
+ service.onClearRoleHolders(roleName, flags, new RemoteCallback(future::complete));
return future;
});
propagateCallback(operation, "onClearRoleHolders", callback);
@@ -227,6 +233,35 @@ public class RoleControllerManager {
propagateCallback(operation, "isRoleVisible", executor, callback);
}
+ /**
+ * @see RoleControllerService#onGrantDefaultRoles()
+ *
+ * @hide
+ */
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ mRemoteService.postAsync(service -> {
+ AndroidFuture<Bundle> future = new AndroidFuture<>();
+ service.getLegacyFallbackDisabledRoles(new RemoteCallback(future::complete));
+ return future;
+ }).orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
+ .whenComplete((res, err) -> executor.execute(() -> {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (err != null) {
+ Log.e(LOG_TAG, "Error calling getLegacyFallbackDisabledRoles()",
+ err);
+ callback.accept(null);
+ } else {
+ callback.accept(res.getStringArrayList(
+ KEY_LEGACY_FALLBACK_DISABLED_ROLES));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }));
+ }
+
private void propagateCallback(AndroidFuture<Bundle> operation, String opName,
@CallbackExecutor @NonNull Executor executor,
Consumer<Boolean> destination) {
diff --git a/framework-s/java/android/app/role/RoleControllerService.java b/framework-s/java/android/app/role/RoleControllerService.java
index cf7872913..60a13f7ba 100644
--- a/framework-s/java/android/app/role/RoleControllerService.java
+++ b/framework-s/java/android/app/role/RoleControllerService.java
@@ -17,6 +17,7 @@
package android.app.role;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -31,9 +32,12 @@ import android.os.IBinder;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.UserHandle;
+import android.permission.flags.Flags;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -175,6 +179,19 @@ public abstract class RoleControllerService extends Service {
boolean visible = onIsRoleVisible(roleName);
callback.sendResult(visible ? Bundle.EMPTY : null);
}
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(RemoteCallback callback) {
+ enforceCallerSystemUid("getLegacyFallbackDisabledRoles");
+
+ Objects.requireNonNull(callback, "callback cannot be null");
+
+ List<String> legacyFallbackDisabledRoles = onGetLegacyFallbackDisabledRoles();
+ Bundle result = new Bundle();
+ result.putStringArrayList(RoleControllerManager.KEY_LEGACY_FALLBACK_DISABLED_ROLES,
+ new ArrayList<>(legacyFallbackDisabledRoles));
+ callback.sendResult(result);
+ }
};
}
@@ -301,4 +318,15 @@ public abstract class RoleControllerService extends Service {
* @return whether the role should be visible to user
*/
public abstract boolean onIsRoleVisible(@NonNull String roleName);
+
+ /**
+ * Get the legacy fallback disabled state.
+ *
+ * @return A list of role names with disabled fallback state.
+ */
+ @FlaggedApi(Flags.FLAG_SYSTEM_SERVER_ROLE_CONTROLLER_ENABLED)
+ @NonNull
+ public List<String> onGetLegacyFallbackDisabledRoles() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/service/java/com/android/role/LocalRoleController.java b/service/java/com/android/role/LocalRoleController.java
index 6548aaa03..03508d1cb 100644
--- a/service/java/com/android/role/LocalRoleController.java
+++ b/service/java/com/android/role/LocalRoleController.java
@@ -16,6 +16,7 @@
package com.android.role;
+import android.annotation.CallbackExecutor;
import android.app.role.RoleControllerService;
import android.app.role.RoleManager;
import android.content.Context;
@@ -29,6 +30,7 @@ import androidx.annotation.NonNull;
import com.android.role.controller.service.RoleControllerServiceImpl;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -93,4 +95,10 @@ public class LocalRoleController implements RoleController {
@NonNull String packageName) {
return mService.onIsApplicationVisibleForRole(roleName, packageName);
}
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/service/java/com/android/role/RemoteRoleController.java b/service/java/com/android/role/RemoteRoleController.java
index cbf164d6d..0920dd56a 100644
--- a/service/java/com/android/role/RemoteRoleController.java
+++ b/service/java/com/android/role/RemoteRoleController.java
@@ -16,6 +16,7 @@
package com.android.role;
+import android.annotation.CallbackExecutor;
import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
import android.content.Context;
@@ -26,6 +27,7 @@ import androidx.annotation.NonNull;
import com.android.permission.util.ForegroundThread;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -73,4 +75,10 @@ public class RemoteRoleController implements RoleController {
@NonNull String packageName) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback) {
+ mRoleControllerManager.getLegacyFallbackDisabledRoles(executor, callback);
+ }
}
diff --git a/service/java/com/android/role/RoleController.java b/service/java/com/android/role/RoleController.java
index 8a7ef8646..6ebbdfd45 100644
--- a/service/java/com/android/role/RoleController.java
+++ b/service/java/com/android/role/RoleController.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.app.role.RoleManager;
import android.os.RemoteCallback;
+import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -58,4 +59,10 @@ public interface RoleController {
* @see android.app.role.RoleControllerManager#isApplicationVisibleForRole
*/
boolean isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName);
+
+ /**
+ * @see android.app.role.RoleControllerManager#getLegacyFallbackDisabledRoles
+ */
+ void getLegacyFallbackDisabledRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<List<String>> callback);
}
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java
index c1a3ea4d9..2524627eb 100644
--- a/service/java/com/android/role/RoleService.java
+++ b/service/java/com/android/role/RoleService.java
@@ -252,9 +252,40 @@ public class RoleService extends SystemService implements RoleUserState.Callback
@Override
public void onUserStarting(@NonNull TargetUser user) {
+ if (SdkLevel.isAtLeastV() && Flags.systemServerRoleControllerEnabled()) {
+ upgradeLegacyFallbackEnabledRolesIfNeeded(user);
+ }
+
maybeGrantDefaultRolesSync(user.getUserHandle().getIdentifier());
}
+ private void upgradeLegacyFallbackEnabledRolesIfNeeded(@NonNull TargetUser user) {
+ int userId = user.getUserHandle().getIdentifier();
+ RoleUserState userState = getOrCreateUserState(userId);
+ if (!userState.isVersionUpgradeNeeded()) {
+ return;
+ }
+ List<String> legacyFallbackDisabledRoles = getLegacyFallbackDisabledRolesSync(userId);
+ if (legacyFallbackDisabledRoles == null) {
+ return;
+ }
+ userState.upgradeVersion(legacyFallbackDisabledRoles);
+ }
+
+ @MainThread
+ private List<String> getLegacyFallbackDisabledRolesSync(@UserIdInt int userId) {
+ AndroidFuture<List<String>> future = new AndroidFuture<>();
+ RoleController controller = new RemoteRoleController(UserHandle.of(userId), getContext());
+ controller.getLegacyFallbackDisabledRoles(ForegroundThread.getExecutor(), future::complete);
+ try {
+ return future.get(30, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Log.e(LOG_TAG, "Failed to get the legacy role fallback disabled state for user "
+ + userId, e);
+ return null;
+ }
+ }
+
@MainThread
private void maybeGrantDefaultRolesSync(@UserIdInt int userId) {
AndroidFuture<Void> future = maybeGrantDefaultRolesInternal(userId);
@@ -493,8 +524,7 @@ public class RoleService extends SystemService implements RoleUserState.Callback
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Objects.requireNonNull(callback, "callback cannot be null");
- getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
- callback);
+ getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags, callback);
}
@Override
diff --git a/service/java/com/android/role/RoleUserState.java b/service/java/com/android/role/RoleUserState.java
index 201633898..39c1e8c3d 100644
--- a/service/java/com/android/role/RoleUserState.java
+++ b/service/java/com/android/role/RoleUserState.java
@@ -89,7 +89,7 @@ class RoleUserState {
private ArrayMap<String, ArraySet<String>> mRoles = new ArrayMap<>();
/**
- *
+ * Role names of the roles with fallback enabled.
*/
@GuardedBy("mLock")
@NonNull
@@ -150,6 +150,15 @@ class RoleUserState {
}
/**
+ * Checks the version and returns whether a version upgrade is needed.
+ */
+ public boolean isVersionUpgradeNeeded() {
+ synchronized (mLock) {
+ return mVersion < VERSION_FALLBACK_STATE_MIGRATED;
+ }
+ }
+
+ /**
* Get the hash representing the state of packages during the last time initial grants was run.
*
* @return the hash representing the state of packages
@@ -228,6 +237,23 @@ class RoleUserState {
}
/**
+ * Upgrade this user state to the latest version if needed.
+ */
+ public void upgradeVersion(@NonNull List<String> legacyFallbackDisabledRoles) {
+ synchronized (mLock) {
+ if (mVersion < VERSION_FALLBACK_STATE_MIGRATED) {
+ int legacyFallbackDisabledRolesSize = legacyFallbackDisabledRoles.size();
+ for (int i = 0; i < legacyFallbackDisabledRolesSize; i++) {
+ String roleName = legacyFallbackDisabledRoles.get(i);
+ mFallbackEnabledRoles.remove(roleName);
+ }
+ mVersion = VERSION_FALLBACK_STATE_MIGRATED;
+ scheduleWriteFileLocked();
+ }
+ }
+ }
+
+ /**
* Get whether the role is available.
*
* @param roleName the name of the role to get the holders for
@@ -269,6 +295,7 @@ class RoleUserState {
synchronized (mLock) {
if (!mRoles.containsKey(roleName)) {
mRoles.put(roleName, new ArraySet<>());
+ mFallbackEnabledRoles.add(roleName);
Log.i(LOG_TAG, "Added new role: " + roleName);
scheduleWriteFileLocked();
return true;
@@ -297,6 +324,7 @@ class RoleUserState {
+ " role: " + roleName + ", holders: " + packageNames);
}
mRoles.removeAt(i);
+ mFallbackEnabledRoles.remove(roleName);
changed = true;
}
}
@@ -432,12 +460,15 @@ class RoleUserState {
RolesState roleState = mPersistence.readForUser(UserHandle.of(mUserId));
Map<String, Set<String>> roles;
+ Set<String> fallbackEnabledRoles;
if (roleState != null) {
mVersion = roleState.getVersion();
mPackagesHash = roleState.getPackagesHash();
roles = roleState.getRoles();
+ fallbackEnabledRoles = roleState.getFallbackEnabledRoles();
} else {
roles = mPlatformHelper.getLegacyRoleState(mUserId);
+ fallbackEnabledRoles = roles.keySet();
}
mRoles.clear();
for (Map.Entry<String, Set<String>> entry : roles.entrySet()) {
@@ -445,12 +476,10 @@ class RoleUserState {
ArraySet<String> roleHolders = new ArraySet<>(entry.getValue());
mRoles.put(roleName, roleHolders);
}
-
+ mFallbackEnabledRoles.clear();
+ mFallbackEnabledRoles.addAll(fallbackEnabledRoles);
if (roleState == null) {
scheduleWriteFileLocked();
- } else {
- mFallbackEnabledRoles.clear();
- mFallbackEnabledRoles.addAll(roleState.getFallbackEnabledRoles());
}
}
}
diff --git a/service/java/com/android/role/persistence/RolesState.java b/service/java/com/android/role/persistence/RolesState.java
index 26644c358..a189dd4c2 100644
--- a/service/java/com/android/role/persistence/RolesState.java
+++ b/service/java/com/android/role/persistence/RolesState.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
import android.permission.flags.Flags;
-import android.util.ArraySet;
import java.util.Map;
import java.util.Objects;
@@ -68,7 +67,7 @@ public final class RolesState {
*/
public RolesState(int version, @Nullable String packagesHash,
@NonNull Map<String, Set<String>> roles) {
- this(version, packagesHash, roles, new ArraySet<>());
+ this(version, packagesHash, roles, roles.keySet());
}
/**
diff --git a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
index 0cf1fa665..6500b3926 100644
--- a/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
+++ b/tests/apex/java/com/android/role/persistence/RolesPersistenceTest.kt
@@ -111,6 +111,7 @@ class RolesPersistenceTest {
assertThat(persistedState).isNull()
}
+
private fun getState(): RolesState =
when (stateVersion) {
StateVersion.VERSION_UNDEFINED -> stateVersionUndefined
diff --git a/tests/cts/permission/Android.bp b/tests/cts/permission/Android.bp
index 9c07544a3..8849f41a7 100644
--- a/tests/cts/permission/Android.bp
+++ b/tests/cts/permission/Android.bp
@@ -52,7 +52,6 @@ android_test {
"sts-device-util",
"platform-test-rules",
"CtsVirtualDeviceCommonLib",
- "android.permission.flags-aconfig-java",
],
jni_libs: [
"libctspermission_jni",
diff --git a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml
index 4b0c60bdb..ef4d82dfc 100644
--- a/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml
+++ b/tests/cts/permission/AppThatAccessesCalendarContactsBodySensorCustomPermission/AndroidManifest.xml
@@ -34,7 +34,6 @@
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.BODY_SENSORS" />
- <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.cts.appthatrequestcustompermission.TEST_PERMISSION" />
<application />
diff --git a/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
index 0ccebed04..51b3bd830 100644
--- a/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
+++ b/tests/cts/permission/src/android/permission/cts/NoSystemFunctionPermissionTest.java
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Vibrator;
+import android.os.VibratorManager;
import android.platform.test.annotations.AppModeFull;
import android.telephony.gsm.SmsManager;
import android.test.AndroidTestCase;
@@ -121,7 +122,17 @@ public class NoSystemFunctionPermissionTest extends AndroidTestCase {
*/
@SmallTest
public void testVibrator() {
- Vibrator vibrator = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ Vibrator vibrator = mContext.getSystemService(VibratorManager.class).getDefaultVibrator();
+
+ if (!vibrator.hasVibrator()) {
+ // Run the test only if a vibrator is present.
+ return;
+ }
+
+ if (!vibrator.hasVibrator()) {
+ // If the test device does not have a vibrator, then abort test.
+ return;
+ }
try {
vibrator.cancel();
diff --git a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java
index 2c39f27d4..05aa41d69 100644
--- a/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java
+++ b/tests/cts/permission/src/android/permission/cts/PermissionUpdateListenerTest.java
@@ -23,26 +23,18 @@ import static com.android.compatibility.common.util.SystemUtil.runWithShellPermi
import static com.google.common.truth.Truth.assertThat;
import android.companion.virtual.VirtualDeviceManager;
-import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
-import android.permission.flags.Flags;
import android.platform.test.annotations.AppModeFull;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.virtualdevice.cts.common.FakeAssociationRule;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.compatibility.common.util.AdoptShellPermissionsRule;
import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,28 +52,15 @@ public class PermissionUpdateListenerTest {
+ "CtsAppThatRequestsCalendarContactsBodySensorCustomPermission.apk";
private static final String PACKAGE_NAME =
"android.permission.cts.appthatrequestcustompermission";
- private static final String PERMISSION_NAME = "android.permission.CAMERA";
+ private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS";
private static final int TIMEOUT = 10000;
- private final Context mDefaultContext =
+ private final Context mContext =
InstrumentationRegistry.getInstrumentation().getContext();
- private final PackageManager mPackageManager = mDefaultContext.getPackageManager();
+ private final PackageManager mPackageManager = mContext.getPackageManager();
private int mTestAppUid;
- private VirtualDeviceManager mVirtualDeviceManager;
-
- @Rule
- public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule();
-
- @Rule
- public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
- InstrumentationRegistry.getInstrumentation().getUiAutomation(),
- android.Manifest.permission.CREATE_VIRTUAL_DEVICE);
-
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
@Before
public void setup() throws PackageManager.NameNotFoundException, InterruptedException {
runShellCommandOrThrow("pm install " + APK);
@@ -90,7 +69,6 @@ public class PermissionUpdateListenerTest {
SystemUtil.waitForBroadcasts();
Thread.sleep(1000);
mTestAppUid = mPackageManager.getPackageUid(PACKAGE_NAME, 0);
- mVirtualDeviceManager = mDefaultContext.getSystemService(VirtualDeviceManager.class);
}
@After
@@ -111,7 +89,7 @@ public class PermissionUpdateListenerTest {
runWithShellPermissionIdentity(() -> {
mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener);
mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
- mDefaultContext.getUser());
+ mContext.getUser());
});
countDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
runWithShellPermissionIdentity(() -> {
@@ -122,117 +100,61 @@ public class PermissionUpdateListenerTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
- public void testVirtualDeviceGrantPermissionNotifyListener() throws InterruptedException {
- VirtualDeviceManager.VirtualDevice virtualDevice =
- mVirtualDeviceManager.createVirtualDevice(
- mFakeAssociationRule.getAssociationInfo().getId(),
- new VirtualDeviceParams.Builder().build());
- Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
- testGrantPermissionNotifyListener(deviceContext, virtualDevice.getPersistentDeviceId());
- }
-
- @Test
- public void testDefaultDeviceGrantPermissionNotifyListener() throws InterruptedException {
- testGrantPermissionNotifyListener(
- mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
- }
-
- private void testGrantPermissionNotifyListener(
- Context context, String expectedDeviceId) throws InterruptedException {
- final PackageManager packageManager = context.getPackageManager();
+ public void testGrantPermissionNotifyListener() throws InterruptedException {
TestOnPermissionsChangedListener permissionsChangedListener =
new TestOnPermissionsChangedListener(1);
runWithShellPermissionIdentity(() -> {
- packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
- packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
- mDefaultContext.getUser());
+ mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mContext.getUser());
});
permissionsChangedListener.waitForPermissionChangedCallbacks();
runWithShellPermissionIdentity(() -> {
- packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
});
String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
- assertThat(deviceId).isEqualTo(expectedDeviceId);
+ assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
@Test
- public void testDefaultDeviceRevokePermissionNotifyListener() throws InterruptedException {
- testRevokePermissionNotifyListener(
- mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
- public void testVirtualDeviceRevokePermissionNotifyListener() throws InterruptedException {
- VirtualDeviceManager.VirtualDevice virtualDevice =
- mVirtualDeviceManager.createVirtualDevice(
- mFakeAssociationRule.getAssociationInfo().getId(),
- new VirtualDeviceParams.Builder().build());
- Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
- testRevokePermissionNotifyListener(
- deviceContext, virtualDevice.getPersistentDeviceId());
- }
-
- private void testRevokePermissionNotifyListener(
- Context context, String expectedDeviceId) throws InterruptedException {
- final PackageManager packageManager = context.getPackageManager();
+ public void testRevokePermissionNotifyListener() throws InterruptedException {
TestOnPermissionsChangedListener permissionsChangedListener =
new TestOnPermissionsChangedListener(1);
runWithShellPermissionIdentity(() -> {
- packageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
- mDefaultContext.getUser());
- packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
- packageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
- mDefaultContext.getUser());
+ mPackageManager.grantRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mContext.getUser());
+ mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.revokeRuntimePermission(PACKAGE_NAME, PERMISSION_NAME,
+ mContext.getUser());
});
permissionsChangedListener.waitForPermissionChangedCallbacks();
runWithShellPermissionIdentity(() -> {
- packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
});
String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
- assertThat(deviceId).isEqualTo(expectedDeviceId);
+ assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
@Test
- public void testDefaultDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException {
- testUpdatePermissionFlagsNotifyListener(
- mDefaultContext, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
- public void testVirtualDeviceUpdatePermissionFlagsNotifyListener() throws InterruptedException {
- VirtualDeviceManager.VirtualDevice virtualDevice =
- mVirtualDeviceManager.createVirtualDevice(
- mFakeAssociationRule.getAssociationInfo().getId(),
- new VirtualDeviceParams.Builder().build());
- Context deviceContext = mDefaultContext.createDeviceContext(virtualDevice.getDeviceId());
- testUpdatePermissionFlagsNotifyListener(
- deviceContext, virtualDevice.getPersistentDeviceId());
- }
-
- private void testUpdatePermissionFlagsNotifyListener(
- Context context, String expectedDeviceId) throws InterruptedException {
+ public void testUpdatePermissionFlagsNotifyListener() throws InterruptedException {
TestOnPermissionsChangedListener permissionsChangedListener =
new TestOnPermissionsChangedListener(1);
- final PackageManager packageManager = context.getPackageManager();
runWithShellPermissionIdentity(() -> {
- packageManager.addOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.addOnPermissionsChangeListener(permissionsChangedListener);
int flag = PackageManager.FLAG_PERMISSION_USER_SET;
- packageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag,
- mDefaultContext.getUser());
+ mPackageManager.updatePermissionFlags(PERMISSION_NAME, PACKAGE_NAME, flag, flag,
+ mContext.getUser());
});
permissionsChangedListener.waitForPermissionChangedCallbacks();
runWithShellPermissionIdentity(() -> {
- packageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
+ mPackageManager.removeOnPermissionsChangeListener(permissionsChangedListener);
});
String deviceId = permissionsChangedListener.getNotifiedDeviceId(mTestAppUid);
- assertThat(deviceId).isEqualTo(expectedDeviceId);
+ assertThat(deviceId).isEqualTo(VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT);
}
private class TestOnPermissionsChangedListener