summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author YoungJoon Yang <youngjoonyang@google.com> 2023-12-06 13:49:58 +0900
committer YoungJoon Yang <youngjoonyang@google.com> 2023-12-06 13:49:58 +0900
commit220ba6395fef8f1ef3928ee3c6a36f0a749e1428 (patch)
tree2c826345d2420630f3af4108dcd034f0c8ccddae
parentd2d700d3968c35badd7681b36cc70220451f7c2e (diff)
Show usage timestamps in WearPermissionApps
Screenshot: https://screenshot.googleplex.com/693ymsMdXbX2svC.png Bug: 309721182 Test: Privacy dashboard -> Contact -> Check timestamps on the chips Change-Id: I5175475c877cf1ef7080d319eb4aa61a3ca4aaa4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt52
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt58
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt6
3 files changed, 107 insertions, 9 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt
index 4fb5b264b..d8eb71e0e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsFragment.kt
@@ -18,19 +18,26 @@ package com.android.permissioncontroller.permission.ui.wear
import android.Manifest
import android.content.Intent
+import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.annotation.RequiresApi
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.Constants
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages
+import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
import com.android.permissioncontroller.permission.ui.handheld.AppPermissionFragment
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModelFactory
/**
* This is a condensed version of
@@ -41,9 +48,15 @@ import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewMo
*
* <p>Shows a list of apps which request at least on permission of this group.
*/
-class WearPermissionAppsFragment : Fragment() {
+class WearPermissionAppsFragment : Fragment(), PermissionsUsagesChangeCallback {
private val LOG_TAG = "PermissionAppsFragment"
+ private lateinit var permissionUsages: PermissionUsages
+ private lateinit var wearViewModel: WearAppPermissionUsagesViewModel
+
+ // Suppress warning of the deprecated class [android.app.LoaderManager] since other form factors
+ // are using the class to load PermissionUsages.
+ @Suppress("DEPRECATION")
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -62,6 +75,9 @@ class WearPermissionAppsFragment : Fragment() {
val factory =
PermissionAppsViewModelFactory(activity.getApplication(), permGroupName, this, Bundle())
val viewModel = ViewModelProvider(this, factory).get(PermissionAppsViewModel::class.java)
+ wearViewModel =
+ ViewModelProvider(this, WearAppPermissionUsagesViewModelFactory())
+ .get(WearAppPermissionUsagesViewModel::class.java)
val onAppClick: (String, UserHandle, String) -> Unit = { packageName, user, category ->
run {
@@ -105,6 +121,26 @@ class WearPermissionAppsFragment : Fragment() {
}
}
+ // 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()) {
+ permissionUsages = PermissionUsages(requireContext())
+
+ val filterTimeBeginMillis: Long = viewModel.getFilterTimeBeginMillis()
+ permissionUsages.load(
+ null,
+ null,
+ filterTimeBeginMillis,
+ Long.MAX_VALUE,
+ PermissionUsages.USAGE_FLAG_LAST,
+ requireActivity().getLoaderManager(),
+ false,
+ false,
+ this,
+ false
+ )
+ }
+
return ComposeView(requireContext()).apply {
setContent {
WearPermissionAppsScreen(
@@ -112,6 +148,7 @@ class WearPermissionAppsFragment : Fragment() {
activity.getApplication(),
permGroupName,
viewModel,
+ wearViewModel,
isStorageAndLessThanT,
onAppClick,
onShowSystemClick,
@@ -121,4 +158,17 @@ class WearPermissionAppsFragment : Fragment() {
}
}
}
+
+ @RequiresApi(Build.VERSION_CODES.S)
+ override fun onPermissionUsagesChanged() {
+ if (permissionUsages.usages.isEmpty()) {
+ return
+ }
+ if (context == null) {
+ // Async result has come in after our context is gone.
+ return
+ }
+ wearViewModel.appPermissionUsages.value =
+ ArrayList<AppPermissionUsage>(permissionUsages.usages)
+ }
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt
index 8d1247e6a..559160b38 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsHelper.kt
@@ -19,12 +19,16 @@ package com.android.permissioncontroller.permission.ui.wear
import android.app.Application
import android.graphics.drawable.Drawable
import android.os.UserHandle
+import com.android.permission.flags.Flags
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage
import com.android.permissioncontroller.permission.ui.Category
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel
+import com.android.permissioncontroller.permission.ui.wear.model.WearAppPermissionUsagesViewModel
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupDescription
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
+import com.android.permissioncontroller.permission.utils.Utils
import com.android.settingslib.utils.applications.AppUtils
import java.text.Collator
import java.util.Random
@@ -34,6 +38,7 @@ class WearPermissionAppsHelper(
val application: Application,
val permGroupName: String,
val viewModel: PermissionAppsViewModel,
+ val wearViewModel: WearAppPermissionUsagesViewModel,
private val isStorageAndLessThanT: Boolean,
private val onAppClick: (String, UserHandle, String) -> Unit,
val onShowSystemClick: (Boolean) -> Unit,
@@ -46,10 +51,15 @@ class WearPermissionAppsHelper(
fun getTitle() = getPermGroupLabel(application, permGroupName).toString()
fun getSubTitle() = getPermGroupDescription(application, permGroupName).toString()
fun getChipsByCategory(
- categorizedApps: Map<Category, List<Pair<String, UserHandle>>>
+ categorizedApps: Map<Category, List<Pair<String, UserHandle>>>,
+ appPermissionUsages: List<AppPermissionUsage>
): Map<String, List<ChipInfo>> {
val chipsByCategory: MutableMap<String, MutableList<ChipInfo>> = HashMap()
+ // A mapping of user + packageName to their last access timestamps for the permission group.
+ val groupUsageLastAccessTime: Map<String, Long> =
+ viewModel.extractGroupUsageLastAccessTime(appPermissionUsages)
+
val context = application
val collator = Collator.getInstance(context.resources.configuration.locales.get(0))
val comparator = ChipComparator(collator)
@@ -64,7 +74,13 @@ class WearPermissionAppsHelper(
.let {
if (it.first.isNotEmpty()) {
chipsByCategory[STORAGE_ALLOWED_FULL] =
- convertToChips(category, it.first, viewIdForLogging, comparator)
+ convertToChips(
+ category,
+ it.first,
+ viewIdForLogging,
+ comparator,
+ groupUsageLastAccessTime
+ )
}
if (it.second.isNotEmpty()) {
chipsByCategory[STORAGE_ALLOWED_SCOPED] =
@@ -72,7 +88,8 @@ class WearPermissionAppsHelper(
category,
it.second,
viewIdForLogging,
- comparator
+ comparator,
+ groupUsageLastAccessTime
)
}
}
@@ -82,7 +99,13 @@ class WearPermissionAppsHelper(
val list = categorizedApps[category]
if (!list.isNullOrEmpty()) {
chipsByCategory[category.categoryName] =
- convertToChips(category, list, viewIdForLogging, comparator)
+ convertToChips(
+ category,
+ list,
+ viewIdForLogging,
+ comparator,
+ groupUsageLastAccessTime
+ )
}
}
@@ -95,17 +118,20 @@ class WearPermissionAppsHelper(
category: Category,
list: List<Pair<String, UserHandle>>,
viewIdForLogging: Long,
- comparator: Comparator<ChipInfo>
+ comparator: Comparator<ChipInfo>,
+ groupUsageLastAccessTime: Map<String, Long>
) =
list
.map { p ->
+ val lastAccessTime = groupUsageLastAccessTime[(p.second.toString() + p.first)]
createAppChipInfo(
application,
p.first,
p.second,
category,
onAppClick,
- viewIdForLogging
+ viewIdForLogging,
+ lastAccessTime
)
}
.sortedWith(comparator)
@@ -121,7 +147,8 @@ class WearPermissionAppsHelper(
user: UserHandle,
category: Category,
onClick: (packageName: String, user: UserHandle, category: String) -> Unit,
- viewIdForLogging: Long
+ viewIdForLogging: Long,
+ lastAccessTime: Long?
): ChipInfo {
if (!viewModel.creationLogged) {
logFragmentCreated(
@@ -133,8 +160,24 @@ class WearPermissionAppsHelper(
category == Category.DENIED
)
}
+ val summary =
+ if (Flags.wearPrivacyDashboardEnabled()) {
+ lastAccessTime?.let {
+ viewModel.getPreferenceSummary(
+ application.resources,
+ Utils.getPermissionLastAccessSummaryTimestamp(
+ lastAccessTime,
+ application,
+ permGroupName
+ )
+ )
+ }
+ } else {
+ null
+ }
return ChipInfo(
title = KotlinUtils.getPackageLabel(application, packageName, user),
+ summary = summary,
contentDescription =
AppUtils.getAppContentDescription(application, packageName, user.getIdentifier()),
icon = KotlinUtils.getBadgedPackageIcon(application, packageName, user),
@@ -184,6 +227,7 @@ class WearPermissionAppsHelper(
class ChipInfo(
val title: String,
+ val summary: String? = null,
val contentDescription: String? = null,
val onClick: () -> Unit = {},
val icon: Drawable? = null,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt
index 08733d3b2..154fd0bff 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionAppsScreen.kt
@@ -38,12 +38,14 @@ fun WearPermissionAppsScreen(helper: WearPermissionAppsHelper) {
val categorizedApps = helper.categorizedAppsLiveData().observeAsState(emptyMap())
val hasSystemApps = helper.hasSystemAppsLiveData().observeAsState(false)
val showSystem = helper.shouldShowSystemLiveData().observeAsState(false)
+ val appPermissionUsages = helper.wearViewModel.appPermissionUsages.observeAsState(emptyList())
var isLoading by remember { mutableStateOf(true) }
val title = helper.getTitle()
val subTitle = helper.getSubTitle()
val showAlways = helper.showAlways()
- val chipsByCategory = helper.getChipsByCategory(categorizedApps.value)
+ val chipsByCategory =
+ helper.getChipsByCategory(categorizedApps.value, appPermissionUsages.value)
WearPermissionAppsContent(
chipsByCategory,
@@ -89,6 +91,8 @@ internal fun WearPermissionAppsContent(
Chip(
label = it.title,
labelMaxLines = Int.MAX_VALUE,
+ secondaryLabel = it.summary,
+ secondaryLabelMaxLines = Int.MAX_VALUE,
icon = it.icon,
enabled = it.enabled,
onClick = { it.onClick() },