[automerger skipped] [automerged blank] Import translations. DO NOT MERGE ANYWHERE 2p: fcbebd4b59 am: edebb4bb6d -s ours am: 0c38f7ebcb -s ours
am skip reason: subject contains skip directive
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/modules/Permission/+/15809190
Change-Id: I19a8a66f7151b67630f42ca67b357384de553019
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index ba03cbf..7a08681 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -136,6 +136,9 @@
<!-- Label when there are no unused apps [CHAR LIMIT=30] -->
<string name="no_unused_apps">No unused apps</string>
+ <!-- Label when there are zero unused apps [CHAR LIMIT=30] -->
+ <string name="zero_unused_apps">0 unused apps</string>
+
<!-- [CHAR LIMIT=30] Manage applications, label for option to disable app -->
<string name="app_disable_dlg_positive">Disable app</string>
diff --git a/PermissionController/res/values/themes.xml b/PermissionController/res/values/themes.xml
index 04265a3..16ff3c1 100644
--- a/PermissionController/res/values/themes.xml
+++ b/PermissionController/res/values/themes.xml
@@ -57,6 +57,10 @@
<item name="android:windowIsTranslucent">true</item>
</style>
+ <style name="GrantPermissions.Car">
+ <item name="carUiActivity">true</item>
+ </style>
+
<!-- Unused since R but exposed as overlayable. -->
<style name="Header.Settings"
parent="@android:style/Theme.DeviceDefault.Settings">
@@ -118,6 +122,10 @@
<item name="android:filterTouchesWhenObscured">true</item>
</style>
+ <style name="GrantPermissions.Car.FilterTouches">
+ <item name="android:filterTouchesWhenObscured">true</item>
+ </style>
+
<style name="RequestRole.FilterTouches">
<item name="android:filterTouchesWhenObscured">true</item>
</style>
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsages.java b/PermissionController/src/com/android/permissioncontroller/permission/model/PermissionUsages.java
similarity index 92%
rename from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsages.java
rename to PermissionController/src/com/android/permissioncontroller/permission/model/PermissionUsages.java
index f83309f..b1dd404 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsages.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/PermissionUsages.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.handheld.dashboard;
+package com.android.permissioncontroller.permission.model;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
@@ -45,10 +45,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.model.AppPermissionUsage;
import com.android.permissioncontroller.permission.model.AppPermissionUsage.Builder;
-import com.android.permissioncontroller.permission.model.Permission;
import com.android.permissioncontroller.permission.model.legacy.PermissionApps.PermissionApp;
import com.android.permissioncontroller.permission.model.legacy.PermissionGroup;
import com.android.permissioncontroller.permission.model.legacy.PermissionGroups;
@@ -92,14 +89,27 @@
private @Nullable PermissionsUsagesChangeCallback mCallback;
+ /**
+ * Callback for when the permission usages has loaded or changed.
+ */
public interface PermissionsUsagesChangeCallback {
+ /**
+ * Called when the permission usages have loaded or changed.
+ */
void onPermissionUsagesChanged();
}
+ /**
+ * Creates a new instance of {@link PermissionUsages}.
+ */
public PermissionUsages(@NonNull Context context) {
mContext = context;
}
+ /**
+ * Start the {@link Loader} to load the permission usages in the background. Loads without a uid
+ * filter.
+ */
public void load(@Nullable String filterPackageName,
@Nullable String[] filterPermissionGroups, long filterBeginTimeMillis,
long filterEndTimeMillis, int usageFlags, @NonNull LoaderManager loaderManager,
@@ -110,6 +120,10 @@
getNonPlatformPermissions, callback, sync);
}
+ /**
+ * Start the {@link Loader} to load the permission usages in the background. Loads only
+ * permissions for the specified {@code filterUid}.
+ */
public void load(int filterUid, @Nullable String filterPackageName,
@Nullable String[] filterPermissionGroups, long filterBeginTimeMillis,
long filterEndTimeMillis, int usageFlags, @NonNull LoaderManager loaderManager,
@@ -155,36 +169,20 @@
mCallback.onPermissionUsagesChanged();
}
+ /**
+ * Return the usages that have already been loaded.
+ */
public @NonNull List<AppPermissionUsage> getUsages() {
return mUsages;
}
+ /**
+ * Stop the {@link Loader} from loading the usages.
+ */
public void stopLoader(@NonNull LoaderManager loaderManager) {
loaderManager.destroyLoader(1);
}
- public static @Nullable AppPermissionUsage.GroupUsage loadLastGroupUsage(
- @NonNull Context context, @NonNull AppPermissionGroup group) {
- final ArraySet<String> opNames = new ArraySet<>();
- final List<Permission> permissions = group.getPermissions();
- final int permCount = permissions.size();
- for (int i = 0; i < permCount; i++) {
- final Permission permission = permissions.get(i);
- final String opName = permission.getAppOp();
- if (opName != null) {
- opNames.add(opName);
- }
- }
- final String[] opNamesArray = opNames.toArray(new String[opNames.size()]);
- final List<PackageOps> usageOps = context.getSystemService(AppOpsManager.class)
- .getOpsForPackage(group.getApp().applicationInfo.uid,
- group.getApp().packageName, opNamesArray);
- if (usageOps == null || usageOps.isEmpty()) {
- return null;
- }
- return new AppPermissionUsage.GroupUsage(group, usageOps.get(0), null);
- }
-
private static final class UsageLoader extends AsyncTaskLoader<List<AppPermissionUsage>> {
private final int mFilterUid;
private @Nullable String mFilterPackageName;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
index b96efef..812e4fe 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/GrantPermissionsActivity.java
@@ -127,6 +127,9 @@
@Override
public void onCreate(Bundle icicle) {
+ if (DeviceUtils.isAuto(this)) {
+ setTheme(R.style.GrantPermissions_Car_FilterTouches);
+ }
super.onCreate(icicle);
if (icicle == null) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
index bf48e28..f33a1dd 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.java
@@ -256,10 +256,10 @@
if (DeviceUtils.isAuto(this)) {
if (allPermissions) {
androidXFragment = AutoAllAppPermissionsFragment.newInstance(packageName,
- userHandle);
+ userHandle, sessionId);
} else {
androidXFragment = AutoAppPermissionsFragment.newInstance(packageName,
- userHandle);
+ userHandle, sessionId);
}
} else if (DeviceUtils.isWear(this)) {
androidXFragment = AppPermissionsFragmentWear.newInstance(packageName);
@@ -296,7 +296,8 @@
return;
}
if (DeviceUtils.isAuto(this)) {
- androidXFragment = AutoPermissionAppsFragment.newInstance(permissionName);
+ androidXFragment =
+ AutoPermissionAppsFragment.newInstance(permissionName, sessionId);
} else if (DeviceUtils.isTelevision(this)) {
androidXFragment = com.android.permissioncontroller.permission.ui.television
.PermissionAppsFragment.newInstance(permissionName);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
index c1d26dd..e1af9d6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/UnusedAppsFragment.kt
@@ -56,14 +56,13 @@
where PF : PreferenceFragmentCompat, PF : UnusedAppsFragment.Parent<UnusedAppPref>,
UnusedAppPref : Preference, UnusedAppPref : RemovablePref {
- private val INFO_MSG_CATEGORY = "info_msg_category"
-
private lateinit var viewModel: UnusedAppsViewModel
private lateinit var collator: Collator
private var sessionId: Long = 0L
private var isFirstLoad = false
companion object {
+ public const val INFO_MSG_CATEGORY = "info_msg_category"
private const val SHOW_LOAD_DELAY_MS = 200L
private const val INFO_MSG_KEY = "info_msg"
private const val ELEVATION_HIGH = 8f
@@ -253,9 +252,7 @@
}
}
- val infoMsgCategory =
- preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
- infoMsgCategory.isVisible = !allCategoriesEmpty
+ preferenceFragment.setEmptyState(allCategoriesEmpty)
if (isFirstLoad) {
if (categorizedPackages[Months.SIX]!!.isNotEmpty() ||
@@ -377,5 +374,12 @@
user: UserHandle,
context: Context
): UnusedAppPref
+
+ /**
+ * Updates the state based on whether the content is empty.
+ *
+ * @param empty whether the content is empty
+ */
+ fun setEmptyState(empty: Boolean)
}
}
\ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
index f065f1c..e509d8a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAllAppPermissionsFragment.java
@@ -16,6 +16,8 @@
package com.android.permissioncontroller.permission.ui.auto;
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -62,18 +64,19 @@
/** Creates an {@link AutoAllAppPermissionsFragment} with no filter. */
public static AutoAllAppPermissionsFragment newInstance(@NonNull String packageName,
- @NonNull UserHandle userHandle) {
- return newInstance(packageName, /* filterGroup= */ null, userHandle);
+ @NonNull UserHandle userHandle, long sessionId) {
+ return newInstance(packageName, /* filterGroup= */ null, userHandle, sessionId);
}
/** Creates an {@link AutoAllAppPermissionsFragment} with a specific filter group. */
public static AutoAllAppPermissionsFragment newInstance(@NonNull String packageName,
- @NonNull String filterGroup, @NonNull UserHandle userHandle) {
+ @NonNull String filterGroup, @NonNull UserHandle userHandle, long sessionId) {
AutoAllAppPermissionsFragment instance = new AutoAllAppPermissionsFragment();
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
arguments.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, filterGroup);
arguments.putParcelable(Intent.EXTRA_USER, userHandle);
+ arguments.putLong(EXTRA_SESSION_ID, sessionId);
instance.setArguments(arguments);
return instance;
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
index 3181db4..2a74fd3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
@@ -16,6 +16,10 @@
package com.android.permissioncontroller.permission.ui.auto;
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_ACTION_REPORTED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_FRAGMENT_VIEWED;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT;
@@ -48,6 +52,7 @@
import androidx.preference.TwoStatePreference;
import com.android.car.ui.AlertDialogBuilder;
+import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
@@ -60,7 +65,9 @@
import com.android.settingslib.RestrictedLockUtils;
import java.lang.annotation.Retention;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
/** Settings related to a particular permission for the given app. */
public class AutoAppPermissionFragment extends AutoSettingsFrameFragment {
@@ -114,7 +121,8 @@
*/
@NonNull
public static AutoAppPermissionFragment newInstance(@NonNull String packageName,
- @NonNull String permName, @Nullable String groupName, @NonNull UserHandle userHandle) {
+ @NonNull String permName, @Nullable String groupName, @NonNull UserHandle userHandle,
+ @NonNull long sessionId) {
AutoAppPermissionFragment fragment = new AutoAppPermissionFragment();
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
@@ -124,6 +132,7 @@
arguments.putString(Intent.EXTRA_PERMISSION_GROUP_NAME, groupName);
}
arguments.putParcelable(Intent.EXTRA_USER, userHandle);
+ arguments.putLong(EXTRA_SESSION_ID, sessionId);
fragment.setArguments(arguments);
return fragment;
}
@@ -143,6 +152,7 @@
setHeaderLabel(
requireContext().getString(R.string.app_permission_title, mGroup.getFullLabel()));
+ logAppPermissionFragmentViewed();
}
private void setResult(@GrantPermissionsViewHandler.Result int result) {
@@ -265,6 +275,15 @@
updateUi();
}
+ void logAppPermissionFragmentViewed() {
+ long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ PermissionControllerStatsLog.write(APP_PERMISSION_FRAGMENT_VIEWED, sessionId,
+ mGroup.getApp().applicationInfo.uid, mGroup.getApp().packageName, mGroup.getName());
+ Log.v(LOG_TAG, "AutoAppPermission fragment viewed with sessionId=" + sessionId + " uid="
+ + mGroup.getApp().applicationInfo.uid + " packageName="
+ + mGroup.getApp().packageName + " permissionGroupName=" + mGroup.getName());
+ }
+
@Override
public void onStop() {
super.onStop();
@@ -588,7 +607,8 @@
*/
private void showAllPermissions(@NonNull String filterGroup) {
Fragment frag = AutoAllAppPermissionsFragment.newInstance(mGroup.getApp().packageName,
- filterGroup, UserHandle.getUserHandleForUid(mGroup.getApp().applicationInfo.uid));
+ filterGroup, UserHandle.getUserHandleForUid(mGroup.getApp().applicationInfo.uid),
+ getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID));
requireFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
.addToBackStack("AllPerms")
@@ -624,6 +644,8 @@
}
if (requestGrant) {
+ ArrayList<PermissionState> stateBefore = createPermissionSnapshot();
+
if ((changeTarget & CHANGE_FOREGROUND) != 0) {
if (!mGroup.areRuntimePermissionsGranted()) {
SafetyNetLogger.logPermissionToggled(mGroup);
@@ -640,6 +662,7 @@
mGroup.getBackgroundPermissions().grantRuntimePermissions(true, false);
}
}
+ logPermissionChanges(stateBefore);
} else {
boolean showDefaultDenyDialog = false;
@@ -664,6 +687,7 @@
updateUi();
return false;
} else {
+ ArrayList<PermissionState> stateBefore = createPermissionSnapshot();
if ((changeTarget & CHANGE_FOREGROUND) != 0
&& mGroup.areRuntimePermissionsGranted()) {
if (mGroup.areRuntimePermissionsGranted()) {
@@ -682,6 +706,7 @@
mGroup.getBackgroundPermissions().revokeRuntimePermissions(false);
}
}
+ logPermissionChanges(stateBefore);
}
}
@@ -737,6 +762,8 @@
*/
private void onDenyAnyWay(@ChangeTarget int changeTarget) {
boolean hasDefaultPermissions = false;
+ ArrayList<PermissionState> stateBefore = createPermissionSnapshot();
+
if ((changeTarget & CHANGE_FOREGROUND) != 0) {
if (mGroup.areRuntimePermissionsGranted()) {
SafetyNetLogger.logPermissionToggled(mGroup);
@@ -756,6 +783,7 @@
mGroup.getBackgroundPermissions().hasGrantedByDefaultPermission();
}
}
+ logPermissionChanges(stateBefore);
if (hasDefaultPermissions || !mGroup.doesSupportRuntimePermissions()) {
mHasConfirmedRevoke = true;
@@ -828,4 +856,81 @@
}
}
}
+
+ private ArrayList<PermissionState> createPermissionSnapshot() {
+ ArrayList<PermissionState> permissionSnapshot = new ArrayList<>();
+ ArrayList<Permission> permissions = mGroup.getPermissions();
+ int numPermissions = permissions.size();
+
+ for (int i = 0; i < numPermissions; i++) {
+ Permission permission = permissions.get(i);
+ permissionSnapshot.add(new PermissionState(permission.getName(),
+ permission.isGrantedIncludingAppOp()));
+ }
+
+ AppPermissionGroup permissionGroup = mGroup.getBackgroundPermissions();
+
+ if (permissionGroup == null) {
+ return permissionSnapshot;
+ }
+
+ permissions = mGroup.getBackgroundPermissions().getPermissions();
+ numPermissions = permissions.size();
+
+ for (int i = 0; i < numPermissions; i++) {
+ Permission permission = permissions.get(i);
+ permissionSnapshot.add(new PermissionState(permission.getName(),
+ permission.isGrantedIncludingAppOp()));
+ }
+
+ return permissionSnapshot;
+ }
+
+ private void logPermissionChanges(ArrayList<PermissionState> previousPermissionSnapshot) {
+ long changeId = new Random().nextLong();
+ int numPermissions = previousPermissionSnapshot.size();
+ long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+
+ for (int i = 0; i < numPermissions; i++) {
+ PermissionState permissionState = previousPermissionSnapshot.get(i);
+ boolean wasGranted = permissionState.permissionGranted;
+ Permission permission = mGroup.getPermission(permissionState.permissionName);
+
+ if (permission == null) {
+ if (mGroup.getBackgroundPermissions() == null) {
+ continue;
+ }
+ permission = mGroup.getBackgroundPermissions().getPermission(
+ permissionState.permissionName);
+ }
+
+ boolean isGranted = permission.isGrantedIncludingAppOp();
+
+ if (wasGranted != isGranted) {
+ logAppPermissionFragmentActionReported(sessionId, changeId,
+ permissionState.permissionName, isGranted);
+ }
+ }
+ }
+
+ private void logAppPermissionFragmentActionReported(
+ long sessionId, long changeId, String permissionName, boolean isGranted) {
+ PermissionControllerStatsLog.write(APP_PERMISSION_FRAGMENT_ACTION_REPORTED, sessionId,
+ changeId, mGroup.getApp().applicationInfo.uid, mGroup.getApp().packageName,
+ permissionName, isGranted, /*flags=*/0, /*buttonPressed=*/0);
+ Log.v(LOG_TAG, "Permission changed via UI with sessionId=" + sessionId + " changeId="
+ + changeId + " uid=" + mGroup.getApp().applicationInfo.uid + " packageName="
+ + mGroup.getApp().packageName + " permission="
+ + permissionName + " isGranted=" + isGranted);
+ }
+
+ private static class PermissionState {
+ @NonNull public final String permissionName;
+ public final boolean permissionGranted;
+
+ PermissionState(@NonNull String permissionName, boolean permissionGranted) {
+ this.permissionName = permissionName;
+ this.permissionGranted = permissionGranted;
+ }
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
index fed489e..b26e30b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionsFragment.java
@@ -17,6 +17,11 @@
package com.android.permissioncontroller.permission.ui.auto;
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
+import static com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__DENIED;
import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
import android.app.Activity;
@@ -27,9 +32,11 @@
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
+import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
@@ -37,6 +44,8 @@
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
+import com.android.car.ui.utils.ViewUtils;
+import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
@@ -50,6 +59,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Random;
/** Screen to show the permissions for a specific application. */
public class AutoAppPermissionsFragment extends AutoSettingsFrameFragment {
@@ -70,16 +80,17 @@
* @return A new fragment
*/
public static AutoAppPermissionsFragment newInstance(@NonNull String packageName,
- @NonNull UserHandle userHandle) {
+ @NonNull UserHandle userHandle, long sessionId) {
return setPackageNameAndUserHandle(new AutoAppPermissionsFragment(), packageName,
- userHandle);
+ userHandle, sessionId);
}
private static <T extends Fragment> T setPackageNameAndUserHandle(@NonNull T fragment,
- @NonNull String packageName, @NonNull UserHandle userHandle) {
+ @NonNull String packageName, @NonNull UserHandle userHandle, long sessionId) {
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
arguments.putParcelable(Intent.EXTRA_USER, userHandle);
+ arguments.putLong(EXTRA_SESSION_ID, sessionId);
fragment.setArguments(arguments);
return fragment;
}
@@ -128,7 +139,8 @@
private void showAllPermissions() {
Fragment frag = AutoAllAppPermissionsFragment.newInstance(
getArguments().getString(Intent.EXTRA_PACKAGE_NAME),
- getArguments().getParcelable(Intent.EXTRA_USER));
+ getArguments().getParcelable(Intent.EXTRA_USER),
+ getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID));
getFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
.addToBackStack("AllPerms")
@@ -229,7 +241,8 @@
frag = new AutoAppPermissionsFragment.AdditionalPermissionsFragment();
setPackageNameAndUserHandle(frag,
getArguments().getString(Intent.EXTRA_PACKAGE_NAME),
- getArguments().getParcelable(Intent.EXTRA_USER));
+ getArguments().getParcelable(Intent.EXTRA_USER),
+ getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID));
frag.setTargetFragment(AutoAppPermissionsFragment.this, 0);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, frag)
@@ -260,6 +273,62 @@
}
setLoading(false);
+ logAppPermissionsFragmentView();
+ }
+
+ private void logAppPermissionsFragmentView() {
+ Context context = getPreferenceManager().getContext();
+ if (context == null) {
+ return;
+ }
+ String permissionSubtitleOnlyInForeground =
+ context.getString(R.string.permission_subtitle_only_in_foreground);
+
+
+ long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ long viewId = new Random().nextLong();
+
+ PreferenceCategory allowed = findPreference(KEY_ALLOWED_PERMISSIONS_GROUP);
+
+ int numAllowed = allowed.getPreferenceCount();
+ for (int i = 0; i < numAllowed; i++) {
+ Preference preference = allowed.getPreference(i);
+ if (preference.getSummary() == null) {
+ // R.string.no_permission_allowed was added to PreferenceCategory
+ continue;
+ }
+
+ int category = APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
+ if (permissionSubtitleOnlyInForeground.contentEquals(preference.getSummary())) {
+ category = APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
+ }
+
+ logAppPermissionsFragmentViewEntry(sessionId, viewId, preference.getKey(), category);
+ }
+
+ PreferenceCategory denied = findPreference(KEY_DENIED_PERMISSIONS_GROUP);
+
+ int numDenied = denied.getPreferenceCount();
+ for (int i = 0; i < numDenied; i++) {
+ Preference preference = denied.getPreference(i);
+ if (preference.getSummary() == null) {
+ // R.string.no_permission_denied was added to PreferenceCategory
+ continue;
+ }
+ logAppPermissionsFragmentViewEntry(sessionId, viewId, preference.getKey(),
+ APP_PERMISSIONS_FRAGMENT_VIEWED__CATEGORY__DENIED);
+ }
+ }
+
+ private void logAppPermissionsFragmentViewEntry(
+ long sessionId, long viewId, String permissionGroupName, int category) {
+ PermissionControllerStatsLog.write(APP_PERMISSIONS_FRAGMENT_VIEWED, sessionId, viewId,
+ permissionGroupName, mAppPermissions.getPackageInfo().applicationInfo.uid,
+ mAppPermissions.getPackageInfo().packageName, category);
+ Log.v(LOG_TAG, "AutoAppPermissionFragment view logged with sessionId=" + sessionId
+ + " viewId=" + viewId + " permissionGroupName=" + permissionGroupName + " uid="
+ + mAppPermissions.getPackageInfo().applicationInfo.uid + " packageName="
+ + mAppPermissions.getPackageInfo().packageName + " category=" + category);
}
private Preference createPermissionPreference(Context context, AppPermissionGroup group) {
@@ -293,7 +362,7 @@
return getContext().getString(R.string.permission_subtitle_only_in_foreground);
}
}
- return null;
+ return "";
}
/**
@@ -312,6 +381,16 @@
}
@Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ // initially focus on focus parking view and then shift focus to recyclerview once it
+ // has loaded
+ ViewUtils.hideFocus(getListView().getRootView());
+ ViewUtils.initFocus((ViewUtils.LazyLayoutView) getListView());
+ }
+
+ @Override
public void onCreatePreferences(Bundle bundle, String s) {
setPreferenceScreen(mOuterFragment.mExtraScreen);
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageCustomPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageCustomPermissionsFragment.java
deleted file mode 100644
index 0de51c8..0000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageCustomPermissionsFragment.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2019 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.ui.auto;
-
-import com.android.permissioncontroller.R;
-
-/** Shows additional non-system permissions that can be granted/denied. */
-public class AutoManageCustomPermissionsFragment extends AutoManagePermissionsFragment {
-
- @Override
- protected int getScreenHeaderRes() {
- return R.string.additional_permissions;
- }
-
- @Override
- protected void updatePermissionsUi() {
- updatePermissionsUi(/* addSystemPermissions= */ false);
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageOtherPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageOtherPermissionsFragment.java
new file mode 100644
index 0000000..e603399
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageOtherPermissionsFragment.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2021 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.ui.auto;
+
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.permissioncontroller.R;
+import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
+import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo;
+import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.PermissionGroupPreferenceUtils;
+
+import java.util.List;
+
+/**
+ * Shows additional non-system permissions that can be granted/denied.
+ *
+ * Largely based on
+ * {@link com.android.permissioncontroller.permission.ui.television.ManagePermissionsOtherFragment}.
+ */
+public class AutoManageOtherPermissionsFragment extends AutoSettingsFrameFragment {
+ private static final String KEY_UNUSED_CATEGORY = "category_unused";
+ private static final String KEY_ADDITIONAL_CATEGORY = "category_additional";
+
+ private PreferenceCategory mUnusedCategory;
+ private PreferenceCategory mAdditionalCategory;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setLoading(true);
+ setHeaderLabel(getString(R.string.other_permissions_label));
+
+ final Application application = getActivity().getApplication();
+ final ViewModelProvider.Factory factory =
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+ final ManagePermissionsViewModel viewModel = new ViewModelProvider(this, factory)
+ .get(ManagePermissionsViewModel.class);
+
+ viewModel.getUnusedPermissionGroups().observe(this, this::onUnusedPermissionGroupsChanged);
+ viewModel.getAdditionalPermissionGroups().observe(this,
+ this::onAdditionalPermissionGroupsChanged);
+ viewModel.hasUnusedOrAdditionalPermissionGroups().observe(this,
+ this::onHasUnusedOrAdditionalPermissionGroups);
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s) {
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
+ }
+
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ final Context context = getPreferenceManager().getContext();
+ final PreferenceScreen screen = getPreferenceScreen();
+ // We add categories here, but make them invisible until the data is loaded.
+ mUnusedCategory = new PreferenceCategory(context);
+ mUnusedCategory.setKey(KEY_UNUSED_CATEGORY);
+ mUnusedCategory.setTitle(R.string.not_used_permissions_label);
+ mUnusedCategory.setSummary(R.string.not_used_permissions_description);
+ mUnusedCategory.setVisible(false);
+ screen.addPreference(mUnusedCategory);
+
+ mAdditionalCategory = new PreferenceCategory(context);
+ mAdditionalCategory.setKey(KEY_ADDITIONAL_CATEGORY);
+ mAdditionalCategory.setTitle(R.string.additional_permissions_label);
+ mAdditionalCategory.setSummary(R.string.additional_permissions_description);
+ mAdditionalCategory.setVisible(false);
+ screen.addPreference(mAdditionalCategory);
+ }
+
+ private void onUnusedPermissionGroupsChanged(List<PermGroupPackagesUiInfo> permissionGroups) {
+ updateCategory(mUnusedCategory, permissionGroups);
+ }
+
+ private void onAdditionalPermissionGroupsChanged(
+ List<PermGroupPackagesUiInfo> permissionGroups) {
+ updateCategory(mAdditionalCategory, permissionGroups);
+ }
+
+ private void onHasUnusedOrAdditionalPermissionGroups(Boolean hasPGs) {
+ if (!hasPGs) {
+ // There are not more permissions on this screen - go back.
+ getParentFragmentManager().popBackStack();
+ }
+ }
+
+ private void updateCategory(PreferenceCategory category,
+ List<PermGroupPackagesUiInfo> permissionGroups) {
+ final Context context = getPreferenceManager().getContext();
+ if (context == null) {
+ return;
+ }
+
+ PermissionGroupPreferenceUtils.updateGroupOfPermissionPreferences(context, category,
+ permissionGroups);
+ // Only show the category if it's not empty.
+ category.setVisible(!permissionGroups.isEmpty());
+
+ setLoading(false);
+ }
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManagePermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManagePermissionsFragment.java
deleted file mode 100644
index 49ea5eb..0000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManagePermissionsFragment.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2019 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.ui.auto;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
-import androidx.preference.Preference;
-
-import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
-import com.android.permissioncontroller.permission.model.legacy.PermissionGroup;
-import com.android.permissioncontroller.permission.model.legacy.PermissionGroups;
-import com.android.permissioncontroller.permission.utils.Utils;
-
-import java.text.Collator;
-import java.util.ArrayList;
-
-/** Base class to show the list of permissions that can be granted/denied. */
-abstract class AutoManagePermissionsFragment extends AutoSettingsFrameFragment implements
- PermissionGroups.PermissionsGroupsChangeCallback, Preference.OnPreferenceClickListener {
-
- private static final String LOG_TAG = "ManagePermissionsFragment";
-
- static final String OS_PKG = "android";
-
- private PermissionGroups mPermissions;
-
- private Collator mCollator;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setLoading(true);
-
- mPermissions = new PermissionGroups(getContext(), requireActivity().getLoaderManager(),
- /* callback= */ this, /* getAppUiInfo= */ false,
- /* getNonPlatformPermissions= */ true);
- mCollator = Collator.getInstance(
- getContext().getResources().getConfiguration().getLocales().get(0));
-
- setHeaderLabel(getString(getScreenHeaderRes()));
- }
-
- @Override
- public void onCreatePreferences(Bundle bundle, String s) {
- setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
- }
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- String key = preference.getKey();
-
- PermissionGroup group = mPermissions.getGroup(key);
- if (group == null) {
- return false;
- }
-
- Intent intent = new Intent(Intent.ACTION_MANAGE_PERMISSION_APPS)
- .putExtra(Intent.EXTRA_PERMISSION_NAME, key);
- try {
- getActivity().startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.w(LOG_TAG, "No app to handle " + intent);
- }
-
- return true;
- }
-
- /** Returns the header string resource. */
- @StringRes
- protected abstract int getScreenHeaderRes();
-
- /** Returns the current permissions. */
- protected PermissionGroups getPermissions() {
- return mPermissions;
- }
-
- @Override
- public void onPermissionGroupsChanged() {
- updatePermissionsUi();
- }
-
- /** Update the preferences to show the new {@link #getPermissions() permissions}. */
- protected abstract void updatePermissionsUi();
-
- /**
- * Add preferences for all permissions of a type to the preference screen.
- */
- protected void updatePermissionsUi(boolean addSystemPermissions) {
- Context context = getPreferenceManager().getContext();
- if (context == null || getActivity() == null) {
- return;
- }
-
- ArrayList<PermissionGroup> groups = new ArrayList<>(mPermissions.getGroups());
- groups.sort((x, y) -> mCollator.compare(x.getLabel(), y.getLabel()));
- getPreferenceScreen().removeAll();
- getPreferenceScreen().setOrderingAsAdded(true);
-
- // Use this to speed up getting the info for all of the PermissionApps below.
- // Create a new one for each refresh to make sure it has fresh data.
- for (int i = 0; i < groups.size(); i++) {
- PermissionGroup group = groups.get(i);
- boolean isSystemPermission = group.getDeclaringPackage().equals(OS_PKG);
-
- if (addSystemPermissions == isSystemPermission) {
- Preference preference = findPreference(group.getName());
-
- if (preference == null) {
- preference = new Preference(context);
- preference.setOnPreferenceClickListener(this);
- preference.setKey(group.getName());
- preference.setIcon(Utils.applyTint(context, group.getIcon(),
- android.R.attr.colorControlNormal));
- preference.setTitle(group.getLabel());
- // Set blank summary so that no resizing/jumping happens when the summary is
- // loaded.
- preference.setSummary(" ");
- preference.setPersistent(false);
- getPreferenceScreen().addPreference(preference);
- }
- preference.setSummary(
- getString(R.string.app_permissions_group_summary, group.getGranted(),
- group.getTotal()));
- }
- }
- if (getPreferenceScreen().getPreferenceCount() != 0) {
- setLoading(false);
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageStandardPermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageStandardPermissionsFragment.java
index c3d9ed2..8bbcde6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageStandardPermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoManageStandardPermissionsFragment.java
@@ -16,31 +16,43 @@
package com.android.permissioncontroller.permission.ui.auto;
+
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
import android.app.Application;
+import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.permissioncontroller.R;
-import com.android.permissioncontroller.permission.model.legacy.PermissionGroup;
+import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
+import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo;
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment;
+import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel;
import com.android.permissioncontroller.permission.ui.model.ManageStandardPermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.PermissionGroupPreferenceUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.List;
-/** Shows the standard permissions that can be granted/denied. */
-public class AutoManageStandardPermissionsFragment extends AutoManagePermissionsFragment {
+/**
+ * Shows the standard permissions that can be granted/denied.
+ *
+ * Largely based on the implementation of
+ * {@link com.android.permissioncontroller.permission.ui.television.ManagePermissionsFragment}.
+ */
+public class AutoManageStandardPermissionsFragment extends AutoSettingsFrameFragment {
- private static final String EXTRA_PREFS_KEY = "extra_prefs_key";
- private static final String AUTO_REVOKE_KEY = "auto_revoke_key";
- private ManageStandardPermissionsViewModel mViewModel;
+ private static final String KEY_OTHER_PERMISSIONS = "other_permissions";
+ private static final String KEY_AUTO_REVOKE = "auto_revoke_key";
+ private ManagePermissionsViewModel mManagePermissionsViewModel;
+ private ManageStandardPermissionsViewModel mManageStandardPermissionsViewModel;
/** Returns a new instance of {@link AutoManageStandardPermissionsFragment}. */
public static AutoManageStandardPermissionsFragment newInstance() {
@@ -50,84 +62,108 @@
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setLoading(true);
+ setHeaderLabel(getString(R.string.app_permission_manager));
final Application application = getActivity().getApplication();
- mViewModel = new ViewModelProvider(this,
+ final ViewModelProvider.Factory viewModelFactory =
+ ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+ mManagePermissionsViewModel = new ViewModelProvider(this, viewModelFactory)
+ .get(ManagePermissionsViewModel.class);
+ mManageStandardPermissionsViewModel = new ViewModelProvider(this,
ViewModelProvider.AndroidViewModelFactory.getInstance(application))
.get(ManageStandardPermissionsViewModel.class);
-
- mViewModel.getUiDataLiveData().observe(this, permissionGroups -> {
- if (permissionGroups != null) {
- updatePermissionsUi();
- } else {
- getActivity().finish();
- }
- });
-
- mViewModel.getNumAutoRevoked().observe(this, show -> updatePermissionsUi());
+ mManagePermissionsViewModel.getUsedPermissionGroups().observe(this,
+ this::onPermissionGroupsChanged);
+ mManageStandardPermissionsViewModel.getNumAutoRevoked().observe(this,
+ this::onNumAutoRevokedChanged);
}
@Override
- protected int getScreenHeaderRes() {
- return R.string.app_permission_manager;
+ public void onCreatePreferences(Bundle bundle, String s) {
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
}
- @Override
- protected void updatePermissionsUi() {
- updatePermissionsUi(/* addSystemPermissions= */ true);
-
- // Check if we need an additional permissions preference
- List<PermissionGroup> groups = getPermissions().getGroups();
- int numExtraPermissions = 0;
- for (PermissionGroup group : groups) {
- if (!group.getDeclaringPackage().equals(AutoManagePermissionsFragment.OS_PKG)) {
- numExtraPermissions++;
- }
+ private void onPermissionGroupsChanged(List<PermGroupPackagesUiInfo> permissionGroups) {
+ final Context context = getPreferenceManager().getContext();
+ if (context == null) {
+ return;
}
- Preference additionalPermissionsPreference = getPreferenceScreen().findPreference(
- EXTRA_PREFS_KEY);
- if (numExtraPermissions == 0) {
- if (additionalPermissionsPreference != null) {
- getPreferenceScreen().removePreference(additionalPermissionsPreference);
- }
+ final PreferenceScreen screen = getPreferenceScreen();
+
+ // First check if "Other preferences" button exists. If it does: remove it, but hold on to
+ // the reference - we'll it add back later, after the preferences for the permission groups
+ // have been updated. If it does not exist: create and hold on to it.
+ Preference otherPermissionsPreference = screen.findPreference(KEY_OTHER_PERMISSIONS);
+ if (otherPermissionsPreference == null) {
+ otherPermissionsPreference = buildOtherPermissionsPreference(context);
} else {
- if (additionalPermissionsPreference == null) {
- additionalPermissionsPreference = new Preference(
- getPreferenceManager().getContext());
- additionalPermissionsPreference.setKey(EXTRA_PREFS_KEY);
- additionalPermissionsPreference.setIcon(Utils.applyTint(getActivity(),
- R.drawable.ic_more_items,
- android.R.attr.colorControlNormal));
- additionalPermissionsPreference.setTitle(R.string.additional_permissions);
- additionalPermissionsPreference.setOnPreferenceClickListener(preference -> {
- AutoManageCustomPermissionsFragment frag =
- new AutoManageCustomPermissionsFragment();
- frag.setTargetFragment(AutoManageStandardPermissionsFragment.this,
- /* requestCode= */ 0);
- FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.replace(android.R.id.content, frag);
- ft.addToBackStack(null);
- ft.commit();
- return true;
- });
-
- getPreferenceScreen().addPreference(additionalPermissionsPreference);
- }
-
- additionalPermissionsPreference.setSummary(getResources().getQuantityString(
- R.plurals.additional_permissions_more, numExtraPermissions,
- numExtraPermissions));
+ screen.removePreference(otherPermissionsPreference);
+ // The PreferenceScreen is ordering items as added
+ // (see PreferenceGroup#setOrderingAsAdded()), which means that it assigns positional
+ // indexes ("order") to Preferences incrementally as they are added, BUT ONLY IF their
+ // current "order" is the DEFAULT_ORDER.
+ // However, when the Preferences are removed from the group they keep their "order" and
+ // thus when they are re-added to a group (same or another) their "order" does not get
+ // re-assigned, so they may show up at the position they previously were at.
+ // We want the otherPermissionsPreference to always be the last in the list, so reset
+ // its "order" to DEFAULT, so that we add last to the group, it indeed goes into the
+ // last position.
+ otherPermissionsPreference.setOrder(Preference.DEFAULT_ORDER);
}
- Integer numAutoRevoked = mViewModel.getNumAutoRevoked().getValue();
+ PermissionGroupPreferenceUtils.updateGroupOfPermissionPreferences(context, screen,
+ permissionGroups);
- Preference autoRevokePreference = getPreferenceScreen().findPreference(AUTO_REVOKE_KEY);
+ screen.addPreference(otherPermissionsPreference);
+
+ // load initial auto-revoke count, if it is ready
+ Integer numAutoRevoked = mManageStandardPermissionsViewModel.getNumAutoRevoked().getValue();
+ onNumAutoRevokedChanged(numAutoRevoked);
+
+ setLoading(false);
+ }
+
+
+ private Preference buildOtherPermissionsPreference(Context context) {
+ final Preference preference = new Preference(context);
+ preference.setPersistent(false);
+ preference.setKey(KEY_OTHER_PERMISSIONS);
+ preference.setTitle(R.string.other_permissions_label);
+ preference.setIcon(
+ Utils.applyTint(
+ context, R.drawable.ic_more_items, android.R.attr.colorControlNormal));
+ preference.setOnPreferenceClickListener(p -> {
+ AutoManageOtherPermissionsFragment frag =
+ new AutoManageOtherPermissionsFragment();
+ frag.setTargetFragment(AutoManageStandardPermissionsFragment.this,
+ /* requestCode= */ 0);
+ FragmentTransaction ft = getFragmentManager().beginTransaction();
+ ft.replace(android.R.id.content, frag);
+ ft.addToBackStack(null);
+ ft.commit();
+ return true;
+ });
+ // Make invisible for now and subscribe to the LiveData that tracks whether there are any
+ // unused or additional permissions.
+ preference.setVisible(false);
+ mManagePermissionsViewModel.hasUnusedOrAdditionalPermissionGroups().observe(this,
+ preference::setVisible);
+ return preference;
+ }
+
+ private void onNumAutoRevokedChanged(Integer numAutoRevoked) {
+ // to prevent ui jank, don't display auto-revoke until categories have loaded
+ if (mManagePermissionsViewModel.getUsedPermissionGroups().getValue() == null) {
+ return;
+ }
+ Preference autoRevokePreference = getPreferenceScreen().findPreference(KEY_AUTO_REVOKE);
if (numAutoRevoked != null && numAutoRevoked != 0) {
if (autoRevokePreference == null) {
autoRevokePreference = new Preference(getPreferenceManager().getContext());
autoRevokePreference.setOrder(-1);
- autoRevokePreference.setKey(AUTO_REVOKE_KEY);
+ autoRevokePreference.setKey(KEY_AUTO_REVOKE);
autoRevokePreference.setSingleLineTitle(false);
autoRevokePreference.setIcon(R.drawable.ic_info_outline);
autoRevokePreference.setTitle(
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
index dfd5361..94fd6b9 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoPermissionAppsFragment.java
@@ -16,82 +16,272 @@
package com.android.permissioncontroller.permission.ui.auto;
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+import static com.android.permissioncontroller.permission.ui.Category.ALLOWED;
+import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND;
+import static com.android.permissioncontroller.permission.ui.Category.ASK;
+import static com.android.permissioncontroller.permission.ui.Category.DENIED;
+import static com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_CALLER_NAME;
+
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.os.Bundle;
+import android.os.UserHandle;
import android.util.ArrayMap;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProvider;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceGroup;
+import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
-import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.model.legacy.PermissionApps;
-import com.android.permissioncontroller.permission.model.legacy.PermissionApps.Callback;
-import com.android.permissioncontroller.permission.ui.handheld.PermissionAppsFragment;
-import com.android.permissioncontroller.permission.ui.handheld.PermissionControlPreference;
+import com.android.permissioncontroller.permission.model.AppPermissionUsage;
+import com.android.permissioncontroller.permission.model.PermissionUsages;
+import com.android.permissioncontroller.permission.ui.Category;
+import com.android.permissioncontroller.permission.ui.handheld.SmartIconLoadPackagePermissionPreference;
+import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel;
+import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory;
+import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.settingslib.utils.applications.AppUtils;
import java.text.Collator;
import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
+import java.util.Random;
+
+import kotlin.Pair;
/** Shows the list of applications which have (or do not have) the given permission. */
-public class AutoPermissionAppsFragment extends AutoSettingsFrameFragment implements Callback {
+public class AutoPermissionAppsFragment extends AutoSettingsFrameFragment implements
+ PermissionUsages.PermissionsUsagesChangeCallback {
- private static final String KEY_SHOW_SYSTEM_PREFS = "_showSystem";
- private static final String KEY_ALLOWED_PERMISSIONS_GROUP = "allowed_permissions_group";
- private static final String KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP =
- "allowed_foreground_permissions_group";
- private static final String KEY_DENIED_PERMISSIONS_GROUP = "denied_permissions_group";
-
- private static final String SHOW_SYSTEM_KEY = AutoPermissionAppsFragment.class.getName()
- + KEY_SHOW_SYSTEM_PREFS;
+ private static final String LOG_TAG = "AutoPermissionAppsFragment";
+ private static final String KEY_EMPTY = "_empty";
/** Creates a new instance of {@link AutoPermissionAppsFragment} for the given permission. */
- public static AutoPermissionAppsFragment newInstance(String permissionName) {
- return setPermissionName(new AutoPermissionAppsFragment(), permissionName);
+ public static AutoPermissionAppsFragment newInstance(String permissionName, long sessionId) {
+ return setPermissionName(new AutoPermissionAppsFragment(), permissionName, sessionId);
}
- private static <T extends Fragment> T setPermissionName(T fragment, String permissionName) {
+ private static <T extends Fragment> T setPermissionName(
+ T fragment, String permissionName, long sessionId) {
Bundle arguments = new Bundle();
arguments.putString(Intent.EXTRA_PERMISSION_NAME, permissionName);
+ arguments.putLong(EXTRA_SESSION_ID, sessionId);
fragment.setArguments(arguments);
return fragment;
}
- private PermissionApps mPermissionApps;
-
- private boolean mShowSystem;
- private boolean mHasSystemApps;
+ private PermissionAppsViewModel mViewModel;
+ private PermissionUsages mPermissionUsages;
+ private List<AppPermissionUsage> mAppPermissionUsages = new ArrayList<>();
+ private String mPermGroupName;
private Collator mCollator;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
- if (savedInstanceState != null) {
- mShowSystem = savedInstanceState.getBoolean(SHOW_SYSTEM_KEY);
- }
-
setLoading(true);
- String groupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
- mPermissionApps = new PermissionApps(getActivity(), groupName, /* callback= */ this);
- mPermissionApps.refresh(/* getUiInfo= */ true);
+ mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_GROUP_NAME);
+ if (mPermGroupName == null) {
+ mPermGroupName = getArguments().getString(Intent.EXTRA_PERMISSION_NAME);
+ }
+
+ Drawable icon = KotlinUtils.INSTANCE.getPermGroupIcon(getContext(), mPermGroupName);
+ CharSequence label = KotlinUtils.INSTANCE.getPermGroupLabel(getContext(), mPermGroupName);
+ CharSequence description = KotlinUtils.INSTANCE.getPermGroupDescription(getContext(),
+ mPermGroupName);
+
+ setHeaderLabel(label);
+ Preference header = new Preference(getContext());
+ header.setTitle(label);
+ header.setIcon(icon);
+ header.setSummary(Utils.getPermissionGroupDescriptionString(getContext(), mPermGroupName,
+ description));
+ getPreferenceScreen().addPreference(header);
mCollator = Collator.getInstance(
getContext().getResources().getConfiguration().getLocales().get(0));
- setShowSystemAppsToggle();
- bindUi(mPermissionApps, groupName);
+ PermissionAppsViewModelFactory factory =
+ new PermissionAppsViewModelFactory(getActivity().getApplication(), mPermGroupName,
+ this, new Bundle());
+ mViewModel = new ViewModelProvider(this, factory).get(PermissionAppsViewModel.class);
+
+ mViewModel.getCategorizedAppsLiveData().observe(this, this::onPackagesLoaded);
+ mViewModel.getShouldShowSystemLiveData().observe(this, this::updateMenu);
+ mViewModel.getHasSystemAppsLiveData().observe(this, this::hideSystemAppToggleIfNecessary);
+
+ // If the build type is below S, the app ops for permission usage can't be found. Thus, we
+ // shouldn't load permission usages, for them.
+ if (SdkLevel.isAtLeastS()) {
+ Context context = getPreferenceManager().getContext();
+ mPermissionUsages = new PermissionUsages(context);
+
+ long filterTimeBeginMillis = mViewModel.getFilterTimeBeginMillis();
+ mPermissionUsages.load(null, null, filterTimeBeginMillis, Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST, getActivity().getLoaderManager(),
+ false, false, this, false);
+ }
+ }
+
+ private void updateMenu(Boolean showSystem) {
+ if (showSystem == null) {
+ showSystem = false;
+ }
+ // Show the opposite label from the current state.
+ String label;
+ if (showSystem) {
+ label = getString(R.string.menu_hide_system);
+ } else {
+ label = getString(R.string.menu_show_system);
+ }
+
+ boolean showSystemFinal = showSystem;
+ setAction(label, v -> mViewModel.updateShowSystem(!showSystemFinal));
+ }
+
+ /**
+ * Main differences between this phone implementation and this one are:
+ * <ul>
+ * <li>No special handling for scoped storage</li>
+ * </ul>
+ */
+ private void onPackagesLoaded(Map<Category, List<Pair<String, UserHandle>>> categories) {
+ Preference additionalPermissionsPreference = getPreferenceScreen().findPreference(
+ ALLOWED_FOREGROUND.getCategoryName());
+ if (additionalPermissionsPreference == null) {
+ // This preference resources includes the "Ask" permission group. That's okay for Auto
+ // even though Auto doesn't support the one-time permission because the code later in
+ // this method will hide unused permission groups.
+ addPreferencesFromResource(R.xml.allowed_denied);
+ }
+ // Hide allowed foreground label by default, to avoid briefly showing it before updating
+ findPreference(ALLOWED_FOREGROUND.getCategoryName()).setVisible(false);
+ Context context = getPreferenceManager().getContext();
+
+ if (context == null || getActivity() == null || categories == null) {
+ return;
+ }
+
+ Map<String, Preference> existingPrefs = new ArrayMap<>();
+
+ // Start at 1 since the header preference will always be in the 0th index
+ for (int i = 1; i < getPreferenceScreen().getPreferenceCount(); i++) {
+ PreferenceCategory category = (PreferenceCategory)
+ getPreferenceScreen().getPreference(i);
+ category.setOrderingAsAdded(true);
+ int numPreferences = category.getPreferenceCount();
+ for (int j = 0; j < numPreferences; j++) {
+ Preference preference = category.getPreference(j);
+ existingPrefs.put(preference.getKey(), preference);
+ }
+ category.removeAll();
+ }
+
+ long viewIdForLogging = new Random().nextLong();
+ long sessionId = getArguments().getLong(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+
+ Boolean showAlways = mViewModel.getShowAllowAlwaysStringLiveData().getValue();
+ if (showAlways != null && showAlways) {
+ findPreference(ALLOWED.getCategoryName()).setTitle(R.string.allowed_always_header);
+ } else {
+ findPreference(ALLOWED.getCategoryName()).setTitle(R.string.allowed_header);
+ }
+
+ // A mapping of user + packageName to their last access timestamps for the permission group.
+ Map<String, Long> groupUsageLastAccessTime =
+ mViewModel.extractGroupUsageLastAccessTime(mAppPermissionUsages);
+
+ for (Category grantCategory : categories.keySet()) {
+ List<Pair<String, UserHandle>> packages = categories.get(grantCategory);
+ PreferenceCategory category = findPreference(grantCategory.getCategoryName());
+
+ // If this category is empty set up the empty preference.
+ if (packages.size() == 0) {
+ Preference empty = new Preference(context);
+ empty.setSelectable(false);
+ empty.setKey(category.getKey() + KEY_EMPTY);
+ if (grantCategory.equals(ALLOWED)) {
+ empty.setTitle(getString(R.string.no_apps_allowed));
+ } else if (grantCategory.equals(ALLOWED_FOREGROUND)) {
+ category.setVisible(false);
+ } else if (grantCategory.equals(ASK)) {
+ category.setVisible(false);
+ } else {
+ empty.setTitle(getString(R.string.no_apps_denied));
+ }
+ category.addPreference(empty);
+ continue;
+ } else if (grantCategory.equals(ALLOWED_FOREGROUND)) {
+ category.setVisible(true);
+ } else if (grantCategory.equals(ASK)) {
+ category.setVisible(true);
+ }
+
+ for (Pair<String, UserHandle> packageUserLabel : packages) {
+ String packageName = packageUserLabel.getFirst();
+ UserHandle user = packageUserLabel.getSecond();
+
+ String key = user + packageName;
+
+ Long lastAccessTime = groupUsageLastAccessTime.get(key);
+ Pair<String, Integer> summaryTimestamp = Utils
+ .getPermissionLastAccessSummaryTimestamp(
+ lastAccessTime, context, mPermGroupName);
+
+ Preference existingPref = existingPrefs.get(key);
+ if (existingPref != null) {
+ updatePreferenceSummary(existingPref, summaryTimestamp);
+ category.addPreference(existingPref);
+ continue;
+ }
+
+ SmartIconLoadPackagePermissionPreference pref =
+ new SmartIconLoadPackagePermissionPreference(getActivity().getApplication(),
+ packageName, user, context);
+ pref.setKey(key);
+ pref.setTitle(KotlinUtils.INSTANCE.getPackageLabel(getActivity().getApplication(),
+ packageName, user));
+ pref.setOnPreferenceClickListener((Preference p) -> {
+ Intent intent = new Intent(Intent.ACTION_MANAGE_APP_PERMISSION);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ intent.putExtra(Intent.EXTRA_PERMISSION_GROUP_NAME, mPermGroupName);
+ intent.putExtra(Intent.EXTRA_USER, user);
+ intent.putExtra(EXTRA_CALLER_NAME, getClass().getName());
+ intent.putExtra(EXTRA_SESSION_ID, sessionId);
+ startActivity(intent);
+ return true;
+ });
+ pref.setTitleContentDescription(AppUtils.getAppContentDescription(context,
+ packageName, user.getIdentifier()));
+
+ updatePreferenceSummary(pref, summaryTimestamp);
+
+ category.addPreference(pref);
+ if (!mViewModel.getCreationLogged()) {
+ logPermissionAppsFragmentCreated(packageName, user, viewIdForLogging,
+ grantCategory.equals(ALLOWED), grantCategory.equals(ALLOWED_FOREGROUND),
+ grantCategory.equals(DENIED));
+ }
+ }
+ KotlinUtils.INSTANCE.sortPreferenceGroup(category, this::comparePreference, false);
+ }
+
+ mViewModel.setCreationLogged(true);
+
+ setLoading(false);
}
@Override
@@ -99,206 +289,44 @@
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
}
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
-
- outState.putBoolean(SHOW_SYSTEM_KEY, mShowSystem);
- }
-
- @Override
- public void onStart() {
- super.onStart();
- mPermissionApps.refresh(/* getUiInfo= */ true);
- }
-
- private void setShowSystemAppsToggle() {
- if (!mHasSystemApps) {
+ private void hideSystemAppToggleIfNecessary(Boolean hasSystemApps) {
+ if (hasSystemApps == null || !hasSystemApps) {
setAction(/* label= */ null, /* onClickListener= */ null);
- return;
}
-
- // Show the opposite label from the current state.
- String label;
- if (mShowSystem) {
- label = getString(R.string.menu_hide_system);
- } else {
- label = getString(R.string.menu_show_system);
- }
-
- setAction(label, v -> {
- mShowSystem = !mShowSystem;
- if (mPermissionApps.getApps() != null) {
- onPermissionsLoaded(mPermissionApps);
- }
- setShowSystemAppsToggle();
- });
}
- private void bindUi(PermissionApps permissionApps, @NonNull String groupName) {
- CharSequence label = permissionApps.getFullLabel();
- setHeaderLabel(label);
-
- Drawable icon = permissionApps.getIcon();
- Preference header = new Preference(getContext());
- header.setTitle(label);
- header.setIcon(icon);
- header.setSummary(Utils.getPermissionGroupDescriptionString(getContext(), groupName,
- permissionApps.getDescription()));
- getPreferenceScreen().addPreference(header);
-
- PreferenceGroup allowed = new PreferenceCategory(getContext());
- allowed.setKey(KEY_ALLOWED_PERMISSIONS_GROUP);
- allowed.setTitle(R.string.allowed_header);
- allowed.setVisible(false);
- getPreferenceScreen().addPreference(allowed);
-
- PreferenceGroup foreground = new PreferenceCategory(getContext());
- foreground.setKey(KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP);
- foreground.setTitle(R.string.allowed_foreground_header);
- foreground.setVisible(false);
- getPreferenceScreen().addPreference(foreground);
-
- PreferenceGroup denied = new PreferenceCategory(getContext());
- denied.setKey(KEY_DENIED_PERMISSIONS_GROUP);
- denied.setTitle(R.string.denied_header);
- denied.setVisible(false);
- getPreferenceScreen().addPreference(denied);
+ private void updatePreferenceSummary(Preference preference,
+ Pair<String, Integer> summaryTimestamp) {
+ String summary = mViewModel.getPreferenceSummary(getResources(), summaryTimestamp);
+ if (!summary.isEmpty()) {
+ preference.setSummary(summary);
+ }
}
@Override
- public void onPermissionsLoaded(PermissionApps permissionApps) {
- Context context = getPreferenceManager().getContext();
-
- if (context == null || getActivity() == null) {
+ @RequiresApi(Build.VERSION_CODES.S)
+ public void onPermissionUsagesChanged() {
+ if (mPermissionUsages.getUsages().isEmpty()) {
+ return;
+ }
+ if (getContext() == null) {
+ // Async result has come in after our context is gone.
return;
}
- PreferenceCategory allowed = findPreference(KEY_ALLOWED_PERMISSIONS_GROUP);
- PreferenceCategory allowedForeground = findPreference(
- KEY_ALLOWED_FOREGROUND_PERMISSIONS_GROUP);
- PreferenceCategory denied = findPreference(KEY_DENIED_PERMISSIONS_GROUP);
+ mAppPermissionUsages = new ArrayList<>(mPermissionUsages.getUsages());
+ onPackagesLoaded(mViewModel.getCategorizedAppsLiveData().getValue());
+ }
- allowed.setOrderingAsAdded(true);
- allowedForeground.setOrderingAsAdded(true);
- denied.setOrderingAsAdded(true);
+ private int comparePreference(Preference lhs, Preference rhs) {
+ return mViewModel.comparePreference(mCollator, lhs, rhs);
+ }
- Map<String, Preference> existingPrefs = new ArrayMap<>();
- int numPreferences = allowed.getPreferenceCount();
- for (int i = 0; i < numPreferences; i++) {
- Preference preference = allowed.getPreference(i);
- existingPrefs.put(preference.getKey(), preference);
- }
- allowed.removeAll();
- numPreferences = allowedForeground.getPreferenceCount();
- for (int i = 0; i < numPreferences; i++) {
- Preference preference = allowedForeground.getPreference(i);
- existingPrefs.put(preference.getKey(), preference);
- }
- allowedForeground.removeAll();
- numPreferences = denied.getPreferenceCount();
- for (int i = 0; i < numPreferences; i++) {
- Preference preference = denied.getPreference(i);
- existingPrefs.put(preference.getKey(), preference);
- }
- denied.removeAll();
-
- mHasSystemApps = false;
- boolean hasPermissionWithBackgroundMode = false;
-
- ArrayList<PermissionApps.PermissionApp> sortedApps = new ArrayList<>(
- permissionApps.getApps());
- sortedApps.sort((x, y) -> {
- int result = mCollator.compare(x.getLabel(), y.getLabel());
- if (result == 0) {
- result = x.getUid() - y.getUid();
- }
- return result;
- });
-
- for (int i = 0; i < sortedApps.size(); i++) {
- PermissionApps.PermissionApp app = sortedApps.get(i);
- AppPermissionGroup group = app.getPermissionGroup();
-
- hasPermissionWithBackgroundMode =
- hasPermissionWithBackgroundMode || group.hasPermissionWithBackgroundMode();
-
- if (!Utils.shouldShowPermission(getContext(), group)) {
- continue;
- }
-
- if (!app.getAppInfo().enabled) {
- continue;
- }
-
- String key = app.getKey();
- Preference existingPref = existingPrefs.get(key);
- if (existingPref != null) {
- // Without this, existing preferences remember their old order.
- existingPref.setOrder(Preference.DEFAULT_ORDER);
- }
-
- boolean isSystemApp = !Utils.isGroupOrBgGroupUserSensitive(group);
-
- if (isSystemApp) {
- mHasSystemApps = true;
- }
-
- if (isSystemApp && !mShowSystem) {
- continue;
- }
-
- PreferenceCategory category;
- if (group.areRuntimePermissionsGranted()) {
- if (!group.hasPermissionWithBackgroundMode()
- || (group.getBackgroundPermissions() != null
- && group.getBackgroundPermissions().areRuntimePermissionsGranted())) {
- category = allowed;
- } else {
- category = allowedForeground;
- }
- } else {
- category = denied;
- }
-
- if (existingPref != null) {
- category.addPreference(existingPref);
- continue;
- }
-
- PermissionControlPreference pref = new PermissionControlPreference(context, group,
- PermissionAppsFragment.class.getName());
- pref.setKey(key);
- pref.setIcon(app.getIcon());
- pref.setTitle(Utils.getFullAppLabel(app.getAppInfo(), context));
- pref.setEllipsizeEnd();
- pref.useSmallerIcon();
- category.addPreference(pref);
- }
-
- if (hasPermissionWithBackgroundMode) {
- allowed.setTitle(R.string.allowed_always_header);
- }
-
- if (allowed.getPreferenceCount() == 0) {
- Preference empty = new Preference(context);
- empty.setTitle(R.string.no_apps_allowed);
- empty.setSelectable(false);
- allowed.addPreference(empty);
- }
- allowed.setVisible(true);
-
- allowedForeground.setVisible(allowedForeground.getPreferenceCount() > 0);
-
- if (denied.getPreferenceCount() == 0) {
- Preference empty = new Preference(context);
- empty.setTitle(R.string.no_apps_denied);
- empty.setSelectable(false);
- denied.addPreference(empty);
- }
- denied.setVisible(true);
-
- setShowSystemAppsToggle();
- setLoading(false);
+ private void logPermissionAppsFragmentCreated(String packageName, UserHandle user, long viewId,
+ boolean isAllowed, boolean isAllowedForeground, boolean isDenied) {
+ long sessionId = getArguments().getLong(EXTRA_SESSION_ID, 0);
+ mViewModel.logPermissionAppsFragmentCreated(packageName, user, viewId, isAllowed,
+ isAllowedForeground, isDenied, sessionId, getActivity().getApplication(),
+ mPermGroupName, LOG_TAG);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
index 2a62d22..11d5b7e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoUnusedAppsFragment.kt
@@ -20,10 +20,12 @@
import android.os.Bundle
import android.os.UserHandle
import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
import com.android.permissioncontroller.R
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment
import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment
+import com.android.permissioncontroller.permission.ui.UnusedAppsFragment.Companion.INFO_MSG_CATEGORY
import com.android.car.ui.utils.ViewUtils
import com.android.car.ui.utils.ViewUtils.LazyLayoutView
@@ -34,6 +36,8 @@
UnusedAppsFragment.Parent<AutoUnusedAppsPreference> {
companion object {
+ private const val UNUSED_PREFERENCE_KEY = "unused_pref_row_key"
+
/** Create a new instance of this fragment. */
@JvmStatic
fun newInstance(): AutoUnusedAppsFragment {
@@ -97,4 +101,25 @@
override fun setTitle(title: CharSequence) {
headerLabel = title
}
+
+ override fun setEmptyState(empty: Boolean) {
+ val infoMsgCategory =
+ preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
+ val noUnusedAppsPreference: Preference? =
+ infoMsgCategory.findPreference<Preference>(UNUSED_PREFERENCE_KEY)
+ if (empty && noUnusedAppsPreference == null) {
+ infoMsgCategory.addPreference(createNoUnusedAppsPreference())
+ } else if (noUnusedAppsPreference != null) {
+ noUnusedAppsPreference.setVisible(empty)
+ }
+ }
+
+ private fun createNoUnusedAppsPreference(): Preference {
+ val preference = Preference(context)
+ preference.title = getString(R.string.zero_unused_apps)
+ preference.key = UNUSED_PREFERENCE_KEY
+ preference.isSelectable = false
+ preference.order = 0
+ return preference
+ }
}
\ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
index 9023a34..a66b15f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/GrantPermissionsAutoViewHandler.java
@@ -160,6 +160,7 @@
}
CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
+ item.setSecure(true);
item.setTitle(mContext.getString(stringId));
item.setOnItemClickedListener(i -> {
mDialog.setOnDismissListener(null);
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 999ca59..cd44832 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionGroupsFragment.java
@@ -68,9 +68,9 @@
import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionUsage;
+import com.android.permissioncontroller.permission.model.PermissionUsages;
import com.android.permissioncontroller.permission.model.livedatatypes.HibernationSettingState;
import com.android.permissioncontroller.permission.ui.Category;
-import com.android.permissioncontroller.permission.ui.handheld.dashboard.PermissionUsages;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModel.GroupUiInfo;
import com.android.permissioncontroller.permission.ui.model.AppPermissionGroupsViewModelFactory;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
index 55686cf..eaf90de 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/HandheldUnusedAppsFragment.kt
@@ -22,9 +22,11 @@
import android.os.UserHandle
import android.view.MenuItem
import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
import com.android.permissioncontroller.R
import com.android.permissioncontroller.hibernation.isHibernationEnabled
import com.android.permissioncontroller.permission.ui.UnusedAppsFragment
+import com.android.permissioncontroller.permission.ui.UnusedAppsFragment.Companion.INFO_MSG_CATEGORY
/**
* Handheld wrapper, with customizations, around [UnusedAppsFragment].
@@ -109,4 +111,10 @@
override fun setTitle(title: CharSequence) {
requireActivity().setTitle(title)
}
+
+ override fun setEmptyState(empty: Boolean) {
+ val infoMsgCategory =
+ preferenceScreen.findPreference<PreferenceCategory>(INFO_MSG_CATEGORY)!!
+ infoMsgCategory.isVisible = !empty
+ }
}
\ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
index 4491557..b28f490 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
@@ -17,23 +17,12 @@
import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED;
-import static com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED;
import static com.android.permissioncontroller.permission.ui.Category.ALLOWED;
import static com.android.permissioncontroller.permission.ui.Category.ALLOWED_FOREGROUND;
import static com.android.permissioncontroller.permission.ui.Category.ASK;
import static com.android.permissioncontroller.permission.ui.Category.DENIED;
import static com.android.permissioncontroller.permission.ui.handheld.UtilsKt.pressBack;
import static com.android.permissioncontroller.permission.ui.handheld.dashboard.UtilsKt.shouldShowPermissionsDashboard;
-import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_CONTENT_PROVIDER;
-import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_SENSOR_TODAY;
-import static com.android.permissioncontroller.permission.utils.Utils.LAST_24H_SENSOR_YESTERDAY;
-import static com.android.permissioncontroller.permission.utils.Utils.NOT_IN_LAST_24H;
-
-import static java.util.concurrent.TimeUnit.DAYS;
import android.Manifest;
import android.app.ActionBar;
@@ -46,7 +35,6 @@
import android.os.Looper;
import android.os.UserHandle;
import android.util.ArrayMap;
-import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -59,12 +47,11 @@
import androidx.preference.PreferenceCategory;
import com.android.modules.utils.build.SdkLevel;
-import com.android.permissioncontroller.PermissionControllerStatsLog;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionUsage;
+import com.android.permissioncontroller.permission.model.PermissionUsages;
import com.android.permissioncontroller.permission.ui.Category;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
-import com.android.permissioncontroller.permission.ui.handheld.dashboard.PermissionUsages;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
@@ -73,9 +60,7 @@
import com.android.settingslib.utils.applications.AppUtils;
import java.text.Collator;
-import java.time.Instant;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
@@ -98,7 +83,6 @@
private static final String STORAGE_ALLOWED_FULL = "allowed_storage_full";
private static final String STORAGE_ALLOWED_SCOPED = "allowed_storage_scoped";
private static final int SHOW_LOAD_DELAY_MS = 200;
- private static final int AGGREGATE_DATA_FILTER_BEGIN_DAYS = 1;
private static final int MENU_PERMISSION_USAGE = MENU_HIDE_SYSTEM + 1;
@@ -167,9 +151,7 @@
Context context = getPreferenceManager().getContext();
mPermissionUsages = new PermissionUsages(context);
- long filterTimeBeginMillis = Math.max(System.currentTimeMillis()
- - DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS),
- Instant.EPOCH.toEpochMilli());
+ long filterTimeBeginMillis = mViewModel.getFilterTimeBeginMillis();
mPermissionUsages.load(null, null, filterTimeBeginMillis, Long.MAX_VALUE,
PermissionUsages.USAGE_FLAG_LAST, getActivity().getLoaderManager(),
false, false, this, false);
@@ -309,8 +291,8 @@
}
// A mapping of user + packageName to their last access timestamps for the permission group.
- Map<String, Long> groupUsageLastAccessTime = new HashMap<>();
- extractGroupUsageLastAccessTime(groupUsageLastAccessTime);
+ Map<String, Long> groupUsageLastAccessTime =
+ mViewModel.extractGroupUsageLastAccessTime(mAppPermissionUsages);
for (Category grantCategory : categories.keySet()) {
List<Pair<String, UserHandle>> packages = categories.get(grantCategory);
@@ -422,57 +404,12 @@
private void updatePreferenceSummary(Preference preference,
Pair<String, Integer> summaryTimestamp) {
- @Utils.AppPermsLastAccessType int lastAccessType = summaryTimestamp.getSecond();
-
- switch (lastAccessType) {
- case LAST_24H_CONTENT_PROVIDER:
- preference.setSummary(
- R.string.app_perms_content_provider);
- break;
- case LAST_24H_SENSOR_TODAY:
- preference.setSummary(
- getString(R.string.app_perms_24h_access,
- summaryTimestamp.getFirst()));
- break;
- case LAST_24H_SENSOR_YESTERDAY:
- preference.setSummary(
- getString(R.string.app_perms_24h_access_yest,
- summaryTimestamp.getFirst()));
- break;
- case NOT_IN_LAST_24H:
- default:
+ String summary = mViewModel.getPreferenceSummary(getResources(), summaryTimestamp);
+ if (!summary.isEmpty()) {
+ preference.setSummary(summary);
}
}
- private void extractGroupUsageLastAccessTime(Map<String, Long> accessTime) {
- accessTime.clear();
- long filterTimeBeginMillis = Math.max(System.currentTimeMillis()
- - DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS), Instant.EPOCH.toEpochMilli());
-
- int numApps = mAppPermissionUsages.size();
- for (int appIndex = 0; appIndex < numApps; appIndex++) {
- AppPermissionUsage appUsage = mAppPermissionUsages.get(appIndex);
- String packageName = appUsage.getPackageName();
-
- List<AppPermissionUsage.GroupUsage> appGroups = appUsage.getGroupUsages();
- int numGroups = appGroups.size();
- for (int groupIndex = 0; groupIndex < numGroups; groupIndex++) {
- AppPermissionUsage.GroupUsage groupUsage = appGroups.get(groupIndex);
- String groupName = groupUsage.getGroup().getName();
- if (!mPermGroupName.equals(groupName)) {
- continue;
- }
-
- long lastAccessTime = groupUsage.getLastAccessTime();
- if (lastAccessTime == 0 || lastAccessTime < filterTimeBeginMillis) {
- continue;
- }
-
- String key = groupUsage.getGroup().getUser() + packageName;
- accessTime.put(key, lastAccessTime);
- }
- }
- }
private int comparePreference(Preference lhs, Preference rhs) {
int result = mCollator.compare(lhs.getTitle().toString(),
@@ -486,27 +423,8 @@
private void logPermissionAppsFragmentCreated(String packageName, UserHandle user, long viewId,
boolean isAllowed, boolean isAllowedForeground, boolean isDenied) {
long sessionId = getArguments().getLong(EXTRA_SESSION_ID, 0);
-
- int category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED;
- if (isAllowed) {
- category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED;
- } else if (isAllowedForeground) {
- category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND;
- } else if (isDenied) {
- category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED;
- }
-
- Integer uid = KotlinUtils.INSTANCE.getPackageUid(getActivity().getApplication(),
- packageName, user);
- if (uid == null) {
- return;
- }
-
- PermissionControllerStatsLog.write(PERMISSION_APPS_FRAGMENT_VIEWED, sessionId, viewId,
- mPermGroupName, uid, packageName, category);
- Log.v(LOG_TAG, "PermissionAppsFragment created with sessionId=" + sessionId
- + " permissionGroupName=" + mPermGroupName + " appUid="
- + uid + " packageName=" + packageName
- + " category=" + category);
+ mViewModel.logPermissionAppsFragmentCreated(packageName, user, viewId, isAllowed,
+ isAllowedForeground, isDenied, sessionId, getActivity().getApplication(),
+ mPermGroupName, LOG_TAG);
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionDetailsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionDetailsFragment.java
index 05e7292..9ab0dc4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionDetailsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionDetailsFragment.java
@@ -58,6 +58,7 @@
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissionUsage;
+import com.android.permissioncontroller.permission.model.PermissionUsages;
import com.android.permissioncontroller.permission.model.legacy.PermissionApps;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsageV2Fragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsageV2Fragment.java
index caeca2d..acc39c2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsageV2Fragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/dashboard/PermissionUsageV2Fragment.java
@@ -52,6 +52,7 @@
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissionUsage;
import com.android.permissioncontroller.permission.model.AppPermissionUsage.GroupUsage;
+import com.android.permissioncontroller.permission.model.PermissionUsages;
import com.android.permissioncontroller.permission.model.legacy.PermissionApps;
import com.android.permissioncontroller.permission.ui.handheld.PermissionUsageV2ControlPreference;
import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
index fa1ce2f..6386e51 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/AppPermissionActivity.java
@@ -19,6 +19,9 @@
import static android.content.Intent.ACTION_MANAGE_APP_PERMISSION;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+import static com.android.permissioncontroller.Constants.EXTRA_SESSION_ID;
+import static com.android.permissioncontroller.Constants.INVALID_SESSION_ID;
+
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
@@ -42,6 +45,7 @@
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.List;
+import java.util.Random;
/**
* Manage a single permission of a single app.
@@ -146,8 +150,13 @@
if (DeviceUtils.isAuto(this)) {
Fragment androidXFragment;
+ long sessionId = getIntent().getLongExtra(EXTRA_SESSION_ID, INVALID_SESSION_ID);
+ while (sessionId == INVALID_SESSION_ID) {
+ sessionId = new Random().nextLong();
+ }
+
androidXFragment = AutoAppPermissionFragment.newInstance(packageName, permissionName,
- groupName, userHandle);
+ groupName, userHandle, sessionId);
getSupportFragmentManager().beginTransaction().replace(android.R.id.content,
androidXFragment).commit();
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
similarity index 96%
rename from PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsViewModel.kt
rename to PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
index 8d4e8c2..970569c 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/ManagePermissionsViewModel.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.television
+package com.android.permissioncontroller.permission.ui.model
import android.app.Application
import androidx.lifecycle.AndroidViewModel
@@ -23,7 +23,6 @@
import com.android.permissioncontroller.permission.data.PermGroupsPackagesUiInfoLiveData
import com.android.permissioncontroller.permission.data.StandardPermGroupNamesLiveData
import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo
-import com.android.permissioncontroller.permission.ui.model.UsedCustomPermGroupNamesLiveData
/**
* A [androidx.lifecycle.ViewModel] for [ManagePermissionsFragment] and
@@ -35,6 +34,7 @@
* [ManagePermissionsViewModel].
*/
class ManagePermissionsViewModel(app: Application) : AndroidViewModel(app) {
+
private val standardPermGroupsLiveData: LiveData<List<PermGroupPackagesUiInfo>> =
MediatorLiveData<List<PermGroupPackagesUiInfo>>().apply {
addSource(PermGroupsPackagesUiInfoLiveData(app, StandardPermGroupNamesLiveData)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
index c7a13db..c4473b1 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt
@@ -19,20 +19,29 @@
import android.Manifest
import android.app.Application
import android.content.Intent
+import android.content.res.Resources
import android.os.Bundle
import android.os.UserHandle
+import android.util.Log
import androidx.fragment.app.Fragment
import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.navigation.fragment.findNavController
+import androidx.preference.Preference
import androidx.savedstate.SavedStateRegistryOwner
+import com.android.permissioncontroller.PermissionControllerStatsLog
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND
+import com.android.permissioncontroller.PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.data.AllPackageInfosLiveData
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState
import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
+import com.android.permissioncontroller.permission.model.AppPermissionUsage
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState
import com.android.permissioncontroller.permission.ui.Category
import com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog
@@ -40,8 +49,14 @@
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.HAS_SYSTEM_APPS_KEY
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOULD_SHOW_SYSTEM_KEY
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel.Companion.SHOW_ALWAYS_ALLOWED
+import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageUid
import com.android.permissioncontroller.permission.utils.LocationUtils
+import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.navigateSafe
+import java.text.Collator
+import java.time.Instant
+import java.util.concurrent.TimeUnit
+import kotlin.math.max
/**
* ViewModel for the PermissionAppsFragment. Has a liveData with all of the UI info for each
@@ -59,6 +74,7 @@
) : ViewModel() {
companion object {
+ const val AGGREGATE_DATA_FILTER_BEGIN_DAYS = 1
internal const val SHOULD_SHOW_SYSTEM_KEY = "showSystem"
internal const val HAS_SYSTEM_APPS_KEY = "hasSystem"
internal const val SHOW_ALWAYS_ALLOWED = "showAlways"
@@ -240,6 +256,110 @@
fragment.findNavController().navigateSafe(R.id.perm_apps_to_app, args)
}
+
+ fun getFilterTimeBeginMillis(): Long {
+ return max(System.currentTimeMillis() -
+ TimeUnit.DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS.toLong()),
+ Instant.EPOCH.toEpochMilli())
+ }
+
+ /**
+ * Return a mapping of user + packageName to their last access timestamps for the permission
+ * group.
+ */
+ fun extractGroupUsageLastAccessTime(appPermissionUsages: List<AppPermissionUsage>):
+ MutableMap<String, Long> {
+ val accessTime: MutableMap<String, Long> = HashMap()
+ val now = System.currentTimeMillis()
+ val filterTimeBeginMillis = max(
+ now - TimeUnit.DAYS.toMillis(AGGREGATE_DATA_FILTER_BEGIN_DAYS.toLong()),
+ Instant.EPOCH.toEpochMilli())
+ val numApps: Int = appPermissionUsages.size
+ for (appIndex in 0 until numApps) {
+ val appUsage: AppPermissionUsage = appPermissionUsages.get(appIndex)
+ val packageName = appUsage.packageName
+ val appGroups = appUsage.groupUsages
+ val numGroups = appGroups.size
+ for (groupIndex in 0 until numGroups) {
+ val groupUsage = appGroups[groupIndex]
+ val groupUsageGroupName = groupUsage.group.name
+ if (groupName != groupUsageGroupName) {
+ continue
+ }
+ val lastAccessTime = groupUsage.lastAccessTime
+ if (lastAccessTime == 0L || lastAccessTime < filterTimeBeginMillis) {
+ continue
+ }
+ val key = groupUsage.group.user.toString() + packageName
+ accessTime[key] = lastAccessTime
+ }
+ }
+ return accessTime
+ }
+
+ /**
+ * Return the String preference summary based on the last access time.
+ */
+ fun getPreferenceSummary(res: Resources, summaryTimestamp: Pair<String, Int>): String {
+ return when (summaryTimestamp.second) {
+ Utils.LAST_24H_CONTENT_PROVIDER -> res.getString(
+ R.string.app_perms_content_provider)
+ Utils.LAST_24H_SENSOR_TODAY -> res.getString(R.string.app_perms_24h_access,
+ summaryTimestamp.first)
+ Utils.LAST_24H_SENSOR_YESTERDAY -> res.getString(R.string.app_perms_24h_access_yest,
+ summaryTimestamp.first)
+ else -> ""
+ }
+ }
+
+ /**
+ * Return two preferences to determine their ordering.
+ */
+ fun comparePreference(collator: Collator, lhs: Preference, rhs: Preference): Int {
+ var result: Int = collator.compare(lhs.title.toString(),
+ rhs.title.toString())
+ if (result == 0) {
+ result = lhs.key.compareTo(rhs.key)
+ }
+ return result
+ }
+
+ /**
+ * Log that the fragment was created.
+ */
+ fun logPermissionAppsFragmentCreated(
+ packageName: String,
+ user: UserHandle,
+ viewId: Long,
+ isAllowed: Boolean,
+ isAllowedForeground: Boolean,
+ isDenied: Boolean,
+ sessionId: Long,
+ application: Application,
+ permGroupName: String,
+ tag: String
+ ) {
+ var category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__UNDEFINED
+ when {
+ isAllowed -> {
+ category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED
+ }
+ isAllowedForeground -> {
+ category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__ALLOWED_FOREGROUND
+ }
+ isDenied -> {
+ category = PERMISSION_APPS_FRAGMENT_VIEWED__CATEGORY__DENIED
+ }
+ }
+ val uid = getPackageUid(application,
+ packageName, user) ?: return
+ PermissionControllerStatsLog.write(
+ PermissionControllerStatsLog.PERMISSION_APPS_FRAGMENT_VIEWED, sessionId, viewId,
+ permGroupName, uid, packageName, category)
+ Log.v(tag, tag + " created with sessionId=" + sessionId +
+ " permissionGroupName=" + permGroupName + " appUid=" + uid +
+ " packageName=" + packageName + " category=" + category)
+ }
}
/**
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreference.java
similarity index 94%
rename from PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreference.java
rename to PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreference.java
index bb45470..b69fb66 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.television;
+package com.android.permissioncontroller.permission.ui.model;
import android.content.Context;
import android.content.Intent;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreferenceUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreferenceUtils.java
similarity index 89%
rename from PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreferenceUtils.java
rename to PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreferenceUtils.java
index a9578ac..49a01ef 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionGroupPreferenceUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionGroupPreferenceUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.television;
+package com.android.permissioncontroller.permission.ui.model;
import android.content.Context;
@@ -27,9 +27,16 @@
import java.util.List;
import java.util.Objects;
-final class PermissionGroupPreferenceUtils {
+/**
+ * Utils related to displaying permission groups in preferences.
+ */
+public final class PermissionGroupPreferenceUtils {
- static void updateGroupOfPermissionPreferences(Context context, PreferenceGroup preferenceGroup,
+ /**
+ * Update a {@link PreferenceGroup} with the specified permission groups.
+ */
+ public static void updateGroupOfPermissionPreferences(Context context,
+ PreferenceGroup preferenceGroup,
List<PermGroupPackagesUiInfo> permissionGroups) {
if (!(permissionGroups instanceof ArrayList)) {
permissionGroups = new ArrayList<>(permissionGroups);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsFragment.java
index 51af4bc..38a899b 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsFragment.java
@@ -31,6 +31,8 @@
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo;
+import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.PermissionGroupPreferenceUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import java.util.List;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsOtherFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsOtherFragment.java
index 6e13dfa..629cf34 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsOtherFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/ManagePermissionsOtherFragment.java
@@ -32,6 +32,8 @@
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.livedatatypes.PermGroupPackagesUiInfo;
+import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel;
+import com.android.permissioncontroller.permission.ui.model.PermissionGroupPreferenceUtils;
import java.util.List;