diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:21:57 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-14 00:21:57 +0000 |
commit | 7d42b9cd21411a95d5b2a3a8ba01db93825c2394 (patch) | |
tree | bc56dca9bcfe376d600a8bb37c73658efc19909b | |
parent | 948678c0ac173ea729146b415561bf3bbd37808e (diff) | |
parent | 9738805ffd06d07e53d99611cc5647b05bee6e36 (diff) | |
download | Permission-7d42b9cd21411a95d5b2a3a8ba01db93825c2394.tar.gz |
Snap for 11216811 from 9738805ffd06d07e53d99611cc5647b05bee6e36 to 24Q1-release
Change-Id: I6b3b9cf55878caba018c92d49e49f8ea603370cf
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 |