blob: dedffda18b00c89cf35352cf9121e18602653958 [file]
/*
* Copyright (C) 2026 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.settings.datausage
import android.util.Log
import com.android.settings.R
import com.android.settings.applications.AppInfoBase
import com.android.settings.applications.InstalledPackageName
import com.android.settings.flags.Flags
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.preferencesapi.PreferencesApiScreen
import com.android.settingslib.metadata.preferencesapi.category.Category
import com.android.settingslib.metadata.preferencesapi.preconditions.Allowed
import com.android.settingslib.metadata.preferencesapi.preconditions.Custom
import com.android.settingslib.metadata.preferencesapi.preconditions.PreconditionStability
import com.android.settingslib.metadata.preferencesapi.types.AnyBoolean
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
/**
* The [PreferencesApiScreen] for the App Data Usage screen.
*
* This screen allows users to view and manage mobile data usage for a specific app.
*/
@ProvidePreferenceScreen(AppDataUsageScreenApi.KEY, parameterized = true)
class AppDataUsageScreenApi :
PreferencesApiScreen(
key = KEY,
topLevelSettingsCategory = Category.APPS,
fragment = AppDataUsage::class,
purpose = R.string.app_data_usage_screen_purpose,
alreadyPartiallyMigrated = DataUsageAppDetailScreen::class,
) {
private val repository = featureFactory.wifiFeatureProvider.dataUsageRepository
private fun getPackageName(): String? = keyParameters?.get(KEY_APP_PACKAGE_NAME)
init {
flag { Flags.catalystMigration26q2() }
parameters {
parameter(
name = KEY_APP_PACKAGE_NAME,
purpose = R.string.app_data_usage_parameter_purpose,
type = InstalledPackageName,
)
prepareScreenExtras { keyParameters, extras ->
val packageName: String =
keyParameters[KEY_APP_PACKAGE_NAME] ?: return@prepareScreenExtras
extras.putString(KEY_APP_PACKAGE_NAME, packageName)
val uid: Int = runBlocking(Dispatchers.IO) { repository.getPackageUid(packageName) }
extras.putInt(AppInfoBase.ARG_PACKAGE_UID, uid)
}
}
preference(
key = KEY_APP_BACKGROUND_DATA_SWITCH,
purpose = R.string.app_background_data_switch_purpose,
type = AnyBoolean,
) {
//not reviewed by security & privacy
get {
execute {
val packageName = getPackageName() ?: return@execute false
!repository.isPolicyReject(packageName)
}
}
set {
execute { value: Boolean ->
val packageName = getPackageName() ?: return@execute
repository.setPolicyReject(packageName, !value)
}
}
}
preference(
key = KEY_APP_UNRESTRICTED_MOBILE_DATA_USAGE_SWITCH,
purpose = R.string.app_unrestricted_mobile_data_usage_switch_purpose,
type = AnyBoolean,
) {
//not reviewed by security & privacy
preconditions(R.string.app_unrestricted_mobile_data_usage_switch_preconditions) {
val packageName =
getPackageName()
?: return@preconditions Custom(R.string.app_package_name_unavailable, stability = PreconditionStability.UNSTABLE)
runBlocking(Dispatchers.IO) {
if (repository.isPolicyAllowAvailable(packageName)) {
Allowed
} else {
Log.w(TAG, "Unrestricted Mobile Data is unavailable for $packageName")
// TODO(b/474027987) Catalyst: migrate the Disallowed to InvalidPreference
Custom(
R.string.app_unrestricted_mobile_data_usage_switch_unavailable,
stability = PreconditionStability.UNSTABLE,
)
}
}
}
get {
execute {
val packageName = getPackageName() ?: return@execute false
repository.isPolicyAllow(packageName)
}
}
set {
execute { value: Boolean ->
val packageName = getPackageName() ?: return@execute
repository.setPolicyAllow(packageName, value)
}
}
}
}
companion object {
private const val TAG = "AppDataUsageScreenApi"
const val KEY = "api_app_data_usage_screen"
const val KEY_APP_PACKAGE_NAME = "app"
const val KEY_APP_BACKGROUND_DATA_SWITCH = "app_background_data_switch"
const val KEY_APP_UNRESTRICTED_MOBILE_DATA_USAGE_SWITCH =
"app_unrestricted_mobile_data_usage_switch"
}
}