diff options
13 files changed, 204 insertions, 275 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt index 543d8eae2..7a817eb6d 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/LightInstallSourceInfoLiveData.kt @@ -74,7 +74,7 @@ private constructor( getInstallSourceInfo(userContext, packageName).installingPackageName) } catch (e: PackageManager.NameNotFoundException) { Log.w(LOG_TAG, "InstallSourceInfo for $packageName not found") - SafetyLabelInfoLiveData.invalidateSingle(packageName to user) + LightInstallSourceInfoLiveData.invalidateSingle(packageName to user) UNKNOWN_INSTALL_SOURCE } postValue(lightInstallSourceInfo) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt index d2ba7031d..e8102c2e0 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/data/SafetyLabelInfoLiveData.kt @@ -18,14 +18,10 @@ package com.android.permissioncontroller.permission.data import android.app.Application import android.content.pm.PackageManager -import android.os.PersistableBundle import android.os.UserHandle import android.util.Log -import com.android.permission.safetylabel.DataCategoryConstants -import com.android.permission.safetylabel.DataLabelConstants -import com.android.permission.safetylabel.DataTypeConstants +import com.android.modules.utils.build.SdkLevel import com.android.permission.safetylabel.SafetyLabel -import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION import com.android.permissioncontroller.PermissionControllerApplication import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo import com.android.permissioncontroller.permission.utils.KotlinUtils.isPlaceholderSafetyLabelDataEnabled @@ -83,6 +79,11 @@ private constructor( return } + if (!SdkLevel.isAtLeastU()) { + postValue(SafetyLabelInfo.UNAVAILABLE) + return + } + // TODO(b/261607291): Add support preinstall apps that provide SafetyLabel. Installing // package is null until updated from an app store val installSourcePackageName = lightInstallSourceInfoLiveData.value?.installingPackageName @@ -91,11 +92,16 @@ private constructor( return } + if (isPlaceholderSafetyLabelDataEnabled()) { + postValue(SafetyLabelInfo(SafetyLabel.getPlaceholderSafetyLabel(), + installSourcePackageName)) + return + } + val safetyLabelInfo: SafetyLabelInfo = try { - val metadataBundle: PersistableBundle = getAppMetadata() - val safetyLabel: SafetyLabel? = - SafetyLabel.getSafetyLabelFromMetadata(metadataBundle) + val safetyLabel: SafetyLabel? = SafetyLabel.getSafetyLabelFromMetadata( + app.packageManager.getAppMetadata(packageName)) if (safetyLabel != null) { SafetyLabelInfo(safetyLabel, installSourcePackageName) } else { @@ -109,49 +115,8 @@ private constructor( postValue(safetyLabelInfo) } - private fun getAppMetadata(): PersistableBundle { - return if (isPlaceholderSafetyLabelDataEnabled()) { - placeholderMetadataBundle() - } else { - app.packageManager.getAppMetadata(packageName) - } - } - - private fun placeholderMetadataBundle(): PersistableBundle { - val approximateLocationBundle = - PersistableBundle().apply { putIntArray("purposes", (1..7).toList().toIntArray()) } - - val locationBundle = - PersistableBundle().apply { - putPersistableBundle( - DataTypeConstants.LOCATION_APPROX_LOCATION, approximateLocationBundle) - } - - val dataSharedBundle = - PersistableBundle().apply { - putPersistableBundle(DataCategoryConstants.CATEGORY_LOCATION, locationBundle) - } - - val dataLabelBundle = - PersistableBundle().apply { - putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, dataSharedBundle) - } - - val safetyLabelBundle = PersistableBundle().apply { - putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION) - putPersistableBundle("data_labels", dataLabelBundle) - } - - return PersistableBundle().apply { - putLong(KEY_VERSION, INITIAL_METADATA_VERSION) - putPersistableBundle("safety_labels", safetyLabelBundle) - } - } - companion object : DataRepositoryForPackage<Pair<String, UserHandle>, SafetyLabelInfoLiveData>( ) { - private const val INITIAL_METADATA_VERSION = 1L - private const val INITIAL_SAFETY_LABELS_VERSION = 1L private val LOG_TAG = SafetyLabelInfoLiveData::class.java.simpleName override fun newValue(key: Pair<String, UserHandle>): SafetyLabelInfoLiveData { diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java index e97c6ef4b..8f73f6577 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java @@ -89,7 +89,7 @@ import java.util.Random; public class GrantPermissionsActivity extends SettingsActivity implements GrantPermissionsViewHandler.ResultListener { - private static final String LOG_TAG = "GrantPermissionsActivit"; + private static final String LOG_TAG = "GrantPermissionsActivity"; private static final String KEY_SESSION_ID = GrantPermissionsActivity.class.getName() + "_REQUEST_ID"; diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java index 007707363..9fad46648 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java @@ -73,7 +73,6 @@ import androidx.lifecycle.ViewModelProvider; import com.android.permissioncontroller.R; import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState; -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo; import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs; import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler; import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel; @@ -87,12 +86,13 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.widget.ActionBarShadowController; +import kotlin.Pair; + import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; -import kotlin.Pair; - /** * Show and manage a single permission group for an app. * @@ -195,10 +195,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader getActivity().getApplication(), mPackageName, mPermGroupName, mUser, mSessionId); mViewModel = new ViewModelProvider(this, factory).get(AppPermissionViewModel.class); Handler delayHandler = new Handler(Looper.getMainLooper()); - if (KotlinUtils.INSTANCE.isPermissionRationaleEnabled()) { - mViewModel.getSafetyLabelInfoLiveData().observe(this, - this::showPermissionRationaleDialog); - } + mViewModel.getShowPermissionRationaleLiveData().observe(this, show -> { + showPermissionRationaleDialog(Optional.ofNullable(show).orElse(false)); + }); mViewModel.getButtonStateLiveData().observe(this, buttonState -> { if (mIsInitialLoad) { setRadioButtonsState(buttonState); @@ -295,11 +294,6 @@ public class AppPermissionFragment extends SettingsWithLargeHeader root.requireViewById(R.id.app_permission_rationale_container); mAppPermissionRationaleContent = root.requireViewById(R.id.app_permission_rationale_content); - if (!KotlinUtils.INSTANCE.isPermissionRationaleEnabled()) { - hidePermissionRationaleContainer(); - } else { - setPermissionRationaleContainer(root, context); - } getActivity().setTitle( getPreferenceManager().getContext().getString(R.string.app_permission_title, @@ -307,19 +301,9 @@ public class AppPermissionFragment extends SettingsWithLargeHeader return root; } - private void setPermissionRationaleContainer(View root, Context context) { - ((TextView) root.requireViewById(R.id.app_permission_rationale_message)).setText( - context.getString(R.string.app_permission_rationale_message)); - ((TextView) root.requireViewById(R.id.app_permission_rationale_title)).setText( - context.getString(R.string.app_location_permission_rationale_title)); - ((TextView) root.requireViewById(R.id.app_permission_rationale_subtitle)).setText( - context.getString(R.string.app_location_permission_rationale_subtitle)); - } - - private void showPermissionRationaleDialog(@Nullable SafetyLabelInfo safetyLabelInfo) { - if (safetyLabelInfo == null - || !mViewModel.shouldShowPermissionRationale(safetyLabelInfo, mPermGroupName)) { - hidePermissionRationaleContainer(); + private void showPermissionRationaleDialog(boolean showPermissionRationale) { + if (!showPermissionRationale) { + mAppPermissionRationaleContainer.setVisibility(View.GONE); } else { mAppPermissionRationaleContainer.setVisibility(View.VISIBLE); mAppPermissionRationaleContent.setOnClickListener((v) -> { @@ -328,10 +312,6 @@ public class AppPermissionFragment extends SettingsWithLargeHeader } } - private void hidePermissionRationaleContainer() { - mAppPermissionRationaleContainer.setVisibility(View.GONE); - } - private void setBottomLinkState(TextView view, String caller, String action) { if ((Objects.equals(caller, AppPermissionGroupsFragment.class.getName()) && action.equals(Intent.ACTION_MANAGE_APP_PERMISSIONS)) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt index ac20a7748..2e1744f54 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt @@ -60,7 +60,6 @@ import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveD import com.android.permissioncontroller.permission.data.get import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs @@ -78,10 +77,8 @@ import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleAct import com.android.permissioncontroller.permission.utils.KotlinUtils import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled -import com.android.permissioncontroller.permission.utils.KotlinUtils.isPermissionRationaleEnabled import com.android.permissioncontroller.permission.utils.LocationUtils import com.android.permissioncontroller.permission.utils.PermissionMapping -import com.android.permissioncontroller.permission.utils.PermissionRationales import com.android.permissioncontroller.permission.utils.SafetyNetLogger import com.android.permissioncontroller.permission.utils.Utils import com.android.permissioncontroller.permission.utils.navigateSafe @@ -114,8 +111,6 @@ class AppPermissionViewModel( const val PHOTO_PICKER_REQUEST_CODE = 1 } - val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] - interface ConfirmDialogShowingFragment { fun showConfirmDialog( changeRequest: ChangeRequest, @@ -184,6 +179,36 @@ class AppPermissionViewModel( val showAdminSupportLiveData = MutableLiveData<RestrictedLockUtils.EnforcedAdmin>() /** + * A livedata for determining the display state of safety label information + */ + val showPermissionRationaleLiveData = object : SmartUpdateMediatorLiveData<Boolean>() { + private val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] + + init { + if (PermissionMapping.isSafetyLabelAwarePermission(permGroupName)) { + addSource(safetyLabelInfoLiveData) { update() } + } else { + value = false + } + } + + override fun onUpdate() { + if (safetyLabelInfoLiveData.isStale) { + return + } + + val safetyLabel = safetyLabelInfoLiveData.value?.safetyLabel + if (safetyLabel == null) { + value = false + return + } + + value = PermissionMapping.getSafetyLabelSharingPurposesForGroup( + safetyLabel, permGroupName).any() + } + } + + /** * A livedata which determines which detail string, if any, should be shown */ val fullStorageStateLiveData = object : SmartUpdateMediatorLiveData<FullStoragePackageState>() { @@ -549,14 +574,6 @@ class AppPermissionViewModel( return true } - fun shouldShowPermissionRationale( - safetyLabelInfo: SafetyLabelInfo, - groupName: String - ): Boolean { - return PermissionRationales.shouldShowPermissionRationale( - safetyLabelInfo.safetyLabel, groupName) - } - /** * Shows the Permission Rationale Dialog. For use with U+ only, otherwise no-op. * @@ -564,10 +581,6 @@ class AppPermissionViewModel( * @param groupName The name of the permission group whose fragment should be opened */ fun showPermissionRationaleActivity(activity: Activity, groupName: String) { - if (!isPermissionRationaleEnabled()) { - return - } - val intent = Intent(activity, PermissionRationaleActivity::class.java).apply { putExtra(Intent.EXTRA_PACKAGE_NAME, packageName) putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt index b82536dd5..01fd079c6 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt @@ -120,9 +120,7 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultP import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions import com.android.permissioncontroller.permission.utils.KotlinUtils.grantForegroundRuntimePermissions import com.android.permissioncontroller.permission.utils.KotlinUtils.isLocationAccuracyEnabled -import com.android.permissioncontroller.permission.utils.KotlinUtils.isPermissionRationaleEnabled import com.android.permissioncontroller.permission.utils.PermissionMapping -import com.android.permissioncontroller.permission.utils.PermissionRationales import com.android.permissioncontroller.permission.utils.SafetyNetLogger import com.android.permissioncontroller.permission.utils.Utils @@ -147,12 +145,16 @@ class GrantPermissionsViewModel( private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName private val user = Process.myUserHandle() private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user] - private val safetyLabelInfoLiveData = SafetyLabelInfoLiveData[packageName, user] + private val safetyLabelInfoLiveData = + if (requestedPermissions.any { PermissionMapping.isSafetyLabelAwarePermission(it) }) { + SafetyLabelInfoLiveData[packageName, user] + } else { + null + } private val dpm = app.getSystemService(DevicePolicyManager::class.java)!! private val permissionPolicy = dpm.getPermissionPolicy(null) private val permGroupsToSkip = mutableListOf<String>() private var groupStates = mutableMapOf<Pair<String, Boolean>, GroupState>() - private val permissionRationaleEnabled: Boolean by lazy { isPermissionRationaleEnabled() } private var autoGrantNotifier: AutoGrantPermissionsNotifier? = null private fun getAutoGrantNotifier(): AutoGrantPermissionsNotifier { @@ -161,7 +163,6 @@ class GrantPermissionsViewModel( } private lateinit var packageInfo: LightPackageInfo - private var safetyLabel: SafetyLabel? = null // All permissions that could possibly be affected by the provided requested permissions, before // filtering system fixed, auto grant, etc. @@ -198,12 +199,10 @@ class GrantPermissionsViewModel( private val LOG_TAG = GrantPermissionsViewModel::class.java.simpleName private val packagePermissionsLiveData = PackagePermissionsLiveData[packageName, user] - // TODO(b/260873483): only query safety label for supported permission groups. should only - // query location, but currently queries for all groups init { addSource(packagePermissionsLiveData) { onPackageLoaded() } addSource(packageInfoLiveData) { onPackageLoaded() } - if (permissionRationaleEnabled) { + if (safetyLabelInfoLiveData != null) { addSource(safetyLabelInfoLiveData) { onPackageLoaded() } } @@ -214,17 +213,10 @@ class GrantPermissionsViewModel( private fun onPackageLoaded() { if (packageInfoLiveData.isStale || packagePermissionsLiveData.isStale || - (permissionRationaleEnabled && safetyLabelInfoLiveData.isStale)) { + (safetyLabelInfoLiveData != null && safetyLabelInfoLiveData.isStale)) { return } - safetyLabel = - if (permissionRationaleEnabled) { - safetyLabelInfoLiveData.value?.safetyLabel - } else { - null - } - val groups = packagePermissionsLiveData.value val pI = packageInfoLiveData.value if (groups == null || groups.isEmpty() || pI == null) { @@ -568,14 +560,15 @@ class GrantPermissionsViewModel( } } + val safetyLabel = safetyLabelInfoLiveData?.value?.safetyLabel + requestInfos.add(RequestInfo( groupInfo, buttonVisibilities, locationVisibilities, message, detailMessage, - showPermissionRationale = shouldShowPermissionRationale( - safetyLabel, groupState))) + shouldShowPermissionRationale(safetyLabel, groupState))) } sortPermissionGroups(requestInfos) @@ -591,6 +584,19 @@ class GrantPermissionsViewModel( } } + private fun shouldShowPermissionRationale( + safetyLabel: SafetyLabel?, + groupState: GroupState + ): Boolean { + if (safetyLabel == null) { + return false + } + + val purposes = PermissionMapping.getSafetyLabelSharingPurposesForGroup(safetyLabel, + groupState.group.permGroupName) + return purposes.isNotEmpty() + } + fun sortPermissionGroups(requestInfos: MutableList<RequestInfo>) { requestInfos.sortWith { rhs, lhs -> val rhsHasOneTime = rhs.buttonVisibilities[ALLOW_ONE_TIME_BUTTON] @@ -607,14 +613,6 @@ class GrantPermissionsViewModel( } } - private fun shouldShowPermissionRationale( - safetyLabel: SafetyLabel?, - groupState: GroupState - ): Boolean { - return PermissionRationales.shouldShowPermissionRationale( - safetyLabel, groupState.group.permGroupName) - } - /** * Converts a list of LightAppPermGroups into a list of GroupStates */ diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt index 8de8de726..54d94f913 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt @@ -29,23 +29,18 @@ import android.util.Log import androidx.annotation.RequiresApi import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.android.permission.safetylabel.DataCategory -import com.android.permission.safetylabel.DataType -import com.android.permission.safetylabel.DataTypeConstants -import com.android.permission.safetylabel.SafetyLabel import com.android.permissioncontroller.Constants import com.android.permissioncontroller.R import com.android.permissioncontroller.permission.data.SafetyLabelInfoLiveData import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData import com.android.permissioncontroller.permission.data.get -import com.android.permissioncontroller.permission.model.livedatatypes.SafetyLabelInfo.Companion.UNAVAILABLE import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity import com.android.permissioncontroller.permission.utils.KotlinUtils import com.android.permissioncontroller.permission.utils.KotlinUtils.getAppStoreIntent -import com.android.permissioncontroller.permission.utils.SafetyLabelPermissionMapping +import com.android.permissioncontroller.permission.utils.PermissionMapping import com.android.settingslib.HelpUtils /** @@ -90,7 +85,7 @@ class PermissionRationaleViewModel( data class PermissionRationaleInfo( val groupName: String, val installSourcePackageName: String?, - val installSourceLabel: CharSequence?, + val installSourceLabel: String?, val purposeSet: Set<Int> ) @@ -111,18 +106,15 @@ class PermissionRationaleViewModel( } val safetyLabelInfo = safetyLabelInfoLiveData.value - val safetyLabel = safetyLabelInfo?.safetyLabel - if (safetyLabelInfo == null || - safetyLabelInfo == UNAVAILABLE || - safetyLabel == null) { + if (safetyLabelInfo?.safetyLabel == null) { Log.e(LOG_TAG, "Safety label for $packageName not found") value = null return } val installSourcePackageName = safetyLabelInfo.installSourcePackageName - val installSourceLabel: CharSequence? = + val installSourceLabel: String? = installSourcePackageName?.let { KotlinUtils.getPackageLabel(app, it, Process.myUserHandle()) } @@ -132,36 +124,8 @@ class PermissionRationaleViewModel( permissionGroupName, installSourcePackageName, installSourceLabel, - getSafetyLabelSharingPurposesForGroup(safetyLabel, permissionGroupName)) - } - - private fun getSafetyLabelSharingPurposesForGroup( - safetyLabel: SafetyLabel, - groupName: String - ): Set<Int> { - val purposeSet = mutableSetOf<Int>() - val categoriesForPermission: List<String> = - SafetyLabelPermissionMapping.getCategoriesForPermissionGroup(groupName) - categoriesForPermission.forEach categoryLoop@{ category -> - val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] - if (dataCategory == null) { - // Continue to next - return@categoryLoop - } - val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) - typesForCategory.forEach typeLoop@{ type -> - val dataType: DataType? = dataCategory.dataTypes[type] - if (dataType == null) { - // Continue to next - return@typeLoop - } - if (dataType.purposeSet.isNotEmpty()) { - purposeSet.addAll(dataType.purposeSet) - } - } - } - - return purposeSet + PermissionMapping.getSafetyLabelSharingPurposesForGroup( + safetyLabelInfo.safetyLabel, permissionGroupName)) } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt index 3fde87108..45a7fb02e 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt @@ -21,7 +21,13 @@ import android.content.pm.PackageManager import android.content.pm.PermissionInfo import android.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP import android.util.Log + import com.android.modules.utils.build.SdkLevel +import com.android.permission.safetylabel.DataCategory +import com.android.permission.safetylabel.DataCategoryConstants +import com.android.permission.safetylabel.DataType +import com.android.permission.safetylabel.DataTypeConstants +import com.android.permission.safetylabel.SafetyLabel /** * This file contains the canonical mapping of permission to permission group, used in the @@ -31,6 +37,9 @@ object PermissionMapping { private val LOG_TAG = "PermissionMapping" + private val PERMISSION_GROUPS_TO_DATA_CATEGORIES: Map<String, List<String>> = mapOf( + Manifest.permission_group.LOCATION to listOf(DataCategoryConstants.CATEGORY_LOCATION)) + @JvmField val SENSOR_DATA_PERMISSIONS: List<String> = listOf( @@ -326,4 +335,64 @@ object PermissionMapping { fun isHealthPermission(permissionName: String): Boolean { return HEALTH_PERMISSIONS_SET.contains(permissionName) } + + /** + * Get the sharing purposes for a SafetyLabel related to a specific permission group. + */ + @JvmStatic + fun getSafetyLabelSharingPurposesForGroup( + safetyLabel: SafetyLabel, + groupName: String + ): Set<Int> { + val purposeSet = mutableSetOf<Int>() + val categoriesForPermission = getDataCategoriesForPermissionGroup(groupName) + categoriesForPermission.forEach categoryLoop@{ category -> + val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] + if (dataCategory == null) { + // Continue to next + return@categoryLoop + } + val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) + typesForCategory.forEach typeLoop@{ type -> + val dataType: DataType? = dataCategory.dataTypes[type] + if (dataType == null) { + // Continue to next + return@typeLoop + } + if (dataType.purposeSet.isNotEmpty()) { + purposeSet.addAll(dataType.purposeSet) + } + } + } + + return purposeSet + } + + /** + * Get the SafetyLabel categories pertaining to a specified permission group. + * + * @return The categories, or an empty list if the group does not have a supported mapping + * to safety label category + */ + fun getDataCategoriesForPermissionGroup(permissionGroupName: String): List<String> { + return if (isSafetyLabelAwarePermission(permissionGroupName)) { + PERMISSION_GROUPS_TO_DATA_CATEGORIES[permissionGroupName] ?: emptyList() + } else { + emptyList() + } + } + + /** + * Whether this permission group maps to a SafetyLabel data category. + * + * @param permissionGroupName the permission group name + */ + @JvmStatic + fun isSafetyLabelAwarePermission(permissionGroupName: String): Boolean { + if (!KotlinUtils.isPermissionRationaleEnabled()) { + return false + } + + return PERMISSION_GROUPS_TO_DATA_CATEGORIES.containsKey(permissionGroupName) + } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt deleted file mode 100644 index ede87e84f..000000000 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionRationales.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.permissioncontroller.permission.utils - -import com.android.permission.safetylabel.DataCategory -import com.android.permission.safetylabel.DataType -import com.android.permission.safetylabel.DataTypeConstants -import com.android.permission.safetylabel.SafetyLabel - -/** - * A set of util functions used for permission rationale dialog. - */ -object PermissionRationales { - - /** - * Returns if the permission rationale dialog should be shown. - * @param safetyLabel the [SafetyLabel] bundle provided - * @param groupName the permission group name - * @return true if the permission dialog should be shown, otherwise false. - */ - fun shouldShowPermissionRationale( - safetyLabel: SafetyLabel?, - groupName: String - ): Boolean { - if (safetyLabel == null || safetyLabel.dataLabel.dataShared.isEmpty()) { - return false - } - val categoriesForPermission: List<String> = - SafetyLabelPermissionMapping.getCategoriesForPermissionGroup(groupName) - categoriesForPermission.forEach categoryLoop@{ category -> - val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category] - if (dataCategory == null) { - // Continue to next - return@categoryLoop - } - val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category) - typesForCategory.forEach typeLoop@{ type -> - val dataType: DataType? = dataCategory.dataTypes[type] - if (dataType == null) { - // Continue to next - return@typeLoop - } - if (dataType.purposeSet.isNotEmpty()) { - return true - } - } - } - return false - } -}
\ No newline at end of file diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt deleted file mode 100644 index 5fd852bb6..000000000 --- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SafetyLabelPermissionMapping.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2022 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.permissioncontroller.permission.utils - -import android.Manifest -import com.android.permission.safetylabel.DataCategoryConstants - -/** - * This file contains the canonical mapping of permission and permission group to Safety Label - * categories and types used in the Permission settings screens and grant dialog. It also includes - * methods related to that mapping. - */ -object SafetyLabelPermissionMapping { - - /** - * Get the Safety Label categories pertaining to a specified permission group. - * - * @param groupName the permission group name - * - * @return The categories or an empty list if the group does not have supported and mapped group - * to safety label category - */ - fun getCategoriesForPermissionGroup(groupName: String): List<String> { - return if (groupName == Manifest.permission_group.LOCATION) { - listOf(DataCategoryConstants.CATEGORY_LOCATION) - } else { - emptyList() - } - } -} diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java index 564d5479f..676cfa6d7 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/DataLabel.java @@ -32,7 +32,10 @@ import java.util.Map; * {@link DataCategory} */ public class DataLabel { - @VisibleForTesting static final String KEY_DATA_LABEL = "data_labels"; + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + static final String KEY_DATA_LABEL = "data_labels"; + private final Map<String, DataCategory> mDataCollected; private final Map<String, DataCategory> mDataShared; diff --git a/SafetyLabel/java/com/android/permission/safetylabel/DataType.java b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java index 68770f823..3350a5942 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/DataType.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/DataType.java @@ -35,7 +35,10 @@ import java.util.Set; * metadata related to the data usage purpose. */ public class DataType { - @VisibleForTesting static final String KEY_PURPOSES = "purposes"; + + @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) + static final String KEY_PURPOSES = "purposes"; + @VisibleForTesting static final String KEY_IS_COLLECTION_OPTIONAL = "is_collection_optional"; @VisibleForTesting static final String KEY_EPHEMERAL = "ephemeral"; diff --git a/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java index 3eb8767b9..0ada11719 100644 --- a/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java +++ b/SafetyLabel/java/com/android/permission/safetylabel/SafetyLabel.java @@ -28,6 +28,10 @@ import java.util.Locale; /** Safety Label representation containing zero or more {@link DataCategory} for data shared */ public class SafetyLabel { private static final String TAG = "SafetyLabel"; + + private static final long INITIAL_METADATA_VERSION = 1L; + private static final long INITIAL_SAFETY_LABELS_VERSION = 1L; + @VisibleForTesting static final String KEY_SAFETY_LABEL = "safety_labels"; public static final String KEY_VERSION = "version"; private final DataLabel mDataLabel; @@ -69,6 +73,44 @@ public class SafetyLabel { return new SafetyLabel(dataLabel); } + /** + * Create a placeholder SafetyLabel for use for testing. + * This is accessible through device configs. + */ + @NonNull + public static SafetyLabel getPlaceholderSafetyLabel() { + return getSafetyLabelFromMetadata(getPlaceholderMetadataBundle()); + } + + @NonNull + private static PersistableBundle getPlaceholderMetadataBundle() { + PersistableBundle approximateLocationBundle = new PersistableBundle(); + approximateLocationBundle.putIntArray(DataType.KEY_PURPOSES, + new int[] { 1, 2, 3, 4, 5, 6, 7 }); + + PersistableBundle locationBundle = new PersistableBundle(); + locationBundle.putPersistableBundle(DataTypeConstants.LOCATION_APPROX_LOCATION, + approximateLocationBundle); + + PersistableBundle dataSharedBundle = new PersistableBundle(); + dataSharedBundle.putPersistableBundle(DataCategoryConstants.CATEGORY_LOCATION, + locationBundle); + + PersistableBundle dataLabelBundle = new PersistableBundle(); + dataLabelBundle.putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, + dataSharedBundle); + + PersistableBundle safetyLabelBundle = new PersistableBundle(); + safetyLabelBundle.putLong(KEY_VERSION, INITIAL_SAFETY_LABELS_VERSION); + safetyLabelBundle.putPersistableBundle(DataLabel.KEY_DATA_LABEL, dataLabelBundle); + + PersistableBundle metadataBundle = new PersistableBundle(); + metadataBundle.putLong(KEY_VERSION, INITIAL_METADATA_VERSION); + metadataBundle.putPersistableBundle(KEY_SAFETY_LABEL, safetyLabelBundle); + + return metadataBundle; + } + /** Returns the data label for the safety label */ @NonNull public DataLabel getDataLabel() { |