• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.spa.app.appinfo
18 
19 import android.content.Context
20 import android.content.pm.ApplicationInfo
21 import android.net.NetworkTemplate
22 import androidx.compose.runtime.Composable
23 import androidx.compose.runtime.getValue
24 import androidx.compose.runtime.remember
25 import androidx.compose.runtime.rememberCoroutineScope
26 import androidx.compose.ui.platform.LocalContext
27 import androidx.compose.ui.res.stringResource
28 import androidx.lifecycle.compose.collectAsStateWithLifecycle
29 import com.android.settings.R
30 import com.android.settings.Utils
31 import com.android.settings.applications.appinfo.AppInfoDashboardFragment
32 import com.android.settings.datausage.AppDataUsage
33 import com.android.settings.datausage.lib.AppDataUsageSummaryRepository
34 import com.android.settings.datausage.lib.IAppDataUsageSummaryRepository
35 import com.android.settings.datausage.lib.INetworkTemplates
36 import com.android.settings.datausage.lib.NetworkTemplates
37 import com.android.settings.datausage.lib.NetworkTemplates.getTitleResId
38 import com.android.settingslib.spa.widget.preference.Preference
39 import com.android.settingslib.spa.widget.preference.PreferenceModel
40 import com.android.settingslib.spaprivileged.model.app.hasFlag
41 import kotlinx.coroutines.CoroutineScope
42 import kotlinx.coroutines.Dispatchers
43 import kotlinx.coroutines.flow.SharingStarted
44 import kotlinx.coroutines.flow.flow
45 import kotlinx.coroutines.flow.map
46 import kotlinx.coroutines.flow.shareIn
47 import kotlinx.coroutines.withContext
48 
49 @Composable
50 fun AppDataUsagePreference(
51     app: ApplicationInfo,
52     networkTemplates: INetworkTemplates = NetworkTemplates,
53     repositoryFactory: (
54         context: Context,
55         networkTemplate: NetworkTemplate,
56     ) -> IAppDataUsageSummaryRepository = { context, networkTemplate ->
57         AppDataUsageSummaryRepository(context, networkTemplate)
58     }
59 ) {
60     val context = LocalContext.current
61     val coroutineScope = rememberCoroutineScope()
<lambda>null62     val presenter = remember(app) {
63         AppDataUsagePresenter(context, app, coroutineScope, networkTemplates, repositoryFactory)
64     }
65     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
66 
67     val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
68         initialValue = stringResource(R.string.computing_size),
69     )
70     Preference(object : PreferenceModel {
71         override val title = stringResource(
72             presenter.titleResIdFlow.collectAsStateWithLifecycle(
73                 initialValue = R.string.summary_placeholder,
74             ).value
75         )
<lambda>null76         override val summary = { summary }
<lambda>null77         override val enabled = { presenter.isEnabled() }
78         override val onClick = presenter::startActivity
79     })
80 }
81 
82 private class AppDataUsagePresenter(
83     private val context: Context,
84     private val app: ApplicationInfo,
85     coroutineScope: CoroutineScope,
86     networkTemplates: INetworkTemplates,
87     private val repositoryFactory: (
88         context: Context,
89         networkTemplate: NetworkTemplate,
90     ) -> IAppDataUsageSummaryRepository,
91 ) {
<lambda>null92     val isAvailableFlow = flow { emit(isAvailable()) }
93 
<lambda>null94     private suspend fun isAvailable(): Boolean = withContext(Dispatchers.IO) {
95         Utils.isBandwidthControlEnabled()
96     }
97 
isEnablednull98     fun isEnabled() = app.hasFlag(ApplicationInfo.FLAG_INSTALLED)
99 
100     private val templateFlow = flow {
101         emit(withContext(Dispatchers.IO) {
102             networkTemplates.getDefaultTemplate(context)
103         })
104     }.shareIn(coroutineScope, SharingStarted.WhileSubscribed(), 1)
105 
<lambda>null106     val titleResIdFlow = templateFlow.map { it.getTitleResId() }
<lambda>null107     val summaryFlow = templateFlow.map { getSummary(it) }
108 
<lambda>null109     private suspend fun getSummary(template: NetworkTemplate) = withContext(Dispatchers.IO) {
110         val appUsageData = repositoryFactory(context, template).querySummary(app.uid)
111         if (appUsageData == null || appUsageData.usage == 0L) {
112             context.getString(R.string.no_data_usage)
113         } else {
114             context.getString(
115                 R.string.data_summary_format,
116                 appUsageData.formatUsage(context).displayText,
117                 appUsageData.formatStartDate(context),
118             )
119         }
120     }
121 
startActivitynull122     fun startActivity() {
123         AppInfoDashboardFragment.startAppInfoFragment(
124             AppDataUsage::class.java,
125             app,
126             context,
127             AppInfoSettingsProvider.METRICS_CATEGORY,
128         )
129     }
130 }
131