summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/res/values-v34/styles.xml1
-rw-r--r--PermissionController/res/xml/roles.xml8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/Constants.java15
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt12
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java43
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java7
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt3
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt74
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt165
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt59
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt6
-rw-r--r--service/java/com/android/safetycenter/SafetyCenterDataFactory.java12
18 files changed, 400 insertions, 119 deletions
diff --git a/PermissionController/res/values-v34/styles.xml b/PermissionController/res/values-v34/styles.xml
index f427d1a8e..cc119a331 100644
--- a/PermissionController/res/values-v34/styles.xml
+++ b/PermissionController/res/values-v34/styles.xml
@@ -149,6 +149,7 @@
<item name="android:gravity">center</item>
<item name="android:insetTop">6dp</item>
<item name="android:insetBottom">6dp</item>
+ <item name="android:minWidth">48dp</item>
<item name="android:minHeight">48dp</item>
<item name="android:paddingTop">8dp</item>
<item name="android:paddingBottom">8dp</item>
diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml
index d225d296a..dc884e810 100644
--- a/PermissionController/res/xml/roles.xml
+++ b/PermissionController/res/xml/roles.xml
@@ -68,12 +68,8 @@
</permission-set>
<permission-set name="sensors">
- <permission name="android.permission.BODY_SENSORS"/>
- <permission name="android.permission.BODY_SENSORS_BACKGROUND" minSdkVersion="33"/>
- <permission name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE"
- minSdkVersion="34"/>
- <permission name="android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND"
- minSdkVersion="34"/>
+ <permission name="android.permission.BODY_SENSORS" />
+ <permission name="android.permission.BODY_SENSORS_BACKGROUND" minSdkVersion="33" />
</permission-set>
<permission-set name="storage">
diff --git a/PermissionController/src/com/android/permissioncontroller/Constants.java b/PermissionController/src/com/android/permissioncontroller/Constants.java
index e16f8d758..3995b608e 100644
--- a/PermissionController/src/com/android/permissioncontroller/Constants.java
+++ b/PermissionController/src/com/android/permissioncontroller/Constants.java
@@ -312,4 +312,19 @@ public class Constants {
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
"android:receive_ambient_trigger_audio";
+
+ /**
+ * Extra used by Settings to indicate an Intent should be treated as if opened directly by
+ * Settings app itself.
+ */
+ public static final String EXTRA_FROM_SETTINGS = "is_from_settings_homepage";
+
+ /**
+ * Extra used by Settings to indicate an Intent should be treated as if opened by a slice
+ * within Settings.
+ *
+ * <p>Slices are opened within settings by firing a PendingIntent, so we can use this extra to
+ * allow the same UX path to be taken as for slices.
+ */
+ public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
index 82620058d..001520c1b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
@@ -34,6 +34,7 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Process;
@@ -50,6 +51,7 @@ import android.util.Xml;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.android.permissioncontroller.PermissionControllerProto.PermissionControllerDumpProto;
import com.android.permissioncontroller.PermissionControllerStatsLog;
@@ -777,6 +779,7 @@ public final class PermissionControllerServiceImpl extends PermissionControllerL
}
@Override
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public void onRevokeSelfPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions, @NonNull Runnable callback) {
PackageInfo pkgInfo = getPkgInfo(packageName);
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 91b6de077..cc44a400b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
@@ -85,6 +85,7 @@ import com.android.permissioncontroller.permission.utils.PermissionMapping.getPa
import com.android.permissioncontroller.permission.utils.SafetyNetLogger
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.navigateSafe
+import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
import com.android.settingslib.RestrictedLockUtils
import java.util.Random
import kotlin.collections.component1
@@ -206,7 +207,7 @@ class AppPermissionViewModel(
return
}
- value = PermissionMapping.getSafetyLabelSharingPurposesForGroup(
+ value = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
safetyLabel, permGroupName).any()
}
}
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 3a689fd72..c6d89876b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
@@ -130,6 +130,7 @@ import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.PermissionMapping.getPartialStorageGrantPermissionsForGroup
import com.android.permissioncontroller.permission.utils.SafetyNetLogger
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
/**
* ViewModel for the GrantPermissionsActivity. Tracks all permission groups that are affected by
@@ -626,7 +627,7 @@ class GrantPermissionsViewModel(
return false
}
- val purposes = PermissionMapping.getSafetyLabelSharingPurposesForGroup(safetyLabel,
+ val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(safetyLabel,
permissionGroupName)
return purposes.isNotEmpty()
}
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 3d205a270..561a8eef2 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
@@ -46,7 +46,7 @@ import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.
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.PermissionMapping
+import com.android.permissioncontroller.permission.utils.v34.SafetyLabelUtils
import com.android.settingslib.HelpUtils
/**
@@ -124,7 +124,7 @@ class PermissionRationaleViewModel(
KotlinUtils.getPackageLabel(app, it, Process.myUserHandle())
}
- val purposes = PermissionMapping.getSafetyLabelSharingPurposesForGroup(
+ val purposes = SafetyLabelUtils.getSafetyLabelSharingPurposesForGroup(
safetyLabelInfo.safetyLabel, permissionGroupName)
if (value == null) {
logPermissionRationaleDialogViewed(purposes)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
index 1d73ac959..a9d8c4e12 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt
@@ -304,18 +304,6 @@ object KotlinUtils {
PROPERTY_SAFETY_LABEL_CHANGES_JOB_SERVICE_KILL_SWITCH, false)
}
- /**
- * The minimum amount of time to wait, after scheduling the safety label changes job, before
- * the job actually runs for the first time.
- */
- @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
- fun getSafetyLabelChangesJobDelayMillis(): Long {
- return DeviceConfig.getLong(
- DeviceConfig.NAMESPACE_PRIVACY,
- PROPERTY_SAFETY_LABEL_CHANGES_JOB_DELAY_MILLIS,
- Duration.ofMinutes(30).toMillis())
- }
-
/** How often the safety label changes job will run. */
@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "UpsideDownCake")
fun getSafetyLabelChangesJobIntervalMillis(): Long {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
index c4355b1e5..b06a09b28 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/PermissionMapping.kt
@@ -26,11 +26,7 @@ import android.util.Log
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup
-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
@@ -187,13 +183,6 @@ object PermissionMapping {
Manifest.permission_group.SENSORS
}
- if (SdkLevel.isAtLeastU()) {
- PLATFORM_PERMISSIONS[Utils.BODY_SENSORS_WRIST_TEMPERATURE] =
- Manifest.permission_group.SENSORS
- PLATFORM_PERMISSIONS[Utils.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND] =
- Manifest.permission_group.SENSORS
- }
-
for ((permission, permissionGroup) in PLATFORM_PERMISSIONS) {
PLATFORM_PERMISSION_GROUPS.getOrPut(permissionGroup) { mutableListOf() }.add(permission)
}
@@ -390,38 +379,6 @@ object PermissionMapping {
return AppOpsManager.opToPermission(opName)?.let { getGroupOfPlatformPermission(it) }
}
- /*
- * 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.
*
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index b0aaac9ea..d4354bd72 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
@@ -76,7 +76,6 @@ import android.hardware.SensorPrivacyManager;
import android.os.Binder;
import android.os.Build;
import android.os.Parcelable;
-import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -110,8 +109,6 @@ import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightAppPermGroup;
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo;
-import kotlin.Triple;
-
import java.lang.annotation.Retention;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
@@ -123,6 +120,8 @@ import java.util.Locale;
import java.util.Random;
import java.util.Set;
+import kotlin.Triple;
+
public final class Utils {
@Retention(SOURCE)
@@ -253,12 +252,6 @@ public final class Utils {
private static final String SYSTEM_VISUAL_INTELLIGENCE =
"android.app.role.SYSTEM_VISUAL_INTELLIGENCE";
- public static final String BODY_SENSORS_WRIST_TEMPERATURE =
- "android.permission.BODY_SENSORS_WRIST_TEMPERATURE";
-
- public static final String BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND =
- "android.permission.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND";
-
// TODO: theianchen Using hardcoded values here as a WIP solution for now.
private static final String[] EXEMPTED_ROLES = {
SYSTEM_AMBIENT_AUDIO_INTELLIGENCE,
@@ -1069,38 +1062,6 @@ public final class Utils {
}
/**
- * Checks whether a package has an active one-time permission according to the system server's
- * flags
- *
- * @param context the {@code Context} to retrieve {@code PackageManager}
- * @param packageName The package to check for
- * @return Whether a package has an active one-time permission
- */
- public static boolean hasOneTimePermissions(Context context, String packageName) {
- String[] permissions;
- PackageManager pm = context.getPackageManager();
- try {
- permissions = pm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS)
- .requestedPermissions;
- } catch (NameNotFoundException e) {
- Log.w(LOG_TAG, "Checking for one-time permissions in nonexistent package");
- return false;
- }
- if (permissions == null) {
- return false;
- }
- for (String permissionName : permissions) {
- if ((pm.getPermissionFlags(permissionName, packageName, Process.myUserHandle())
- & PackageManager.FLAG_PERMISSION_ONE_TIME) != 0
- && pm.checkPermission(permissionName, packageName)
- == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- }
- return false;
- }
-
- /**
* Returns a random session ID value that's guaranteed to not be {@code INVALID_SESSION_ID}.
*
* @return A valid session ID.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
index e9d68c9c6..9b7927c1d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
@@ -53,13 +53,6 @@ public final class AdminRestrictedPermissionsUtils {
if (SdkLevel.isAtLeastT()) {
ADMIN_RESTRICTED_SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND);
}
- // New U permissions - do not add unless running on U and above.
- if (SdkLevel.isAtLeastU()) {
- ADMIN_RESTRICTED_SENSORS_PERMISSIONS.add(
- Utils.BODY_SENSORS_WRIST_TEMPERATURE);
- ADMIN_RESTRICTED_SENSORS_PERMISSIONS.add(
- Utils.BODY_SENSORS_WRIST_TEMPERATURE_BACKGROUND);
- }
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
new file mode 100644
index 000000000..5dbe203f9
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v34/SafetyLabelUtils.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.v34
+
+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.permission.utils.PermissionMapping
+
+object SafetyLabelUtils {
+ /*
+ * 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 = PermissionMapping
+ .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
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
index 11881e3ab..4ba685589 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/AccessibilitySourceService.kt
@@ -420,7 +420,7 @@ class AccessibilitySourceService(
// Start this Settings activity using the same UX that settings slices uses. This allows
// settings to correctly support 2-pane layout with as-best-as-possible transition
// animation.
- intent.putExtra(EXTRA_IS_FROM_SLICE, true)
+ intent.putExtra(Constants.EXTRA_IS_FROM_SLICE, true)
return PendingIntent.getActivity(
context,
0,
@@ -649,7 +649,6 @@ class AccessibilitySourceService(
private const val PROPERTY_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS =
"sc_accessibility_job_interval_millis"
private val DEFAULT_SC_ACCESSIBILITY_JOB_INTERVAL_MILLIS = TimeUnit.DAYS.toMillis(1)
- private val EXTRA_IS_FROM_SLICE = "is_from_slice"
private val sourceStateChanged = SafetyEvent.Builder(
SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
new file mode 100644
index 000000000..305dcdfb7
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/ArrayUtilsTest.kt
@@ -0,0 +1,74 @@
+/*
+ * 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.util
+
+import com.android.permissioncontroller.permission.utils.ArrayUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ArrayUtilsTest {
+ @Test
+ fun appendString_appendToNull_returnsArrayWithString() {
+ assertThat(ArrayUtils.appendString(null, TEST_STRING))
+ .isEqualTo(arrayOf(TEST_STRING))
+ }
+
+ @Test
+ fun appendString_appendToNull_returnsArrayWithNull() {
+ val result = ArrayUtils.appendString(null, null)
+ assertThat(result.size).isEqualTo(1)
+ assertThat(result[0]).isEqualTo(null)
+ }
+
+ @Test
+ fun appendString_duplicatedString_returnsArray() {
+ val cur = arrayOf("a", "b", TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(cur)
+ }
+
+ @Test
+ fun appendString_appendNull_returnsArray() {
+ val cur = arrayOf("a", "b", null)
+ assertThat(ArrayUtils.appendString(cur, null)).isEqualTo(cur)
+ }
+
+ @Test
+ fun appendString_appendToEmptyArray_returnsArrayWithNewString() {
+ val cur = arrayOf<String>()
+ val new = arrayOf(TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(new)
+ }
+
+ @Test
+ fun appendString_appendNullToEmptyArray_returnsArrayWithNewString() {
+ val cur = arrayOf<String>()
+ val result = ArrayUtils.appendString(cur, null)
+ assertThat(result.size).isEqualTo(1)
+ assertThat(result[0]).isNull()
+ }
+
+ @Test
+ fun appendString_appendNewString() {
+ val cur = arrayOf("old test")
+ val new = arrayOf("old test", TEST_STRING)
+ assertThat(ArrayUtils.appendString(cur, TEST_STRING)).isEqualTo(new)
+ }
+
+ companion object {
+ private const val TEST_STRING = "test"
+ }
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
new file mode 100644
index 000000000..8f54da579
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/KotlinUtilsTest.kt
@@ -0,0 +1,165 @@
+/*
+ * 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.util
+
+import android.Manifest.permission.READ_MEDIA_IMAGES
+import android.Manifest.permission.READ_MEDIA_VIDEO
+import android.content.Context
+import android.content.Intent
+import android.content.Intent.ACTION_SHOW_APP_INFO
+import android.content.Intent.EXTRA_PACKAGE_NAME
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.ColorFilter
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.permissioncontroller.permission.utils.KotlinUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.argThat
+import org.mockito.Mockito.mock
+import kotlin.test.assertFailsWith
+import org.mockito.Mockito.`when` as whenever
+
+/**
+ * Unit tests for [KotlinUtils].
+ */
+@RunWith(AndroidJUnit4::class)
+class KotlinUtilsTest {
+ private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext
+
+ @Test
+ fun convertToBitmap_argb888BitmapDrawable_returnsSameBitmap() {
+ val bitmap = Bitmap.createBitmap(/* width= */ 5, /* height= */ 10, Bitmap.Config.ARGB_8888)
+ val drawable = BitmapDrawable(targetContext.resources, bitmap)
+
+ assertThat(KotlinUtils.convertToBitmap(drawable).sameAs(bitmap)).isTrue()
+ }
+
+ @Test
+ fun convertToBitmap_noIntrinsicSize_throws() {
+ val drawable = FakeDrawable(intrinsicSize = 0)
+ assertFailsWith<IllegalArgumentException> { KotlinUtils.convertToBitmap(drawable) }
+ }
+
+ class FakeDrawable(private val intrinsicSize: Int) : Drawable() {
+ override fun getIntrinsicWidth() = intrinsicSize
+ override fun getIntrinsicHeight() = intrinsicSize
+
+ override fun draw(canvas: Canvas) = Unit // no-op
+ override fun getOpacity() = throw UnsupportedOperationException()
+ override fun setAlpha(alpha: Int) = throw UnsupportedOperationException()
+ override fun setColorFilter(colorFilter: ColorFilter?) =
+ throw UnsupportedOperationException()
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsResolvedIntent() {
+ val installerPackage = "installer"
+ val installerActivity = "activity"
+ val appPackage = "app"
+ val mockContext = mock(Context::class.java)
+ val mockPackageManager = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(mockPackageManager)
+ val installerIntent = Intent(ACTION_SHOW_APP_INFO).setPackage(installerPackage)
+ whenever(
+ mockPackageManager.resolveActivity(
+ argThat { intent -> intent.filterEquals(installerIntent) }, /* flags= */ anyInt()))
+ .thenReturn(ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply {
+ packageName = installerPackage
+ name = installerActivity
+ }
+ })
+
+ val intent = KotlinUtils.getAppStoreIntent(mockContext, installerPackage, appPackage)
+
+ assertThat(intent).isNotNull()
+ with (intent!!) {
+ assertThat(action).isEqualTo(ACTION_SHOW_APP_INFO)
+ assertThat(component?.packageName).isEqualTo(installerPackage)
+ assertThat(component?.className).isEqualTo(installerActivity)
+ }
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsAppPackageInExtras() {
+ val appPackage = "app"
+ val mockContext = mock(Context::class.java)
+ val mockPackageManager = mock(PackageManager::class.java)
+ whenever(mockContext.packageManager).thenReturn(mockPackageManager)
+ whenever(
+ mockPackageManager.resolveActivity(any(), /* flags= */ anyInt()))
+ .thenReturn(ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply {
+ packageName = ""
+ name = ""
+ }
+ })
+
+ val intent = KotlinUtils.getAppStoreIntent(mockContext, "com.installer", appPackage)
+
+ assertThat(intent).isNotNull()
+ assertThat(intent?.extras?.getString(EXTRA_PACKAGE_NAME)).isEqualTo(appPackage)
+ }
+
+ @Test
+ fun getAppStoreIntent_returnsNullWhenInstallerNotResolved() {
+ val mockContext = mock(Context::class.java)
+ whenever(mockContext.packageManager).thenReturn(mock(PackageManager::class.java))
+ // Un-stubbed activity resolution will return null.
+
+ assertThat(KotlinUtils.getAppStoreIntent(mockContext, "com.installer", "com.app")).isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_onlyReadMediaImages_returnsImage() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, "read memes")))
+ .isEqualTo("image/*")
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_onlyReadMediaVideo_returnsVideo() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf("write memes", READ_MEDIA_VIDEO)))
+ .isEqualTo("video/*")
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_bothReadMediaPermissions_returnsNull() {
+ assertThat(
+ KotlinUtils.getMimeTypeForPermissions(listOf(READ_MEDIA_IMAGES, READ_MEDIA_VIDEO)))
+ .isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_noReadMediaPermissions_returnsNull() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(listOf("amazing permission"))).isNull()
+ }
+
+ @Test
+ fun getMimeTypeForPermissions_emptyList_returnsNull() {
+ assertThat(KotlinUtils.getMimeTypeForPermissions(emptyList())).isNull()
+ }
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt
new file mode 100644
index 000000000..64a13df60
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/PermissionMappingTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.util
+
+import android.Manifest
+import android.app.AppOpsManager
+import android.health.connect.HealthPermissions
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.permissioncontroller.permission.utils.PermissionMapping
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class PermissionMappingTest {
+ @Test
+ fun testGetPlatformPermissionGroupForOp_healthPermissionGroup() {
+ assertThat(PermissionMapping.getPlatformPermissionGroupForOp(
+ AppOpsManager.OPSTR_READ_WRITE_HEALTH_DATA
+ )).isEqualTo(HealthPermissions.HEALTH_PERMISSION_GROUP)
+ }
+
+ @Test
+ fun testGetPlatformPermissionGroupForOp_microphone() {
+ assertThat(PermissionMapping.getPlatformPermissionGroupForOp(
+ AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
+ )).isEqualTo(Manifest.permission_group.MICROPHONE)
+ }
+
+ @Test
+ fun testGetPlatformPermissionGroupForOp_camera() {
+ assertThat(
+ PermissionMapping.getPlatformPermissionGroupForOp(AppOpsManager.OPSTR_PHONE_CALL_CAMERA)
+ ).isEqualTo(Manifest.permission_group.CAMERA)
+ }
+
+ @Test
+ fun testGetPlatformPermissionGroupForOp_readContacts() {
+ assertThat(
+ PermissionMapping.getPlatformPermissionGroupForOp(AppOpsManager.OPSTR_READ_CONTACTS)
+ ).isEqualTo(
+ PermissionMapping.getGroupOfPlatformPermission(Manifest.permission.READ_CONTACTS)
+ )
+ }
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
index 9cd6da588..15218024e 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
@@ -45,6 +45,7 @@ import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.privacysources.WorkPolicyInfo
import com.google.common.truth.Truth.assertThat
+import org.junit.Ignore
import org.junit.Test
import kotlin.test.assertFailsWith
@@ -78,7 +79,7 @@ class UtilsTest {
fun getAbsoluteTimeString_previousDateTime_returnsDateFormatString() {
val lastAccessTime = 1680739840723L
val time = Utils.getAbsoluteTimeString(context, lastAccessTime)
- assertThat(time).isEqualTo("Apr 5, 2023")
+ assertThat(time == "Apr 5, 2023" || time == "Apr 6, 2023").isTrue()
}
@Test
@@ -107,6 +108,7 @@ class UtilsTest {
}
@Test
+ @Ignore("b/277782895")
fun getEnterpriseString() {
assertThat(Utils.getEnterpriseString(context, WorkPolicyInfo.WORK_POLICY_TITLE,
R.string.work_policy_title)).isInstanceOf(String::class.java)
@@ -184,7 +186,7 @@ class UtilsTest {
@Test
fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Days() {
val result = Utils.getPermissionLastAccessSummaryTimestamp(
- System.currentTimeMillis() - 6 * 24 * 60 * 60 * 1000, context, LOCATION)
+ System.currentTimeMillis() - 5 * 24 * 60 * 60 * 1000, context, LOCATION)
assertThat(result.first).isNotEmpty()
assertThat(result.second).isEqualTo(Utils.LAST_7D_SENSOR)
assertThat(result.third).isNotEmpty()
diff --git a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
index 5d03fa299..5d2d1ca88 100644
--- a/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
+++ b/service/java/com/android/safetycenter/SafetyCenterDataFactory.java
@@ -597,7 +597,7 @@ public final class SafetyCenterDataFactory {
}
PendingIntent entryPendingIntent = safetySourceStatus.getPendingIntent();
boolean enabled = safetySourceStatus.isEnabled() && !inQuietMode;
- if (entryPendingIntent == null) {
+ if (entryPendingIntent == null || inQuietMode) {
entryPendingIntent =
mPendingIntentFactory.getPendingIntent(
safetySource.getId(),
@@ -809,7 +809,15 @@ public final class SafetyCenterDataFactory {
mSafetyCenterDataManager.getSafetySourceDataInternal(key));
boolean inQuietMode = isUserManaged && !isManagedUserRunning;
if (safetySourceStatus != null) {
- PendingIntent pendingIntent = safetySourceStatus.getPendingIntent();
+ PendingIntent pendingIntent =
+ inQuietMode
+ ? mPendingIntentFactory.getPendingIntent(
+ safetySource.getId(),
+ safetySource.getIntentAction(),
+ safetySource.getPackageName(),
+ userId,
+ true)
+ : safetySourceStatus.getPendingIntent();
if (pendingIntent == null) {
// TODO(b/222838784): Decide strategy for static entries when the intent is
// null.