Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
index bb49e15..1868687 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/data/HibernationSettingStateLiveData.kt
@@ -27,7 +27,6 @@
import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState
import com.android.permissioncontroller.hibernation.ExemptServicesLiveData
import com.android.permissioncontroller.hibernation.HibernationEnabledLiveData
-import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.hibernation.isHibernationJobEnabled
import com.android.permissioncontroller.hibernation.isPackageHibernationExemptByUser
import com.android.permissioncontroller.hibernation.isPackageHibernationExemptBySystem
@@ -102,8 +101,7 @@
}
}
- postValue(HibernationSettingState(isHibernationJobEnabled(), canHibernate, revocableGroups,
- isHibernationEnabled() || revocableGroups.isNotEmpty()))
+ postValue(HibernationSettingState(isHibernationJobEnabled(), canHibernate, revocableGroups))
}
override fun onOpChanged(op: String?, packageName: String?) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionUsage.java b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionUsage.java
index eec91f0..e9e5a99 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionUsage.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/AppPermissionUsage.java
@@ -20,23 +20,31 @@
import android.Manifest;
import android.app.AppOpsManager;
+import android.app.AppOpsManager.AttributedHistoricalOps;
+import android.app.AppOpsManager.AttributedOpEntry;
import android.app.AppOpsManager.HistoricalOp;
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.OpEntry;
import android.app.AppOpsManager.OpEventProxyInfo;
import android.app.AppOpsManager.PackageOps;
+import android.content.pm.Attribution;
import android.media.AudioRecordingConfiguration;
+import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.function.Function;
+import java.util.stream.Collectors;
import kotlin.Triple;
@@ -129,7 +137,7 @@
* Stats for permission usage of a permission group. This data is for a
* given time period, i.e. does not contain the full history.
*/
- public static class GroupUsage {
+ public static class GroupUsage implements TimelineUsage {
private final @NonNull AppPermissionGroup mGroup;
private final @Nullable PackageOps mLastUsage;
private final @Nullable HistoricalPackageOps mHistoricalUsage;
@@ -219,9 +227,7 @@
}
- /**
- * returns whether the usage has discrete data
- */
+ @Override
public boolean hasDiscreteData() {
if (mHistoricalUsage == null) {
return false;
@@ -234,14 +240,10 @@
return true;
}
}
-
return false;
}
- /**
- * get all discrete access time in millis
- * Returns a list of triples of (access time, access duration, proxy)
- */
+ @Override
public List<Triple<Long, Long, OpEventProxyInfo>> getAllDiscreteAccessTime() {
List<Triple<Long, Long, OpEventProxyInfo>> allDiscreteAccessTime = new ArrayList<>();
if (!hasDiscreteData()) {
@@ -340,13 +342,17 @@
return allOps;
}
+ @Override
public @NonNull AppPermissionGroup getGroup() {
return mGroup;
}
- /**
- * Returns attribution tags for the historical usage.
- */
+ @Override
+ public int getLabel() {
+ return -1;
+ }
+
+ @Override
public @Nullable ArrayList<String> getAttributionTags() {
if (mHistoricalUsage == null || mHistoricalUsage.getAttributedOpsCount() == 0) {
return null;
@@ -358,6 +364,143 @@
}
return attributionTags;
}
+
+ /** Creates a lookup from the attribution tag to its label. **/
+ @RequiresApi(Build.VERSION_CODES.S)
+ private static Map<String, Integer> getAttributionTagToLabelMap(
+ Attribution[] attributions) {
+ Map<String, Integer> attributionTagToLabelMap = new HashMap<>();
+ for (Attribution attribution : attributions) {
+ attributionTagToLabelMap.put(attribution.getTag(), attribution.getLabel());
+ }
+ return attributionTagToLabelMap;
+ }
+
+ /** Partitions the usages based on the attribution tag label. */
+ @RequiresApi(Build.VERSION_CODES.S)
+ public List<AttributionLabelledGroupUsage> getAttributionLabelledGroupUsages() {
+ Map<String, Integer> attributionTagToLabelMap =
+ getAttributionTagToLabelMap(getGroup().getApp().attributions);
+
+ Set<String> allOps = getAllOps(mGroup);
+
+ // we need to collect discreteAccessTime for each label
+ Map<Integer, AttributionLabelledGroupUsage.Builder> labelDiscreteAccessMap =
+ new HashMap<>();
+
+ for (int i = 0; i < mHistoricalUsage.getAttributedOpsCount(); i++) {
+ AttributedHistoricalOps attributedOp = mHistoricalUsage.getAttributedOpsAt(i);
+ String attributionTag = attributedOp.getTag();
+
+ for (String opName : allOps) {
+ final HistoricalOp historicalOp = attributedOp.getOp(opName);
+ if (historicalOp == null) {
+ continue;
+ }
+
+ int discreteAccessCount = historicalOp.getDiscreteAccessCount();
+ for (int j = 0; j < discreteAccessCount; j++) {
+ AttributedOpEntry opEntry = historicalOp.getDiscreteAccessAt(j);
+ Integer label = attributionTagToLabelMap.get(attributedOp.getTag());
+ if (!labelDiscreteAccessMap.containsKey(label)) {
+ labelDiscreteAccessMap.put(label,
+ new AttributionLabelledGroupUsage.Builder(label, getGroup()));
+ }
+ labelDiscreteAccessMap.get(label).addAttributionTag(attributionTag);
+ labelDiscreteAccessMap.get(label).addDiscreteAccessTime(new Triple<>(
+ opEntry.getLastAccessTime(PRIVACY_HUB_FLAGS),
+ opEntry.getLastDuration(PRIVACY_HUB_FLAGS),
+ opEntry.getLastProxyInfo(PRIVACY_HUB_FLAGS)));
+ }
+ }
+ }
+
+ return labelDiscreteAccessMap.entrySet().stream()
+ .map(e -> e.getValue().build())
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Represents the slice of {@link GroupUsage} with a label.
+ *
+ * <p> -1 as label means that there was no entry for the attribution tag in the
+ * manifest.</p>
+ */
+ public static class AttributionLabelledGroupUsage implements TimelineUsage {
+ private final int mLabel;
+ private final AppPermissionGroup mAppPermissionGroup;
+ private final List<String> mAttributionTags;
+ private final List<Triple<Long, Long, OpEventProxyInfo>> mDiscreteAccessTime;
+
+ AttributionLabelledGroupUsage(int label,
+ AppPermissionGroup appPermissionGroup,
+ List<String> attributionTags,
+ List<Triple<Long, Long, OpEventProxyInfo>> discreteAccessTime) {
+ mLabel = label;
+ mAppPermissionGroup = appPermissionGroup;
+ mAttributionTags = attributionTags;
+ mDiscreteAccessTime = discreteAccessTime;
+ }
+
+ @Override
+ public int getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ public boolean hasDiscreteData() {
+ return mDiscreteAccessTime.size() > 0;
+ }
+
+ @Override
+ public List<Triple<Long, Long, OpEventProxyInfo>> getAllDiscreteAccessTime() {
+ return mDiscreteAccessTime;
+ }
+
+ @Override
+ public List<String> getAttributionTags() {
+ return mAttributionTags;
+ }
+
+ @Override
+ public AppPermissionGroup getGroup() {
+ return mAppPermissionGroup;
+ }
+
+ static class Builder {
+ private final int mLabel;
+ private final AppPermissionGroup mAppPermissionGroup;
+ private Set<String> mAttributionTags;
+ private List<Triple<Long, Long, OpEventProxyInfo>> mDiscreteAccessTime;
+
+ Builder(int label, AppPermissionGroup appPermissionGroup) {
+ mLabel = label;
+ mAppPermissionGroup = appPermissionGroup;
+ mAttributionTags = new HashSet<>();
+ mDiscreteAccessTime = new ArrayList<>();
+ }
+
+ @NonNull Builder addAttributionTag(String attributionTag) {
+ mAttributionTags.add(attributionTag);
+ return this;
+ }
+
+ @NonNull
+ Builder addDiscreteAccessTime(
+ Triple<Long, Long, OpEventProxyInfo> discreteAccessTime) {
+ mDiscreteAccessTime.add(discreteAccessTime);
+ return this;
+ }
+
+ AttributionLabelledGroupUsage build() {
+ return new AttributionLabelledGroupUsage(mLabel,
+ mAppPermissionGroup,
+ new ArrayList<String>() {{
+ addAll(mAttributionTags);
+ }}, mDiscreteAccessTime);
+ }
+ }
+ }
}
public static class Builder {
@@ -400,4 +543,36 @@
mAudioRecordingConfigurations);
}
}
+
+ /** Usage for showing timeline view for a specific permission group with a label. */
+ public interface TimelineUsage {
+ /**
+ * Returns whether the usage has discrete data.
+ */
+ boolean hasDiscreteData();
+
+ /**
+ * Returns all discrete access time in millis.
+ * Returns a list of triples of (access time, access duration, proxy)
+ */
+ List<Triple<Long, Long, OpEventProxyInfo>> getAllDiscreteAccessTime();
+
+ /**
+ * Returns attribution tags for the usage.
+ */
+ List<String> getAttributionTags();
+
+ /**
+ * Returns the permission group of the usage.
+ */
+ AppPermissionGroup getGroup();
+
+ /**
+ * Returns the user facing string's resource id.
+ *
+ * <p> -1 means show the app name otherwise get the string resource from the app
+ * context.</p>
+ */
+ int getLabel();
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
index 636f199..69bbdce 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/HibernationSettingState.kt
@@ -25,12 +25,9 @@
* @param revocableGroupNames A list of which permission groups of this package are eligible for
* auto-revoke. A permission group is auto-revocable if it does not contain a default granted
* permission.
- * @param shouldAllowUserToggle If the hibernation/auto-revoke switch should be provided for the
- * user to control.
*/
data class HibernationSettingState(
val isEnabledGlobal: Boolean,
val isEnabledForApp: Boolean,
- val revocableGroupNames: List<String>,
- val shouldAllowUserToggle: Boolean
+ val revocableGroupNames: List<String>
)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
index f2466a4..dfcb39c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
@@ -551,7 +551,7 @@
Preference autoRevokeSummary = autoRevokeCategory.findPreference(
AUTO_REVOKE_SUMMARY_KEY);
- if (!state.isEnabledGlobal()) {
+ if (!state.isEnabledGlobal() || state.getRevocableGroupNames().isEmpty()) {
autoRevokeCategory.setVisible(false);
autoRevokeSwitch.setVisible(false);
autoRevokeSummary.setVisible(false);
@@ -560,7 +560,6 @@
autoRevokeCategory.setVisible(true);
autoRevokeSwitch.setVisible(true);
autoRevokeSummary.setVisible(true);
- autoRevokeSwitch.setEnabled(state.getShouldAllowUserToggle());
autoRevokeSwitch.setChecked(state.isEnabledForApp());
List<String> groupLabels = new ArrayList<>();
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
index 92f595e..2cd2773 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java
@@ -418,12 +418,11 @@
if (state == null || autoRevokeSwitch == null) {
return;
}
- if (!state.isEnabledGlobal()) {
+ if (!state.isEnabledGlobal() || state.getRevocableGroupNames().isEmpty()) {
autoRevokeSwitch.setVisible(false);
return;
}
autoRevokeSwitch.setVisible(true);
- autoRevokeSwitch.setEnabled(state.getShouldAllowUserToggle());
autoRevokeSwitch.setChecked(state.isEnabledForApp());
}
diff --git a/service/java/com/android/role/RoleService.java b/service/java/com/android/role/RoleService.java
index 5df76c4..802e38b 100644
--- a/service/java/com/android/role/RoleService.java
+++ b/service/java/com/android/role/RoleService.java
@@ -704,6 +704,12 @@
@Override
public String getSmsRoleHolder(int userId) {
+ enforceCrossUserPermission(userId, false, "getSmsRoleHolder");
+ if (!isUserExistent(userId)) {
+ Log.e(LOG_TAG, "user " + userId + " does not exist");
+ return null;
+ }
+
final long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(getRoleHoldersAsUser(RoleManager.ROLE_SMS,