summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author mrulhania <mrulhania@google.com> 2025-02-02 22:11:20 -0800
committer mrulhania <mrulhania@google.com> 2025-02-03 09:35:56 -0800
commit314693e4b0099a955fa0cb974b575865bf7f19da (patch)
treec6dd7f3fc5991f92620c96200fcf9e6c8844f173
parent4d9853a88e879df10068caaca5acd1f2f4258760 (diff)
Remove Livedata implementation for permission timeline page
livedata_refactor_permission_timeline_enabled flag was enabled in Nov mainline release, and the old impl can be removed now. No functional change in this CL. Bug: 354234946 Test: atest PermissionUsageDetailsViewModelTest PermissionUsageDetailsViewModelTest FLAG: EXEMPT removing obsolete code Relnote: code cleanup Change-Id: I2555f963cfcc2ddfaf802f69064a2981717682ae
-rw-r--r--PermissionController/lint-baseline.xml136
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt147
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java8
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/BasePermissionUsageDetailsViewModel.kt124
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt827
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelV2.kt242
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt3
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/ui/model/PermissionUsageDetailsViewModelTest.kt9
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/PermissionUsageDetailsViewModelTest.kt108
11 files changed, 360 insertions, 1259 deletions
diff --git a/PermissionController/lint-baseline.xml b/PermissionController/lint-baseline.xml
index be77a0d18..b1570d0b7 100644
--- a/PermissionController/lint-baseline.xml
+++ b/PermissionController/lint-baseline.xml
@@ -1,16 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
-
- <issue
- id="NewApi"
- message="Class requires API level 34 (current min is 31): `android.app.AppOpsManager.OnOpNotedListener`"
- errorLine1=" AppOpsManager.OnOpNotedListener,"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt"
- line="46"
- column="5"/>
- </issue>
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name=""
+ variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
@@ -20,7 +10,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="504"
- column="31"/>
+ column="31" />
</issue>
<issue
@@ -31,7 +21,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="505"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -42,7 +32,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="509"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -53,7 +43,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="513"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -64,7 +54,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="515"
- column="59"/>
+ column="59" />
</issue>
<issue
@@ -75,7 +65,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="518"
- column="42"/>
+ column="42" />
</issue>
<issue
@@ -86,7 +76,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="519"
- column="42"/>
+ column="42" />
</issue>
<issue
@@ -97,7 +87,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="521"
- column="18"/>
+ column="18" />
</issue>
<issue
@@ -108,7 +98,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java"
line="522"
- column="29"/>
+ column="29" />
</issue>
<issue
@@ -119,7 +109,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="709"
- column="31"/>
+ column="31" />
</issue>
<issue
@@ -130,7 +120,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="710"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -141,7 +131,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="714"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -152,7 +142,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="718"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -163,7 +153,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="720"
- column="59"/>
+ column="59" />
</issue>
<issue
@@ -174,7 +164,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="722"
- column="67"/>
+ column="67" />
</issue>
<issue
@@ -185,7 +175,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="722"
- column="42"/>
+ column="42" />
</issue>
<issue
@@ -196,7 +186,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="724"
- column="18"/>
+ column="18" />
</issue>
<issue
@@ -207,7 +197,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java"
line="725"
- column="29"/>
+ column="29" />
</issue>
<issue
@@ -218,7 +208,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java"
line="159"
- column="35"/>
+ column="35" />
</issue>
<issue
@@ -229,7 +219,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionsFragment.java"
line="367"
- column="35"/>
+ column="35" />
</issue>
<issue
@@ -240,7 +230,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="463"
- column="31"/>
+ column="31" />
</issue>
<issue
@@ -251,7 +241,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="464"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -262,7 +252,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="468"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -273,7 +263,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="472"
- column="41"/>
+ column="41" />
</issue>
<issue
@@ -284,7 +274,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="474"
- column="59"/>
+ column="59" />
</issue>
<issue
@@ -295,7 +285,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="476"
- column="67"/>
+ column="67" />
</issue>
<issue
@@ -306,7 +296,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="476"
- column="42"/>
+ column="42" />
</issue>
<issue
@@ -317,7 +307,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="478"
- column="18"/>
+ column="18" />
</issue>
<issue
@@ -328,7 +318,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java"
line="479"
- column="29"/>
+ column="29" />
</issue>
<issue
@@ -339,7 +329,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt"
line="1059"
- column="45"/>
+ column="45" />
</issue>
<issue
@@ -350,7 +340,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
line="48"
- column="74"/>
+ column="74" />
</issue>
<issue
@@ -361,7 +351,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/data/HibernatedPackagesLiveData.kt"
line="51"
- column="44"/>
+ column="44" />
</issue>
<issue
@@ -372,7 +362,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/IssueCardAnimator.kt"
line="47"
- column="37"/>
+ column="37" />
</issue>
<issue
@@ -383,7 +373,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
line="653"
- column="29"/>
+ column="29" />
</issue>
<issue
@@ -394,7 +384,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
line="662"
- column="18"/>
+ column="18" />
</issue>
<issue
@@ -405,7 +395,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/utils/KotlinUtils.kt"
line="1689"
- column="48"/>
+ column="48" />
</issue>
<issue
@@ -416,7 +406,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
line="140"
- column="72"/>
+ column="72" />
</issue>
<issue
@@ -427,7 +417,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/model/livedatatypes/LightPackageInfo.kt"
line="140"
- column="62"/>
+ column="62" />
</issue>
<issue
@@ -438,7 +428,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="288"
- column="19"/>
+ column="19" />
</issue>
<issue
@@ -449,7 +439,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="291"
- column="48"/>
+ column="48" />
</issue>
<issue
@@ -460,7 +450,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="291"
- column="30"/>
+ column="30" />
</issue>
<issue
@@ -471,7 +461,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="292"
- column="30"/>
+ column="30" />
</issue>
<issue
@@ -482,7 +472,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="292"
- column="39"/>
+ column="39" />
</issue>
<issue
@@ -493,7 +483,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="298"
- column="5"/>
+ column="5" />
</issue>
<issue
@@ -504,7 +494,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="298"
- column="12"/>
+ column="12" />
</issue>
<issue
@@ -515,7 +505,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="301"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -526,7 +516,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/model/LiveSafetyCenterViewModel.kt"
line="308"
- column="13"/>
+ column="13" />
</issue>
<issue
@@ -537,7 +527,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt"
line="110"
- column="21"/>
+ column="21" />
</issue>
<issue
@@ -548,7 +538,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/ui/MoreIssuesCardAnimator.kt"
line="110"
- column="46"/>
+ column="46" />
</issue>
<issue
@@ -559,7 +549,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
line="114"
- column="35"/>
+ column="35" />
</issue>
<issue
@@ -570,7 +560,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/television/PermissionAppsFragment.java"
line="365"
- column="35"/>
+ column="35" />
</issue>
<issue
@@ -581,7 +571,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/ui/model/PermissionAppsViewModel.kt"
line="100"
- column="43"/>
+ column="43" />
</issue>
<issue
@@ -592,7 +582,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
line="521"
- column="43"/>
+ column="43" />
</issue>
<issue
@@ -603,7 +593,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
line="521"
- column="75"/>
+ column="75" />
</issue>
<issue
@@ -614,7 +604,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
line="522"
- column="48"/>
+ column="48" />
</issue>
<issue
@@ -625,7 +615,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java"
line="522"
- column="24"/>
+ column="24" />
</issue>
<issue
@@ -636,7 +626,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
line="85"
- column="42"/>
+ column="42" />
</issue>
<issue
@@ -647,7 +637,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
line="97"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -658,7 +648,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
line="141"
- column="73"/>
+ column="73" />
</issue>
<issue
@@ -669,7 +659,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
line="146"
- column="34"/>
+ column="34" />
</issue>
<issue
@@ -680,7 +670,7 @@
<location
file="packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/safetycenter/service/SafetyCenterBackgroundRefreshJobService.java"
line="152"
- column="29"/>
+ column="29" />
</issue>
</issues> \ No newline at end of file
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt b/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt
deleted file mode 100644
index a3fc40232..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/data/v31/AllLightHistoricalPackageOpsLiveData.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.permissioncontroller.permission.data.v31
-
-import android.app.AppOpsManager
-import android.app.AppOpsManager.HISTORY_FLAG_DISCRETE
-import android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS
-import android.app.AppOpsManager.HistoricalOps
-import android.app.AppOpsManager.HistoricalOpsRequest
-import android.app.AppOpsManager.OP_FLAG_SELF
-import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
-import android.app.Application
-import android.os.UserHandle
-import android.os.UserManager
-import com.android.modules.utils.build.SdkLevel
-import com.android.permissioncontroller.permission.data.SmartAsyncMediatorLiveData
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps
-import java.util.concurrent.TimeUnit
-import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.Job
-
-/**
- * LiveData class tracking [LightHistoricalPackageOps] for all packages on the device and for the
- * provided app ops.
- *
- * App ops data is retrieved from [AppOpsManager] and is updated whenever app ops data changes are
- * heard.
- */
-class AllLightHistoricalPackageOpsLiveData(app: Application, val opNames: Set<String>) :
- SmartAsyncMediatorLiveData<Map<Pair<String, UserHandle>, LightHistoricalPackageOps>>(),
- AppOpsManager.OnOpActiveChangedListener,
- AppOpsManager.OnOpNotedListener,
- AppOpsManager.OnOpChangedListener {
-
- private val appOpsManager = app.getSystemService(AppOpsManager::class.java)!!
- private val userManager = app.getSystemService(UserManager::class.java)!!
-
- override fun onActive() {
- super.onActive()
-
- opNames.forEach { opName ->
- // TODO(b/262035952): We watch each active op individually as startWatchingActive only
- // registers the callback if all ops are valid. Fix this behavior so if one op is
- // invalid it doesn't affect the other ops.
- try {
- appOpsManager.startWatchingActive(arrayOf(opName), { it.run() }, this)
- } catch (ignored: IllegalArgumentException) {
- // Older builds may not support all requested app ops.
- }
-
- try {
- appOpsManager.startWatchingMode(opName, /* all packages */ null, this)
- } catch (ignored: IllegalArgumentException) {
- // Older builds may not support all requested app ops.
- }
-
- if (SdkLevel.isAtLeastU()) {
- try {
- appOpsManager.startWatchingNoted(arrayOf(opName), this)
- } catch (ignored: IllegalArgumentException) {
- // Older builds may not support all requested app ops.
- }
- }
- }
- }
-
- override fun onInactive() {
- super.onInactive()
-
- appOpsManager.stopWatchingActive(this)
- appOpsManager.stopWatchingMode(this)
- }
-
- override suspend fun loadDataAndPostValue(job: Job) {
- if (job.isCancelled) {
- return
- }
-
- val allLightHistoricalPackageOps =
- mutableMapOf<Pair<String, UserHandle>, LightHistoricalPackageOps>()
-
- val endTimeMillis = System.currentTimeMillis()
- val beginTimeMillis = endTimeMillis - TimeUnit.DAYS.toMillis(7)
-
- val allProfilesInCurrentUser = userManager.userProfiles
-
- val request =
- HistoricalOpsRequest.Builder(beginTimeMillis, endTimeMillis)
- .setFlags(OP_FLAG_SELF or OP_FLAG_TRUSTED_PROXIED)
- .setHistoryFlags(HISTORY_FLAG_DISCRETE or HISTORY_FLAG_GET_ATTRIBUTION_CHAINS)
- .build()
-
- val historicalOps = suspendCoroutine {
- appOpsManager.getHistoricalOps(request, { it.run() }) { ops: HistoricalOps ->
- it.resumeWith(Result.success(ops))
- }
- }
-
- for (i in 0 until historicalOps.uidCount) {
- val historicalUidOps = historicalOps.getUidOpsAt(i)
- val userHandle = UserHandle.getUserHandleForUid(historicalUidOps.uid)
- if (userHandle !in allProfilesInCurrentUser) {
- continue
- }
- for (j in 0 until historicalUidOps.packageCount) {
- val historicalPackageOps = historicalUidOps.getPackageOpsAt(j)
- allLightHistoricalPackageOps[Pair(historicalPackageOps.packageName, userHandle)] =
- LightHistoricalPackageOps(historicalPackageOps, userHandle, opNames)
- }
- }
-
- postValue(allLightHistoricalPackageOps)
- }
-
- override fun onOpChanged(op: String?, packageName: String?) {
- update()
- }
-
- override fun onOpActiveChanged(op: String, uid: Int, packageName: String, active: Boolean) {
- update()
- }
-
- override fun onOpNoted(
- code: String,
- uid: Int,
- packageName: String,
- attributionTag: String?,
- flags: Int,
- result: Int
- ) {
- update()
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
index 8edd39913..2ecf40ce2 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
@@ -35,7 +35,6 @@ import com.android.permissioncontroller.R
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.auto.AutoDividerPreference
-import com.android.permissioncontroller.permission.ui.model.v31.BasePermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
@@ -80,7 +79,7 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment() {
private val SESSION_ID_KEY = (AutoPermissionUsageFragment::class.java.name + KEY_SESSION_ID)
- private lateinit var usageViewModel: BasePermissionUsageDetailsViewModel
+ private lateinit var usageViewModel: PermissionUsageDetailsViewModel
private lateinit var filterGroup: String
private var showSystem = false
@@ -119,11 +118,10 @@ class AutoPermissionUsageDetailsFragment : AutoSettingsFrameFragment() {
val factory =
PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory(
PermissionControllerApplication.get(),
- this,
filterGroup,
)
usageViewModel =
- ViewModelProvider(this, factory)[BasePermissionUsageDetailsViewModel::class.java]
+ ViewModelProvider(this, factory)[PermissionUsageDetailsViewModel::class.java]
usageViewModel.getPermissionUsagesDetailsInfoUiLiveData().observe(this, this::updateUI)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
index 3a904c466..9078f1a0a 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/PermissionUsageDetailsFragment.java
@@ -54,7 +54,7 @@ import com.android.permissioncontroller.PermissionControllerApplication;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
import com.android.permissioncontroller.permission.ui.handheld.SettingsWithLargeHeader;
-import com.android.permissioncontroller.permission.ui.model.v31.BasePermissionUsageDetailsViewModel;
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel;
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo;
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState;
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory;
@@ -89,7 +89,7 @@ public class PermissionUsageDetailsFragment extends SettingsWithLargeHeader {
private MenuItem mShow7DaysDataMenu;
private MenuItem mShow24HoursDataMenu;
- private BasePermissionUsageDetailsViewModel mViewModel;
+ private PermissionUsageDetailsViewModel mViewModel;
private long mSessionId;
@@ -103,9 +103,9 @@ public class PermissionUsageDetailsFragment extends SettingsWithLargeHeader {
}
PermissionUsageDetailsViewModelFactory factory =
new PermissionUsageDetailsViewModelFactory(
- PermissionControllerApplication.get(), this, mPermissionGroup);
+ PermissionControllerApplication.get(), mPermissionGroup);
mViewModel =
- new ViewModelProvider(this, factory).get(BasePermissionUsageDetailsViewModel.class);
+ new ViewModelProvider(this, factory).get(PermissionUsageDetailsViewModel.class);
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getLong(SESSION_ID_KEY);
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/BasePermissionUsageDetailsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/BasePermissionUsageDetailsViewModel.kt
deleted file mode 100644
index 64c5c6927..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/BasePermissionUsageDetailsViewModel.kt
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2024 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.model.v31
-
-import android.app.Application
-import android.graphics.drawable.Drawable
-import android.os.UserHandle
-import androidx.lifecycle.AndroidViewModel
-import androidx.lifecycle.LiveData
-import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.handheld.v31.getDurationUsedStr
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.CLUSTER_SPACING_MINUTES
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState
-import com.android.permissioncontroller.permission.utils.KotlinUtils
-import java.util.concurrent.TimeUnit
-
-abstract class BasePermissionUsageDetailsViewModel(val app: Application) : AndroidViewModel(app) {
- abstract fun getPermissionUsagesDetailsInfoUiLiveData(): LiveData<PermissionUsageDetailsUiState>
-
- abstract fun getShowSystem(): Boolean
-
- abstract val showSystemLiveData: LiveData<Boolean>
-
- abstract fun getShow7Days(): Boolean
-
- abstract fun updateShowSystemAppsToggle(showSystem: Boolean)
-
- abstract fun updateShow7DaysToggle(show7Days: Boolean)
-
- private val packageIconCache: MutableMap<Pair<String, UserHandle>, Drawable> = mutableMapOf()
- private val packageLabelCache: MutableMap<String, String> = mutableMapOf()
-
- /**
- * Returns the label for the provided package name, by first searching the cache otherwise
- * retrieving it from the app's [android.content.pm.ApplicationInfo].
- */
- fun getPackageLabel(packageName: String, user: UserHandle): String {
- if (packageLabelCache.containsKey(packageName)) {
- return requireNotNull(packageLabelCache[packageName])
- }
- val packageLabel = getPackageLabel(app, packageName, user)
- packageLabelCache[packageName] = packageLabel
- return packageLabel
- }
-
- open fun getPackageLabel(app: Application, packageName: String, user: UserHandle): String {
- return KotlinUtils.getPackageLabel(app, packageName, user)
- }
-
- /**
- * Returns the icon for the provided package name and user, by first searching the cache
- * otherwise retrieving it from the app's [android.content.pm.ApplicationInfo].
- */
- fun getBadgedPackageIcon(packageName: String, userHandle: UserHandle): Drawable? {
- val packageNameWithUser: Pair<String, UserHandle> = Pair(packageName, userHandle)
- if (packageIconCache.containsKey(packageNameWithUser)) {
- return requireNotNull(packageIconCache[packageNameWithUser])
- }
- val packageIcon = getBadgedPackageIcon(app, packageName, userHandle)
- if (packageIcon != null) packageIconCache[packageNameWithUser] = packageIcon
-
- return packageIcon
- }
-
- open fun getBadgedPackageIcon(
- app: Application,
- packageName: String,
- user: UserHandle
- ): Drawable? {
- return KotlinUtils.getBadgedPackageIcon(app, packageName, user)
- }
-
- fun getDurationSummary(durationMs: Long): String? {
- // Only show the duration summary if it is at least (CLUSTER_SPACING_MINUTES + 1) minutes.
- // Displaying a time that is shorter than the cluster granularity
- // (CLUSTER_SPACING_MINUTES) will not convey useful information.
- if (durationMs >= TimeUnit.MINUTES.toMillis(CLUSTER_SPACING_MINUTES + 1)) {
- return getDurationUsedStr(app, durationMs)
- }
- return null
- }
-
- fun buildUsageSummary(
- subAttributionLabel: String?,
- proxyPackageLabel: String?,
- durationSummary: String?
- ): String? {
- val subTextStrings: MutableList<String> = mutableListOf()
- subAttributionLabel?.let { subTextStrings.add(subAttributionLabel) }
- proxyPackageLabel?.let { subTextStrings.add(it) }
- durationSummary?.let { subTextStrings.add(it) }
- return when (subTextStrings.size) {
- 3 ->
- app.getString(
- R.string.history_preference_subtext_3,
- subTextStrings[0],
- subTextStrings[1],
- subTextStrings[2]
- )
- 2 ->
- app.getString(
- R.string.history_preference_subtext_2,
- subTextStrings[0],
- subTextStrings[1]
- )
- 1 -> subTextStrings[0]
- else -> null
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
index 497e5cc35..ad21ab220 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -13,677 +13,288 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@file:Suppress("DEPRECATION")
package com.android.permissioncontroller.permission.ui.model.v31
import android.Manifest
import android.app.AppOpsManager
+import android.app.AppOpsManager.OPSTR_EMERGENCY_LOCATION
import android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA
import android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE
import android.app.Application
-import android.app.role.RoleManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.location.LocationManager
import android.os.Build
-import android.os.Bundle
import android.os.UserHandle
-import android.os.UserManager
import android.permission.flags.Flags
-import android.util.Log
import androidx.annotation.RequiresApi
-import androidx.lifecycle.AbstractSavedStateViewModelFactory
+import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
-import androidx.savedstate.SavedStateRegistryOwner
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.application
+import androidx.lifecycle.asLiveData
+import androidx.lifecycle.createSavedStateHandle
+import androidx.lifecycle.viewModelScope
+import androidx.lifecycle.viewmodel.CreationExtras
import com.android.modules.utils.build.SdkLevel
import com.android.permissioncontroller.DeviceUtils
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.appops.data.repository.v31.AppOpRepository
import com.android.permissioncontroller.permission.compat.IntentCompat
-import com.android.permissioncontroller.permission.data.AppPermGroupUiInfoLiveData
-import com.android.permissioncontroller.permission.data.LightPackageInfoLiveData
-import com.android.permissioncontroller.permission.data.SmartUpdateMediatorLiveData
-import com.android.permissioncontroller.permission.data.get
-import com.android.permissioncontroller.permission.data.v31.AllLightHistoricalPackageOpsLiveData
-import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.AppPermissionId
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.AppPermissionDiscreteAccesses
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.AttributedAppPermissionDiscreteAccesses
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.Companion.NO_ATTRIBUTION_TAG
-import com.android.permissioncontroller.permission.model.livedatatypes.v31.LightHistoricalPackageOps.DiscreteAccess
+import com.android.permissioncontroller.permission.data.repository.v31.PermissionRepository
+import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModel
+import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModelWrapper
+import com.android.permissioncontroller.permission.domain.usecase.v31.GetPermissionGroupUsageDetailsUseCase
import com.android.permissioncontroller.permission.ui.handheld.v31.getDurationUsedStr
-import com.android.permissioncontroller.permission.ui.handheld.v31.shouldShowSubattributionInPermissionsDashboard
import com.android.permissioncontroller.permission.utils.PermissionMapping
-import com.android.permissioncontroller.permission.utils.Utils
-import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
+import com.android.permissioncontroller.pm.data.repository.v31.PackageRepository
+import com.android.permissioncontroller.role.data.repository.v31.RoleRepository
+import com.android.permissioncontroller.user.data.repository.v31.UserRepository
import java.time.Instant
import java.util.Objects
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit.DAYS
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.stateIn
-/** [ViewModel] for the Permission Usage Details page. */
-@RequiresApi(Build.VERSION_CODES.S)
class PermissionUsageDetailsViewModel(
- private val application: Application,
+ app: Application,
+ private val getPermissionUsageDetailsUseCase: GetPermissionGroupUsageDetailsUseCase,
private val state: SavedStateHandle,
private val permissionGroup: String,
-) : BasePermissionUsageDetailsViewModel(application) {
-
- val allLightHistoricalPackageOpsLiveData =
- AllLightHistoricalPackageOpsLiveData(application, opNames)
- private val appPermGroupUiInfoLiveDataList =
- mutableMapOf<AppPermissionId, AppPermGroupUiInfoLiveData>()
- private val lightPackageInfoLiveDataMap =
- mutableMapOf<Pair<String, UserHandle>, LightPackageInfoLiveData>()
-
- override val showSystemLiveData = state.getLiveData(SHOULD_SHOW_SYSTEM_KEY, false)
- val show7DaysLiveData = state.getLiveData(SHOULD_SHOW_7_DAYS_KEY, false)
-
- private val roleManager =
- Utils.getSystemServiceSafe(application.applicationContext, RoleManager::class.java)
- private val userManager =
- Utils.getSystemServiceSafe(application.applicationContext, UserManager::class.java)
+ scope: CoroutineScope? = null,
+ private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default,
+ private val packageRepository: PackageRepository = PackageRepository.getInstance(app),
+) : AndroidViewModel(app) {
+ private val coroutineScope = scope ?: viewModelScope
+ private val context = app
+
+ private val packageIconCache: MutableMap<Pair<String, UserHandle>, Drawable> = mutableMapOf()
+ private val packageLabelCache: MutableMap<String, String> = mutableMapOf()
+
+ private val showSystemFlow = MutableStateFlow(state[SHOULD_SHOW_SYSTEM_KEY] ?: false)
+ private val show7DaysFlow = MutableStateFlow(state[SHOULD_SHOW_7_DAYS_KEY] ?: false)
+
+ private val permissionTimelineUsagesFlow:
+ StateFlow<PermissionTimelineUsageModelWrapper> by lazy {
+ getPermissionUsageDetailsUseCase(coroutineScope)
+ .flowOn(defaultDispatcher)
+ .stateIn(
+ coroutineScope,
+ SharingStarted.WhileSubscribed(5000),
+ PermissionTimelineUsageModelWrapper.Loading,
+ )
+ }
- /** Updates whether system app permissions usage should be displayed in the UI. */
- override fun updateShowSystemAppsToggle(showSystem: Boolean) {
- if (showSystem != state[SHOULD_SHOW_SYSTEM_KEY]) {
- state[SHOULD_SHOW_SYSTEM_KEY] = showSystem
- }
+ @VisibleForTesting
+ val permissionUsageDetailsUiStateFlow: Flow<PermissionUsageDetailsUiState> by lazy {
+ combine(permissionTimelineUsagesFlow, showSystemFlow, show7DaysFlow) {
+ permissionTimelineUsages,
+ showSystem,
+ show7Days ->
+ permissionTimelineUsages.buildPermissionUsageDetailsUiInfo(showSystem, show7Days)
+ }
+ .flowOn(defaultDispatcher)
}
- /** Updates whether 7 days usage or 1 day usage should be displayed in the UI. */
- override fun updateShow7DaysToggle(show7Days: Boolean) {
- if (show7Days != state[SHOULD_SHOW_7_DAYS_KEY]) {
- state[SHOULD_SHOW_7_DAYS_KEY] = show7Days
- }
+ fun getPermissionUsagesDetailsInfoUiLiveData(): LiveData<PermissionUsageDetailsUiState> {
+ return permissionUsageDetailsUiStateFlow.asLiveData(
+ context = coroutineScope.coroutineContext
+ )
}
- /** Creates a [PermissionUsageDetailsUiState] containing all information to render the UI. */
- fun buildPermissionUsageDetailsUiInfo(): PermissionUsageDetailsUiState {
- val showSystem: Boolean = state[SHOULD_SHOW_SYSTEM_KEY] ?: false
- val show7Days: Boolean = state[SHOULD_SHOW_7_DAYS_KEY] ?: false
- val showPermissionUsagesDuration =
- if (show7Days && DeviceUtils.isHandheld()) {
- TIME_7_DAYS_DURATION
- } else {
- TIME_24_HOURS_DURATION
- }
+ private fun PermissionTimelineUsageModelWrapper.buildPermissionUsageDetailsUiInfo(
+ showSystem: Boolean,
+ show7Days: Boolean,
+ ): PermissionUsageDetailsUiState {
+ if (this is PermissionTimelineUsageModelWrapper.Loading) {
+ return PermissionUsageDetailsUiState.Loading
+ }
+ val timelineUsageModels =
+ (this as PermissionTimelineUsageModelWrapper.Success).timelineUsageModels
val startTime =
- (System.currentTimeMillis() - showPermissionUsagesDuration).coerceAtLeast(
+ (System.currentTimeMillis() - getUsageDuration(show7Days)).coerceAtLeast(
Instant.EPOCH.toEpochMilli()
)
+ val permissionTimelineUsageModels =
+ timelineUsageModels.filter { it.accessEndMillis > startTime }
+ val containsSystemUsages = permissionTimelineUsageModels.any { !it.isUserSensitive }
+ val result =
+ permissionTimelineUsageModels
+ .filter { showSystem || it.isUserSensitive }
+ .map { clusterOps ->
+ val durationSummaryLabel =
+ if (clusterOps.durationMillis > 0) {
+ getDurationSummary(clusterOps.durationMillis)
+ } else {
+ null
+ }
+ val proxyLabel = getProxyPackageLabel(clusterOps)
+ val isEmergencyLocationAccess =
+ isLocationByPassEnabled() &&
+ clusterOps.opNames.any { it == OPSTR_EMERGENCY_LOCATION }
+ val subAttributionLabel =
+ if (isEmergencyLocationAccess) {
+ emergencyLocationAttributionLabel
+ } else {
+ clusterOps.attributionLabel
+ }
+ val showingSubAttribution = !subAttributionLabel.isNullOrEmpty()
+ val summary =
+ buildUsageSummary(subAttributionLabel, proxyLabel, durationSummaryLabel)
+ PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo(
+ UserHandle.of(clusterOps.userId),
+ clusterOps.packageName,
+ getPackageLabel(clusterOps.packageName, UserHandle.of(clusterOps.userId)),
+ permissionGroup,
+ clusterOps.accessStartMillis,
+ clusterOps.accessEndMillis,
+ summary,
+ showingSubAttribution,
+ clusterOps.attributionTags ?: emptySet(),
+ getBadgedPackageIcon(
+ clusterOps.packageName,
+ UserHandle.of(clusterOps.userId),
+ ),
+ isEmergencyLocationAccess,
+ )
+ }
+ .sortedBy { -1 * it.accessStartTime }
return PermissionUsageDetailsUiState.Success(
- buildAppPermissionAccessUiInfoList(
- allLightHistoricalPackageOpsLiveData,
- startTime,
- showSystem
- ),
- containsSystemAppUsages(allLightHistoricalPackageOpsLiveData, startTime),
+ result,
+ containsSystemUsages,
showSystem,
- show7Days
+ show7Days,
)
}
- /**
- * Returns whether the "show/hide system" toggle should be displayed in the UI for the provided
- * [AllLightHistoricalPackageOpsLiveData].
- */
- private fun containsSystemAppUsages(
- allLightHistoricalPackageOpsLiveData: AllLightHistoricalPackageOpsLiveData,
- startTime: Long
- ): Boolean {
- return allLightHistoricalPackageOpsLiveData
- .getLightHistoricalPackageOps()
- ?.flatMap {
- it.appPermissionDiscreteAccesses
- .map { it.withLabel() }
- .filterOutExemptAppPermissions(true)
- .filterAccessesLaterThan(startTime)
- }
- ?.any { isAppPermissionSystem(it.appPermissionId) } ?: false
+ private val emergencyLocationAttributionLabel: String by lazy {
+ context.getString(R.string.privacy_dashboard_emergency_location_enforced_attribution_label)
}
- private fun isPermissionRequestedByApp(appPermissionId: AppPermissionId): Boolean {
- val appRequestedPermissions =
- lightPackageInfoLiveDataMap[
- Pair(appPermissionId.packageName, appPermissionId.userHandle)]
- ?.value
- ?.requestedPermissions ?: listOf()
-
- if (
- appPermissionId.permissionGroup == Manifest.permission_group.LOCATION &&
- appRequestedPermissions.contains(Manifest.permission.LOCATION_BYPASS)
- ) {
- return true
- }
+ fun getShowSystem(): Boolean = showSystemFlow.value
- return appRequestedPermissions.any {
- PermissionMapping.getGroupOfPlatformPermission(it) == appPermissionId.permissionGroup
- }
- }
+ val showSystemLiveData = showSystemFlow.asLiveData(context = coroutineScope.coroutineContext)
- private fun isAppPermissionSystem(appPermissionId: AppPermissionId): Boolean {
- val appPermGroupUiInfo = appPermGroupUiInfoLiveDataList[appPermissionId]?.value
-
- if (appPermGroupUiInfo != null) {
- return appPermGroupUiInfo.isSystem
- } else
- // The AppPermGroupUiInfo may be null if it has either not loaded yet or if the app has not
- // requested any permissions from the permission group in question.
- // The Telecom doesn't request microphone or camera permissions. However, telecom app may
- // use these permissions and they are considered system app permissions, so we return true
- // even if the AppPermGroupUiInfo is unavailable.
- if (
- appPermissionId.packageName == TELECOM_PACKAGE &&
- (appPermissionId.permissionGroup == Manifest.permission_group.CAMERA ||
- appPermissionId.permissionGroup == Manifest.permission_group.MICROPHONE)
- ) {
- return true
+ fun getShow7Days(): Boolean = show7DaysFlow.value
+
+ private fun getUsageDuration(show7Days: Boolean): Long {
+ return if (show7Days && DeviceUtils.isHandheld()) {
+ TIME_7_DAYS_DURATION
+ } else {
+ TIME_24_HOURS_DURATION
}
- return false
}
- /**
- * Extracts access data from [AllLightHistoricalPackageOpsLiveData] and composes
- * [AppPermissionAccessUiInfo]s to be displayed in the UI.
- */
- private fun buildAppPermissionAccessUiInfoList(
- allLightHistoricalPackageOpsLiveData: AllLightHistoricalPackageOpsLiveData,
- startTime: Long,
- showSystem: Boolean
- ): List<AppPermissionAccessUiInfo> {
- return allLightHistoricalPackageOpsLiveData
- .getLightHistoricalPackageOps()
- ?.filter { Utils.shouldShowInSettings(it.userHandle, userManager) }
- ?.flatMap { it.clusterAccesses(startTime, showSystem) }
- ?.map { it.buildAppPermissionAccessUiInfo() }
- ?.sortedBy { -it.accessStartTime } ?: listOf()
- }
+ private fun getProxyPackageLabel(accessCluster: PermissionTimelineUsageModel): String? =
+ accessCluster.proxyPackageName?.let { proxyPackageName ->
+ if (accessCluster.proxyUserId != null) {
+ getPackageLabel(proxyPackageName, UserHandle.of(accessCluster.proxyUserId))
+ } else null
+ }
- private fun LightHistoricalPackageOps.clusterAccesses(
- startTime: Long,
- showSystem: Boolean
- ): List<AppPermissionDiscreteAccessCluster> {
- return if (!shouldShowSubAttributionForApp(getLightPackageInfo(packageName, userHandle)))
- this.clusterAccessesWithoutAttribution(startTime, showSystem)
- else {
- this.clusterAccessesWithAttribution(startTime, showSystem)
+ fun updateShowSystemAppsToggle(showSystem: Boolean) {
+ if (showSystem != state[SHOULD_SHOW_SYSTEM_KEY]) {
+ state[SHOULD_SHOW_SYSTEM_KEY] = showSystem
}
+ showSystemFlow.compareAndSet(!showSystem, showSystem)
}
- /**
- * Clusters accesses that are close enough together in time such that they can be displayed as a
- * single access to the user.
- *
- * Accesses are clustered taking into account any app subattribution, so each cluster will
- * pertain a particular attribution label.
- */
- private fun LightHistoricalPackageOps.clusterAccessesWithAttribution(
- startTime: Long,
- showSystem: Boolean
- ): List<AppPermissionDiscreteAccessCluster> =
- this.attributedAppPermissionDiscreteAccesses
- .flatMap { it.groupAccessesByLabel(getLightPackageInfo(packageName, userHandle)) }
- .filterOutExemptAppPermissions(showSystem)
- .filterAccessesLaterThan(startTime)
- .flatMap { createAccessClusters(it) }
-
- /**
- * Clusters accesses that are close enough together in time such that they can be displayed as a
- * single access to the user.
- *
- * Accesses are clustered disregarding any app subattribution.
- */
- private fun LightHistoricalPackageOps.clusterAccessesWithoutAttribution(
- startTime: Long,
- showSystem: Boolean
- ): List<AppPermissionDiscreteAccessCluster> =
- this.appPermissionDiscreteAccesses
- .map { it.withLabel() }
- .filterOutExemptAppPermissions(showSystem)
- .filterAccessesLaterThan(startTime)
- .flatMap { createAccessClusters(it) }
-
- /** Filters out accesses earlier than the provided start time. */
- private fun List<AppPermissionDiscreteAccessesWithLabel>.filterAccessesLaterThan(
- startTime: Long,
- ): List<AppPermissionDiscreteAccessesWithLabel> =
- this.mapNotNull {
- val updatedDiscreteAccesses =
- it.discreteAccesses.filter { access -> access.accessTimeMs > startTime }
- if (updatedDiscreteAccesses.isEmpty()) null
- else
- AppPermissionDiscreteAccessesWithLabel(
- it.appPermissionId,
- it.attributionLabel,
- it.attributionTags,
- updatedDiscreteAccesses
- )
+ fun updateShow7DaysToggle(show7Days: Boolean) {
+ if (show7Days != state[SHOULD_SHOW_7_DAYS_KEY]) {
+ state[SHOULD_SHOW_7_DAYS_KEY] = show7Days
}
-
- /** Filters out data for apps and permissions that don't need to be displayed in the UI. */
- private fun List<AppPermissionDiscreteAccessesWithLabel>.filterOutExemptAppPermissions(
- showSystem: Boolean
- ): List<AppPermissionDiscreteAccessesWithLabel> {
- val exemptedPackages = Utils.getExemptedPackages(roleManager)
- return filter { !exemptedPackages.contains(it.appPermissionId.packageName) }
- .filter { it.appPermissionId.permissionGroup == permissionGroup }
- .filter { isPermissionRequestedByApp(it.appPermissionId) }
- .filter { showSystem || !isAppPermissionSystem(it.appPermissionId) }
+ show7DaysFlow.compareAndSet(!show7Days, show7Days)
}
/**
- * Converts the provided [AppPermissionDiscreteAccesses] to a
- * [AppPermissionDiscreteAccessesWithLabel] by adding a label.
+ * Returns the label for the provided package name, by first searching the cache otherwise
+ * retrieving it from the app's [android.content.pm.ApplicationInfo].
*/
- private fun AppPermissionDiscreteAccesses.withLabel(): AppPermissionDiscreteAccessesWithLabel =
- AppPermissionDiscreteAccessesWithLabel(
- this.appPermissionId,
- Resources.ID_NULL,
- attributionTags = emptyList(),
- this.discreteAccesses
- )
-
- /** Groups tag-attributed accesses for the provided app and permission by attribution label. */
- private fun AttributedAppPermissionDiscreteAccesses.groupAccessesByLabel(
- lightPackageInfo: LightPackageInfo?
- ): List<AppPermissionDiscreteAccessesWithLabel> {
- if (lightPackageInfo == null) return emptyList()
-
- val appPermissionId = this.appPermissionId
- val labelsToDiscreteAccesses = mutableMapOf<Int, MutableList<DiscreteAccess>>()
- val labelsToTags = mutableMapOf<Int, MutableList<String>>()
-
- val appPermissionDiscreteAccessWithLabels =
- mutableListOf<AppPermissionDiscreteAccessesWithLabel>()
-
- for ((tag, discreteAccesses) in this.attributedDiscreteAccesses) {
- val label: Int =
- if (tag == NO_ATTRIBUTION_TAG) Resources.ID_NULL
- else lightPackageInfo.attributionTagsToLabels[tag] ?: Resources.ID_NULL
-
- if (!labelsToDiscreteAccesses.containsKey(label)) {
- labelsToDiscreteAccesses[label] = mutableListOf()
- }
- labelsToDiscreteAccesses[label]?.addAll(discreteAccesses)
-
- if (!labelsToTags.containsKey(label)) {
- labelsToTags[label] = mutableListOf()
- }
- labelsToTags[label]?.add(tag)
- }
-
- for ((label, discreteAccesses) in labelsToDiscreteAccesses.entries) {
- val tags = labelsToTags[label]?.toList() ?: listOf()
-
- appPermissionDiscreteAccessWithLabels.add(
- AppPermissionDiscreteAccessesWithLabel(
- appPermissionId,
- label,
- tags,
- discreteAccesses.sortedBy { -1 * it.accessTimeMs }
- )
- )
+ fun getPackageLabel(packageName: String, user: UserHandle): String {
+ if (packageLabelCache.containsKey(packageName)) {
+ return requireNotNull(packageLabelCache[packageName])
}
-
- return appPermissionDiscreteAccessWithLabels
+ val packageLabel = packageRepository.getPackageLabel(packageName, user)
+ packageLabelCache[packageName] = packageLabel
+ return packageLabel
}
/**
- * Clusters [DiscreteAccess]es represented by a [AppPermissionDiscreteAccessesWithLabel] into
- * smaller groups to form a list of [AppPermissionDiscreteAccessCluster] instances.
- *
- * [DiscreteAccess]es which have accesses sufficiently close together in time will be places in
- * the same cluster.
+ * Returns the icon for the provided package name and user, by first searching the cache
+ * otherwise retrieving it from the app's [android.content.pm.ApplicationInfo].
*/
- private fun createAccessClusters(
- appPermAccesses: AppPermissionDiscreteAccessesWithLabel,
- ): List<AppPermissionDiscreteAccessCluster> {
- val clusters = mutableListOf<AppPermissionDiscreteAccessCluster>()
- val currentDiscreteAccesses = mutableListOf<DiscreteAccess>()
- // Iterate entries in asc order based on access timestamp.
- for (index in appPermAccesses.discreteAccesses.size - 1 downTo 0) {
- val discreteAccess = appPermAccesses.discreteAccesses[index]
- if (currentDiscreteAccesses.isEmpty()) {
- currentDiscreteAccesses.add(discreteAccess)
- } else if (!canAccessBeAddedToCluster(discreteAccess, currentDiscreteAccesses)) {
- clusters.add(
- AppPermissionDiscreteAccessCluster(
- appPermAccesses.appPermissionId,
- appPermAccesses.attributionLabel,
- appPermAccesses.attributionTags,
- currentDiscreteAccesses.toMutableList(),
- if (isOpClusteredByItself(discreteAccess.opName)) discreteAccess.opName
- else null
- )
- )
- currentDiscreteAccesses.clear()
- currentDiscreteAccesses.add(discreteAccess)
- } else {
- currentDiscreteAccesses.add(discreteAccess)
- }
+ fun getBadgedPackageIcon(packageName: String, userHandle: UserHandle): Drawable? {
+ val packageNameWithUser: Pair<String, UserHandle> = Pair(packageName, userHandle)
+ if (packageIconCache.containsKey(packageNameWithUser)) {
+ return requireNotNull(packageIconCache[packageNameWithUser])
}
-
- if (currentDiscreteAccesses.isNotEmpty()) {
- val opName = currentDiscreteAccesses.last().opName
- clusters.add(
- AppPermissionDiscreteAccessCluster(
- appPermAccesses.appPermissionId,
- appPermAccesses.attributionLabel,
- appPermAccesses.attributionTags,
- currentDiscreteAccesses.toMutableList(),
- if (isOpClusteredByItself(opName)) opName else null
- )
- )
+ val packageIcon = packageRepository.getBadgedPackageIcon(packageName, userHandle)
+ if (packageIcon != null) {
+ packageIconCache[packageNameWithUser] = packageIcon
}
- return clusters
- }
- /**
- * Returns whether the provided [DiscreteAccess] occurred close enough to those in the clustered
- * list that it can be added to the cluster.
- */
- private fun canAccessBeAddedToCluster(
- currentAccess: DiscreteAccess,
- clusteredAccesses: List<DiscreteAccess>
- ): Boolean {
- val clusterOp = clusteredAccesses.last().opName
- if (
- (isOpClusteredByItself(currentAccess.opName) || isOpClusteredByItself(clusterOp)) &&
- currentAccess.opName != clusteredAccesses.last().opName
- ) {
- return false
- }
- val currentAccessMinute = currentAccess.accessTimeMs / ONE_MINUTE_MS
- val prevMostRecentAccessMillis =
- clusteredAccesses.maxOf { discreteAccess ->
- if (discreteAccess.accessDurationMs > 0)
- discreteAccess.accessTimeMs + discreteAccess.accessDurationMs - ONE_MINUTE_MS
- else discreteAccess.accessTimeMs
- }
- val prevMostRecentAccessMinute = prevMostRecentAccessMillis / ONE_MINUTE_MS
- return (currentAccessMinute - prevMostRecentAccessMinute) <= CLUSTER_SPACING_MINUTES
+ return packageIcon
}
- /**
- * Determine if an op should be in its own cluster and hence display as an individual entry in
- * the privacy timeline
- */
- private fun isOpClusteredByItself(opName: String): Boolean {
- if (isLocationByPassEnabled()) {
- return opName == AppOpsManager.OPSTR_EMERGENCY_LOCATION
+ private fun getDurationSummary(durationMs: Long): String? {
+ // Only show the duration summary if it is at least (CLUSTER_SPACING_MINUTES + 1) minutes.
+ // Displaying a time that is shorter than the cluster granularity
+ // (CLUSTER_SPACING_MINUTES) will not convey useful information.
+ if (durationMs >= TimeUnit.MINUTES.toMillis(CLUSTER_SPACING_MINUTES + 1)) {
+ return getDurationUsedStr(application, durationMs)
}
- return false
+ return null
}
- /**
- * Composes all UI information from a [AppPermissionDiscreteAccessCluster] into a
- * [AppPermissionAccessUiInfo].
- */
- private fun AppPermissionDiscreteAccessCluster.buildAppPermissionAccessUiInfo():
- AppPermissionAccessUiInfo {
- val context = application
- // The end minute is exclusive here in terms of access, i.e. [1..5) as the private data
- // was not accessed at minute 5, it helps calculate the duration correctly.
- val accessEndTimeMillis =
- discreteAccesses.maxOf { appOpEvent ->
- if (appOpEvent.accessDurationMs > 0)
- appOpEvent.accessTimeMs + appOpEvent.accessDurationMs
- else appOpEvent.accessTimeMs + ONE_MINUTE_MS
- }
- val accessStartTimeMillis = discreteAccesses.minOf { it.accessTimeMs }
- val durationMs = accessEndTimeMillis - accessStartTimeMillis
- val durationSummaryLabel =
- if (durationMs >= TimeUnit.MINUTES.toMillis(CLUSTER_SPACING_MINUTES + 1)) {
- getDurationUsedStr(context, durationMs)
- } else null
-
- val proxyLabel = getProxyPackageLabel(this)
- val subAttributionLabel = getSubAttributionLabel(this)
- val showingSubAttribution = !subAttributionLabel.isNullOrEmpty()
- val summary =
- buildUsageSummary(context, subAttributionLabel, proxyLabel, durationSummaryLabel)
- val isEmergencyLocationAccess =
- isLocationByPassEnabled() && clusteredOp == AppOpsManager.OPSTR_EMERGENCY_LOCATION
-
- return AppPermissionAccessUiInfo(
- this.appPermissionId.userHandle,
- this.appPermissionId.packageName,
- getPackageLabel(this.appPermissionId.packageName, this.appPermissionId.userHandle),
- permissionGroup,
- accessStartTimeMillis,
- // Make the end time inclusive i.e. [1..4]
- accessEndTimeMillis - ONE_MINUTE_MS,
- summary,
- showingSubAttribution,
- this.attributionTags.toSet(),
- getBadgedPackageIcon(this.appPermissionId.packageName, this.appPermissionId.userHandle),
- isEmergencyLocationAccess
- )
- }
-
- /** Builds a summary of the permission access. */
private fun buildUsageSummary(
- context: Context,
subAttributionLabel: String?,
proxyPackageLabel: String?,
- durationSummary: String?
+ durationSummary: String?,
): String? {
val subTextStrings: MutableList<String> = mutableListOf()
-
subAttributionLabel?.let { subTextStrings.add(subAttributionLabel) }
proxyPackageLabel?.let { subTextStrings.add(it) }
durationSummary?.let { subTextStrings.add(it) }
return when (subTextStrings.size) {
3 ->
- context.getString(
+ application.getString(
R.string.history_preference_subtext_3,
subTextStrings[0],
subTextStrings[1],
- subTextStrings[2]
+ subTextStrings[2],
)
2 ->
- context.getString(
+ application.getString(
R.string.history_preference_subtext_2,
subTextStrings[0],
- subTextStrings[1]
+ subTextStrings[1],
)
1 -> subTextStrings[0]
else -> null
}
}
- /** Returns whether app subattribution should be shown. */
- private fun shouldShowSubAttributionForApp(lightPackageInfo: LightPackageInfo?): Boolean {
- return lightPackageInfo != null &&
- shouldShowSubattributionInPermissionsDashboard() &&
- SubattributionUtils.isSubattributionSupported(lightPackageInfo)
- }
-
- /** Returns the proxied package label if the permission access was proxied. */
- private fun getProxyPackageLabel(accessCluster: AppPermissionDiscreteAccessCluster): String? =
- accessCluster.discreteAccesses
- .firstOrNull { it.proxy?.packageName != null }
- ?.let {
- getPackageLabel(
- it.proxy!!.packageName!!,
- UserHandle.getUserHandleForUid(it.proxy.uid)
- )
- }
-
- /** Returns the attribution label for the permission access, if any. */
- private fun getSubAttributionLabel(accessCluster: AppPermissionDiscreteAccessCluster): String? {
- // Special case for EMERGENCY_LOCATION app op. Show enforced attribution label in the
- // Privacy Dashboard
- if (
- isLocationByPassEnabled() &&
- accessCluster.clusteredOp == AppOpsManager.OPSTR_EMERGENCY_LOCATION
- ) {
- return application.getString(
- R.string.privacy_dashboard_emergency_location_enforced_attribution_label
- )
- }
-
- return if (accessCluster.attributionLabel == Resources.ID_NULL) null
- else {
- val lightPackageInfo = getLightPackageInfo(accessCluster.appPermissionId)
- getSubAttributionLabels(lightPackageInfo)?.get(accessCluster.attributionLabel)
- }
- }
-
- private fun getSubAttributionLabels(lightPackageInfo: LightPackageInfo?): Map<Int, String>? =
- if (lightPackageInfo == null) null
- else SubattributionUtils.getAttributionLabels(application, lightPackageInfo)
-
- private fun getLightPackageInfo(appPermissionId: AppPermissionId) =
- lightPackageInfoLiveDataMap[Pair(appPermissionId.packageName, appPermissionId.userHandle)]
- ?.value
-
- private fun getLightPackageInfo(packageName: String, userHandle: UserHandle) =
- lightPackageInfoLiveDataMap[Pair(packageName, userHandle)]?.value
-
- private fun AllLightHistoricalPackageOpsLiveData.getLightHistoricalPackageOps() =
- this.value?.values
-
- /** Data used to create a preference for an app's permission usage. */
- data class AppPermissionAccessUiInfo(
- val userHandle: UserHandle,
- val packageName: String,
- val packageLabel: String,
- val permissionGroup: String,
- val accessStartTime: Long,
- val accessEndTime: Long,
- val summaryText: CharSequence?,
- val showingAttribution: Boolean,
- val attributionTags: Set<String>,
- val badgedPackageIcon: Drawable?,
- val isEmergencyLocationAccess: Boolean
- )
-
- sealed class PermissionUsageDetailsUiState {
- data object Loading : PermissionUsageDetailsUiState()
-
- data class Success(
- val appPermissionAccessUiInfoList: List<AppPermissionAccessUiInfo>,
- val containsSystemAppUsage: Boolean,
- val showSystem: Boolean,
- val show7Days: Boolean,
- ) : PermissionUsageDetailsUiState()
- }
-
- /**
- * Data class representing a cluster of permission accesses close enough together to be
- * displayed as a single access in the UI.
- */
- private data class AppPermissionDiscreteAccessCluster(
- val appPermissionId: AppPermissionId,
- val attributionLabel: Int,
- val attributionTags: List<String>,
- val discreteAccesses: List<DiscreteAccess>,
- val clusteredOp: String?
- )
-
- /**
- * Data class representing all permission accesses for a particular package, user, permission
- * and attribution label.
- */
- private data class AppPermissionDiscreteAccessesWithLabel(
- val appPermissionId: AppPermissionId,
- val attributionLabel: Int,
- val attributionTags: List<String>,
- val discreteAccesses: List<DiscreteAccess>
- )
-
- /** [LiveData] object for [PermissionUsageDetailsUiState]. */
- private val _permissionUsagesDetailsInfoUiLiveData =
- object :
- SmartUpdateMediatorLiveData<@JvmSuppressWildcards PermissionUsageDetailsUiState>() {
- private val getAppPermGroupUiInfoLiveData = { appPermissionId: AppPermissionId ->
- AppPermGroupUiInfoLiveData[
- Triple(
- appPermissionId.packageName,
- appPermissionId.permissionGroup,
- appPermissionId.userHandle,
- )]
- }
- private val getLightPackageInfoLiveData =
- { packageWithUserHandle: Pair<String, UserHandle> ->
- LightPackageInfoLiveData[packageWithUserHandle]
- }
-
- init {
- addSource(allLightHistoricalPackageOpsLiveData) { update() }
- addSource(showSystemLiveData) { update() }
- addSource(show7DaysLiveData) { update() }
- }
-
- override fun onUpdate() {
- if (!allLightHistoricalPackageOpsLiveData.isInitialized) {
- return
- }
-
- val appPermissionIds = mutableSetOf<AppPermissionId>()
- val allPackages: Set<Pair<String, UserHandle>> =
- allLightHistoricalPackageOpsLiveData.value?.keys ?: setOf()
- for (packageWithUserHandle: Pair<String, UserHandle> in allPackages) {
- val appPermGroupIds =
- allLightHistoricalPackageOpsLiveData.value
- ?.get(packageWithUserHandle)
- ?.appPermissionDiscreteAccesses
- ?.map { it.appPermissionId }
- ?.toSet() ?: setOf()
-
- appPermissionIds.addAll(appPermGroupIds)
- }
-
- setSourcesToDifference(
- appPermissionIds,
- appPermGroupUiInfoLiveDataList,
- getAppPermGroupUiInfoLiveData
- ) {
- update()
- }
- setSourcesToDifference(
- allPackages,
- lightPackageInfoLiveDataMap,
- getLightPackageInfoLiveData
- ) {
- update()
- }
-
- if (appPermGroupUiInfoLiveDataList.any { it.value.isStale }) {
- return
- }
-
- if (lightPackageInfoLiveDataMap.any { it.value.isStale }) {
- return
- }
-
- value = buildPermissionUsageDetailsUiInfo()
- }
- }
-
- override fun getPermissionUsagesDetailsInfoUiLiveData():
- LiveData<PermissionUsageDetailsUiState> = _permissionUsagesDetailsInfoUiLiveData
-
- override fun getShowSystem(): Boolean = showSystemLiveData.value ?: false
-
- override fun getShow7Days(): Boolean = show7DaysLiveData.value ?: false
-
/** Companion object for [PermissionUsageDetailsViewModel]. */
companion object {
- const val ONE_HOUR_MS = 3_600_000
const val ONE_MINUTE_MS = 60_000
const val CLUSTER_SPACING_MINUTES: Long = 1L
- private const val TELECOM_PACKAGE = "com.android.server.telecom"
val TIME_7_DAYS_DURATION: Long = DAYS.toMillis(7)
val TIME_24_HOURS_DURATION: Long = DAYS.toMillis(1)
internal const val SHOULD_SHOW_SYSTEM_KEY = "showSystem"
@@ -694,7 +305,7 @@ class PermissionUsageDetailsViewModel(
listOf(
Manifest.permission_group.CAMERA,
Manifest.permission_group.LOCATION,
- Manifest.permission_group.MICROPHONE
+ Manifest.permission_group.MICROPHONE,
)
.flatMap { group -> PermissionMapping.getPlatformPermissionNamesOfGroup(group) }
.mapNotNull { permName -> AppOpsManager.permissionToOp(permName) }
@@ -719,7 +330,7 @@ class PermissionUsageDetailsViewModel(
accessStartTime: Long,
accessEndTime: Long,
showingAttribution: Boolean,
- attributionTags: Set<String>
+ attributionTags: Set<String>,
): Intent {
return getManagePermissionUsageIntent(
context,
@@ -728,7 +339,7 @@ class PermissionUsageDetailsViewModel(
accessStartTime,
accessEndTime,
showingAttribution,
- attributionTags
+ attributionTags,
) ?: getDefaultManageAppPermissionsIntent(packageName, userHandle)
}
@@ -736,6 +347,7 @@ class PermissionUsageDetailsViewModel(
* Gets an [Intent.ACTION_MANAGE_PERMISSION_USAGE] intent, or null if attribution shouldn't
* be shown or the intent can't be handled.
*/
+ @Suppress("DEPRECATION")
private fun getManagePermissionUsageIntent(
context: Context,
packageName: String,
@@ -743,7 +355,7 @@ class PermissionUsageDetailsViewModel(
accessStartTime: Long,
accessEndTime: Long,
showingAttribution: Boolean,
- attributionTags: Set<String>
+ attributionTags: Set<String>,
): Intent? {
if (
!showingAttribution ||
@@ -768,13 +380,13 @@ class PermissionUsageDetailsViewModel(
val resolveInfo =
context.packageManager.resolveActivity(
intent,
- PackageManager.ResolveInfoFlags.of(0)
+ PackageManager.ResolveInfoFlags.of(0),
)
if (
resolveInfo?.activityInfo == null ||
!Objects.equals(
resolveInfo.activityInfo.permission,
- Manifest.permission.START_VIEW_PERMISSION_USAGE
+ Manifest.permission.START_VIEW_PERMISSION_USAGE,
)
) {
return null
@@ -785,8 +397,9 @@ class PermissionUsageDetailsViewModel(
private fun getDefaultManageAppPermissionsIntent(
packageName: String,
- userHandle: UserHandle
+ userHandle: UserHandle,
): Intent {
+ @Suppress("DEPRECATION")
return Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS).apply {
putExtra(Intent.EXTRA_USER, userHandle)
putExtra(Intent.EXTRA_PACKAGE_NAME, packageName)
@@ -795,29 +408,65 @@ class PermissionUsageDetailsViewModel(
private fun isLocationByPassEnabled(): Boolean =
SdkLevel.isAtLeastV() && Flags.locationBypassPrivacyDashboardEnabled()
+
+ fun create(
+ app: Application,
+ handle: SavedStateHandle,
+ permissionGroup: String,
+ ): PermissionUsageDetailsViewModel {
+ val permissionRepository = PermissionRepository.getInstance(app)
+ val packageRepository = PackageRepository.getInstance(app)
+ val appOpRepository = AppOpRepository.getInstance(app, permissionRepository)
+ val roleRepository = RoleRepository.getInstance(app)
+ val userRepository = UserRepository.getInstance(app)
+ val useCase =
+ GetPermissionGroupUsageDetailsUseCase(
+ permissionGroup,
+ packageRepository,
+ permissionRepository,
+ appOpRepository,
+ roleRepository,
+ userRepository,
+ )
+ return PermissionUsageDetailsViewModel(app, useCase, handle, permissionGroup)
+ }
+ }
+
+ /** Data used to create a preference for an app's permission usage. */
+ data class AppPermissionAccessUiInfo(
+ val userHandle: UserHandle,
+ val packageName: String,
+ val packageLabel: String,
+ val permissionGroup: String,
+ val accessStartTime: Long,
+ val accessEndTime: Long,
+ val summaryText: CharSequence?,
+ val showingAttribution: Boolean,
+ val attributionTags: Set<String>,
+ val badgedPackageIcon: Drawable?,
+ val isEmergencyLocationAccess: Boolean,
+ )
+
+ sealed class PermissionUsageDetailsUiState {
+ data object Loading : PermissionUsageDetailsUiState()
+
+ data class Success(
+ val appPermissionAccessUiInfoList: List<AppPermissionAccessUiInfo>,
+ val containsSystemAppUsage: Boolean,
+ val showSystem: Boolean,
+ val show7Days: Boolean,
+ ) : PermissionUsageDetailsUiState()
}
/** Factory for [PermissionUsageDetailsViewModel]. */
@RequiresApi(Build.VERSION_CODES.S)
class PermissionUsageDetailsViewModelFactory(
val app: Application,
- owner: SavedStateRegistryOwner,
private val permissionGroup: String,
- ) : AbstractSavedStateViewModelFactory(owner, Bundle()) {
- override fun <T : ViewModel> create(
- key: String,
- modelClass: Class<T>,
- handle: SavedStateHandle,
- ): T {
+ ) : ViewModelProvider.Factory {
+ override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
@Suppress("UNCHECKED_CAST")
- return if (
- com.android.permission.flags.Flags.livedataRefactorPermissionTimelineEnabled()
- ) {
- Log.d("PermissionTimeline", "timeline refactor flag enabled..")
- PermissionUsageDetailsViewModelV2.create(app, handle, permissionGroup) as T
- } else {
- PermissionUsageDetailsViewModel(app, handle, permissionGroup) as T
- }
+ return create(app, extras.createSavedStateHandle(), permissionGroup) as T
}
}
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelV2.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelV2.kt
deleted file mode 100644
index 312a7ee20..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelV2.kt
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2024 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.model.v31
-
-import android.app.AppOpsManager.OPSTR_EMERGENCY_LOCATION
-import android.app.Application
-import android.graphics.drawable.Drawable
-import android.os.UserHandle
-import androidx.annotation.VisibleForTesting
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.SavedStateHandle
-import androidx.lifecycle.asLiveData
-import androidx.lifecycle.viewModelScope
-import com.android.permissioncontroller.DeviceUtils
-import com.android.permissioncontroller.R
-import com.android.permissioncontroller.appops.data.repository.v31.AppOpRepository
-import com.android.permissioncontroller.permission.data.repository.v31.PermissionRepository
-import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModel
-import com.android.permissioncontroller.permission.domain.model.v31.PermissionTimelineUsageModelWrapper
-import com.android.permissioncontroller.permission.domain.usecase.v31.GetPermissionGroupUsageDetailsUseCase
-import com.android.permissioncontroller.permission.domain.usecase.v31.isLocationByPassEnabled
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.SHOULD_SHOW_7_DAYS_KEY
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.SHOULD_SHOW_SYSTEM_KEY
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.TIME_24_HOURS_DURATION
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.Companion.TIME_7_DAYS_DURATION
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState
-import com.android.permissioncontroller.pm.data.repository.v31.PackageRepository
-import com.android.permissioncontroller.role.data.repository.v31.RoleRepository
-import com.android.permissioncontroller.user.data.repository.v31.UserRepository
-import java.time.Instant
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.stateIn
-
-class PermissionUsageDetailsViewModelV2(
- app: Application,
- private val getPermissionUsageDetailsUseCase: GetPermissionGroupUsageDetailsUseCase,
- private val state: SavedStateHandle,
- private val permissionGroup: String,
- scope: CoroutineScope? = null,
- private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default,
- private val packageRepository: PackageRepository = PackageRepository.getInstance(app)
-) : BasePermissionUsageDetailsViewModel(app) {
- private val coroutineScope = scope ?: viewModelScope
- private val context = app
-
- private val showSystemFlow = MutableStateFlow(state[SHOULD_SHOW_SYSTEM_KEY] ?: false)
- private val show7DaysFlow = MutableStateFlow(state[SHOULD_SHOW_7_DAYS_KEY] ?: false)
-
- private val permissionTimelineUsagesFlow:
- StateFlow<PermissionTimelineUsageModelWrapper> by lazy {
- getPermissionUsageDetailsUseCase(coroutineScope)
- .flowOn(defaultDispatcher)
- .stateIn(
- coroutineScope,
- SharingStarted.WhileSubscribed(5000),
- PermissionTimelineUsageModelWrapper.Loading
- )
- }
-
- @VisibleForTesting
- val permissionUsageDetailsUiStateFlow: Flow<PermissionUsageDetailsUiState> by lazy {
- combine(permissionTimelineUsagesFlow, showSystemFlow, show7DaysFlow) {
- permissionTimelineUsages,
- showSystem,
- show7Days ->
- permissionTimelineUsages.buildPermissionUsageDetailsUiInfo(showSystem, show7Days)
- }
- .flowOn(defaultDispatcher)
- }
-
- override fun getPermissionUsagesDetailsInfoUiLiveData():
- LiveData<PermissionUsageDetailsUiState> {
- return permissionUsageDetailsUiStateFlow.asLiveData(
- context = coroutineScope.coroutineContext
- )
- }
-
- private fun PermissionTimelineUsageModelWrapper.buildPermissionUsageDetailsUiInfo(
- showSystem: Boolean,
- show7Days: Boolean
- ): PermissionUsageDetailsUiState {
- if (this is PermissionTimelineUsageModelWrapper.Loading) {
- return PermissionUsageDetailsUiState.Loading
- }
- val timelineUsageModels =
- (this as PermissionTimelineUsageModelWrapper.Success).timelineUsageModels
- val startTime =
- (System.currentTimeMillis() - getUsageDuration(show7Days)).coerceAtLeast(
- Instant.EPOCH.toEpochMilli()
- )
-
- val permissionTimelineUsageModels =
- timelineUsageModels.filter { it.accessEndMillis > startTime }
- val containsSystemUsages = permissionTimelineUsageModels.any { !it.isUserSensitive }
- val result =
- permissionTimelineUsageModels
- .filter { showSystem || it.isUserSensitive }
- .map { clusterOps ->
- val durationSummaryLabel =
- if (clusterOps.durationMillis > 0) {
- getDurationSummary(clusterOps.durationMillis)
- } else {
- null
- }
- val proxyLabel = getProxyPackageLabel(clusterOps)
- val isEmergencyLocationAccess =
- isLocationByPassEnabled() &&
- clusterOps.opNames.any { it == OPSTR_EMERGENCY_LOCATION }
- val subAttributionLabel =
- if (isEmergencyLocationAccess) {
- emergencyLocationAttributionLabel
- } else {
- clusterOps.attributionLabel
- }
- val showingSubAttribution = !subAttributionLabel.isNullOrEmpty()
- val summary =
- buildUsageSummary(subAttributionLabel, proxyLabel, durationSummaryLabel)
- PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo(
- UserHandle.of(clusterOps.userId),
- clusterOps.packageName,
- getPackageLabel(clusterOps.packageName, UserHandle.of(clusterOps.userId)),
- permissionGroup,
- clusterOps.accessStartMillis,
- clusterOps.accessEndMillis,
- summary,
- showingSubAttribution,
- clusterOps.attributionTags ?: emptySet(),
- getBadgedPackageIcon(
- clusterOps.packageName,
- UserHandle.of(clusterOps.userId)
- ),
- isEmergencyLocationAccess
- )
- }
- .sortedBy { -1 * it.accessStartTime }
- return PermissionUsageDetailsUiState.Success(
- result,
- containsSystemUsages,
- showSystem,
- show7Days
- )
- }
-
- private val emergencyLocationAttributionLabel: String by lazy {
- context.getString(R.string.privacy_dashboard_emergency_location_enforced_attribution_label)
- }
-
- override fun getShowSystem(): Boolean = showSystemFlow.value
-
- override val showSystemLiveData =
- showSystemFlow.asLiveData(context = coroutineScope.coroutineContext)
-
- override fun getShow7Days(): Boolean = show7DaysFlow.value
-
- private fun getUsageDuration(show7Days: Boolean): Long {
- return if (show7Days && DeviceUtils.isHandheld()) {
- TIME_7_DAYS_DURATION
- } else {
- TIME_24_HOURS_DURATION
- }
- }
-
- private fun getProxyPackageLabel(accessCluster: PermissionTimelineUsageModel): String? =
- accessCluster.proxyPackageName?.let { proxyPackageName ->
- if (accessCluster.proxyUserId != null) {
- getPackageLabel(proxyPackageName, UserHandle.of(accessCluster.proxyUserId))
- } else null
- }
-
- override fun updateShowSystemAppsToggle(showSystem: Boolean) {
- if (showSystem != state[SHOULD_SHOW_SYSTEM_KEY]) {
- state[SHOULD_SHOW_SYSTEM_KEY] = showSystem
- }
- showSystemFlow.compareAndSet(!showSystem, showSystem)
- }
-
- override fun updateShow7DaysToggle(show7Days: Boolean) {
- if (show7Days != state[SHOULD_SHOW_7_DAYS_KEY]) {
- state[SHOULD_SHOW_7_DAYS_KEY] = show7Days
- }
- show7DaysFlow.compareAndSet(!show7Days, show7Days)
- }
-
- // TODO review these methods when old impl is removed, suspend function??
- override fun getPackageLabel(app: Application, packageName: String, user: UserHandle): String {
- return packageRepository.getPackageLabel(packageName, user)
- }
-
- override fun getBadgedPackageIcon(
- app: Application,
- packageName: String,
- user: UserHandle
- ): Drawable? {
- return packageRepository.getBadgedPackageIcon(packageName, user)
- }
-
- companion object {
- fun create(
- app: Application,
- handle: SavedStateHandle,
- permissionGroup: String
- ): PermissionUsageDetailsViewModelV2 {
- val permissionRepository = PermissionRepository.getInstance(app)
- val packageRepository = PackageRepository.getInstance(app)
- val appOpRepository = AppOpRepository.getInstance(app, permissionRepository)
- val roleRepository = RoleRepository.getInstance(app)
- val userRepository = UserRepository.getInstance(app)
- val useCase =
- GetPermissionGroupUsageDetailsUseCase(
- permissionGroup,
- packageRepository,
- permissionRepository,
- appOpRepository,
- roleRepository,
- userRepository
- )
- return PermissionUsageDetailsViewModelV2(app, useCase, handle, permissionGroup)
- }
- }
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt
index 2ade4863a..2d302c2b4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsFragment.kt
@@ -29,7 +29,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
-import com.android.permissioncontroller.permission.ui.model.v31.BasePermissionUsageDetailsViewModel
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsViewModelFactory
/**
@@ -42,7 +42,7 @@ class WearPermissionUsageDetailsFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
+ savedInstanceState: Bundle?,
): View? {
val permissionGroup =
arguments?.getString(Intent.EXTRA_PERMISSION_GROUP_NAME)
@@ -56,11 +56,10 @@ class WearPermissionUsageDetailsFragment : Fragment() {
val factory =
PermissionUsageDetailsViewModelFactory(
PermissionControllerApplication.get(),
- this,
- permissionGroup
+ permissionGroup,
)
val viewModel =
- ViewModelProvider(this, factory).get(BasePermissionUsageDetailsViewModel::class.java)
+ ViewModelProvider(this, factory).get(PermissionUsageDetailsViewModel::class.java)
viewModel.updateShowSystemAppsToggle(showSystem)
return ComposeView(requireContext()).apply {
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt
index 279eaa8cc..adcf9323f 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/wear/WearPermissionUsageDetailsScreen.kt
@@ -31,7 +31,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.ui.model.v31.BasePermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.AppPermissionAccessUiInfo
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState
@@ -45,7 +44,7 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils
@Composable
fun WearPermissionUsageDetailsScreen(
permissionGroup: String,
- viewModel: BasePermissionUsageDetailsViewModel,
+ viewModel: PermissionUsageDetailsViewModel,
) {
val context = LocalContext.current
val uiData = viewModel.getPermissionUsagesDetailsInfoUiLiveData().observeAsState(null)
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/ui/model/PermissionUsageDetailsViewModelTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
index eb5fdefdb..644bdfd15 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
@@ -16,16 +16,14 @@
package com.android.permissioncontroller.permission.ui.model
-import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.SavedStateHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.modules.utils.build.SdkLevel
-import com.android.permission.flags.Flags
import com.android.permissioncontroller.PermissionControllerApplication
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelV2
import com.google.common.truth.Truth
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
@@ -42,15 +40,14 @@ class PermissionUsageDetailsViewModelTest {
@JvmField @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
@Test
- @RequiresFlagsEnabled(Flags.FLAG_LIVEDATA_REFACTOR_PERMISSION_TIMELINE_ENABLED)
fun verifyUiStateIsGeneratedSuccessfully() {
Assume.assumeTrue(SdkLevel.isAtLeastS())
lateinit var uiState: PermissionUsageDetailsUiState.Success
val viewModel =
- PermissionUsageDetailsViewModelV2.create(
+ PermissionUsageDetailsViewModel.create(
PermissionControllerApplication.get(),
SavedStateHandle(mapOf("show7Days" to true, "showSystem" to true)),
- LOCATION_PERMISSION_GROUP
+ LOCATION_PERMISSION_GROUP,
)
val countDownLatch = CountDownLatch(1)
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/PermissionUsageDetailsViewModelTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
index edaea9aba..4334026c3 100644
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
+++ b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/permission/ui/model/PermissionUsageDetailsViewModelTest.kt
@@ -30,8 +30,8 @@ import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.appops.data.model.v31.DiscretePackageOpsModel
import com.android.permissioncontroller.appops.data.model.v31.DiscretePackageOpsModel.DiscreteOpModel
import com.android.permissioncontroller.permission.domain.usecase.v31.GetPermissionGroupUsageDetailsUseCase
+import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel.PermissionUsageDetailsUiState
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelV2
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.StringUtils
import com.android.permissioncontroller.permission.utils.Utils
@@ -67,7 +67,7 @@ import org.mockito.quality.Strictness
/**
* These unit tests are for new permission timeline implementation, the new view model class is
- * [PermissionUsageDetailsViewModelV2]
+ * [PermissionUsageDetailsViewModel]
*/
@RunWith(AndroidJUnit4::class)
class PermissionUsageDetailsViewModelTest {
@@ -107,7 +107,7 @@ class PermissionUsageDetailsViewModelTest {
any(),
anyInt(),
anyInt(),
- any(Array<String>::class.java)
+ any(Array<String>::class.java),
)
)
.thenReturn("Duration Summary")
@@ -119,7 +119,7 @@ class PermissionUsageDetailsViewModelTest {
systemPackageName to
getPackageInfoModel(
systemPackageName,
- applicationFlags = ApplicationInfo.FLAG_SYSTEM
+ applicationFlags = ApplicationInfo.FLAG_SYSTEM,
),
)
.toMutableMap()
@@ -127,7 +127,7 @@ class PermissionUsageDetailsViewModelTest {
packageRepository =
FakePackageRepository(
packageInfos,
- packagesAndLabels = mapOf(testPackageName to testPackageLabel)
+ packagesAndLabels = mapOf(testPackageName to testPackageLabel),
)
}
@@ -140,9 +140,7 @@ class PermissionUsageDetailsViewModelTest {
fun verifyOnlyNonSystemAppsAreShown() = runTest {
val accessTimeMillis = (getCurrentTime() - TimeUnit.HOURS.toMillis(5))
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, accessTimeMillis, -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_COARSE_LOCATION, accessTimeMillis, -1))
val discretePackageOps = flow {
emit(
listOf(
@@ -176,8 +174,8 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val discretePackageOps = flow {
emit(
@@ -192,7 +190,7 @@ class PermissionUsageDetailsViewModelTest {
getViewModel(
LOCATION_PERMISSION_GROUP,
discretePackageOps,
- savedStateMap = mapOf("show7Days" to false, "showSystem" to true)
+ savedStateMap = mapOf("show7Days" to false, "showSystem" to true),
)
val uiState = getPermissionUsageDetailsUiState(underTest)
@@ -210,13 +208,13 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -225,7 +223,7 @@ class PermissionUsageDetailsViewModelTest {
getViewModel(
LOCATION_PERMISSION_GROUP,
discretePackageOps,
- savedStateMap = mapOf("show7Days" to false, "showSystem" to false)
+ savedStateMap = mapOf("show7Days" to false, "showSystem" to false),
)
val uiState = getPermissionUsageDetailsUiState(underTest)
@@ -240,13 +238,13 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(systemPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(systemPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -255,7 +253,7 @@ class PermissionUsageDetailsViewModelTest {
getViewModel(
LOCATION_PERMISSION_GROUP,
discretePackageOps,
- savedStateMap = mapOf("show7Days" to false, "showSystem" to false)
+ savedStateMap = mapOf("show7Days" to false, "showSystem" to false),
)
val uiState = getPermissionUsageDetailsUiState(underTest)
@@ -271,18 +269,18 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessStartWithIn24Hours,
- TimeUnit.MINUTES.toMillis(5)
+ TimeUnit.MINUTES.toMillis(5),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessStartBefore24Hours,
- TimeUnit.MINUTES.toMillis(7)
+ TimeUnit.MINUTES.toMillis(7),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -304,18 +302,18 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessTimeWithIn24Hours,
- TimeUnit.MINUTES.toMillis(5)
+ TimeUnit.MINUTES.toMillis(5),
),
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessTimeBefore24Hours,
- TimeUnit.MINUTES.toMillis(7)
+ TimeUnit.MINUTES.toMillis(7),
),
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -344,13 +342,13 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(5)
- ),
+ TimeUnit.MINUTES.toMillis(5),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -371,13 +369,13 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_CAMERA,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
@@ -397,22 +395,16 @@ class PermissionUsageDetailsViewModelTest {
whenever(application.getString(anyInt())).thenReturn("emergency attr label")
val accessTimeMillis = (getCurrentTime() - TimeUnit.HOURS.toMillis(5))
val appOpEvents =
- listOf(
- DiscreteOpModel(AppOpsManager.OPSTR_EMERGENCY_LOCATION, accessTimeMillis, -1),
- )
+ listOf(DiscreteOpModel(AppOpsManager.OPSTR_EMERGENCY_LOCATION, accessTimeMillis, -1))
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
- val underTest =
- getViewModel(
- LOCATION_PERMISSION_GROUP,
- discretePackageOps,
- )
+ val underTest = getViewModel(LOCATION_PERMISSION_GROUP, discretePackageOps)
val uiState = getPermissionUsageDetailsUiState(underTest)
assertThat(uiState.appPermissionAccessUiInfoList.size).isEqualTo(1)
val timelineRow = uiState.appPermissionAccessUiInfoList.first()
@@ -429,21 +421,15 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val actualData =
- listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
- )
+ listOf(DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents))
val discretePackageOps = MutableStateFlow(emptyList<DiscretePackageOpsModel>())
discretePackageOps.emit(emptyList())
- val underTest =
- getViewModel(
- LOCATION_PERMISSION_GROUP,
- discretePackageOps,
- )
+ val underTest = getViewModel(LOCATION_PERMISSION_GROUP, discretePackageOps)
val result by collectLastValue(underTest.permissionUsageDetailsUiStateFlow)
var uiState = result as PermissionUsageDetailsUiState.Success
assertThat(uiState.appPermissionAccessUiInfoList).isEmpty()
@@ -463,22 +449,18 @@ class PermissionUsageDetailsViewModelTest {
DiscreteOpModel(
AppOpsManager.OPSTR_COARSE_LOCATION,
accessTimeMillis,
- TimeUnit.MINUTES.toMillis(1)
- ),
+ TimeUnit.MINUTES.toMillis(1),
+ )
)
val discretePackageOps = flow {
emit(
listOf(
- DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents),
+ DiscretePackageOpsModel(testPackageName, currentUser.identifier, appOpEvents)
)
)
}
- val underTest =
- getViewModel(
- LOCATION_PERMISSION_GROUP,
- discretePackageOps,
- )
+ val underTest = getViewModel(LOCATION_PERMISSION_GROUP, discretePackageOps)
val uiState = getPermissionUsageDetailsUiState(underTest)
assertThat(uiState.show7Days).isFalse()
@@ -517,20 +499,20 @@ class PermissionUsageDetailsViewModelTest {
permissionGroup: String,
discretePackageOps: Flow<List<DiscretePackageOpsModel>>,
savedStateMap: Map<String, Boolean> = mapOf("show7Days" to false, "showSystem" to false),
- pkgRepository: PackageRepository = packageRepository
+ pkgRepository: PackageRepository = packageRepository,
) =
- PermissionUsageDetailsViewModelV2(
+ PermissionUsageDetailsViewModel(
application,
getPermissionGroupUsageDetailsUseCase(permissionGroup, discretePackageOps),
SavedStateHandle(savedStateMap),
permissionGroup,
scope = backgroundScope,
StandardTestDispatcher(testScheduler),
- packageRepository = pkgRepository
+ packageRepository = pkgRepository,
)
private fun TestScope.getPermissionUsageDetailsUiState(
- viewModel: PermissionUsageDetailsViewModelV2
+ viewModel: PermissionUsageDetailsViewModel
): PermissionUsageDetailsUiState.Success {
val result by collectLastValue(viewModel.permissionUsageDetailsUiStateFlow)
return result as PermissionUsageDetailsUiState.Success
@@ -542,7 +524,7 @@ class PermissionUsageDetailsViewModelTest {
permissionsFlags: List<Int> =
listOf(
PackageInfo.REQUESTED_PERMISSION_GRANTED,
- PackageInfo.REQUESTED_PERMISSION_GRANTED
+ PackageInfo.REQUESTED_PERMISSION_GRANTED,
),
applicationFlags: Int = 0,
) = PackageInfoModel(packageName, requestedPermissions, permissionsFlags, applicationFlags)