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.app.settings.SettingsEnums
20 import android.content.pm.ApplicationInfo
21 import android.os.Bundle
22 import android.os.SystemProperties
23 import android.os.UserHandle
24 import android.util.FeatureFlagUtils
25 import androidx.compose.runtime.Composable
26 import androidx.compose.runtime.remember
27 import androidx.compose.runtime.rememberCoroutineScope
28 import androidx.compose.ui.platform.LocalContext
29 import androidx.compose.ui.res.stringResource
30 import androidx.fragment.app.Fragment
31 import androidx.lifecycle.compose.collectAsStateWithLifecycle
32 import androidx.navigation.NavType
33 import androidx.navigation.navArgument
34 import com.android.settings.R
35 import com.android.settings.applications.AppInfoBase
36 import com.android.settings.applications.appinfo.AppInfoDashboardFragment
37 import com.android.settings.flags.Flags
38 import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
39 import com.android.settings.spa.app.appcompat.UserAspectRatioAppPreference
40 import com.android.settings.spa.app.specialaccess.AlarmsAndRemindersAppListProvider
41 import com.android.settings.spa.app.specialaccess.DisplayOverOtherAppsAppListProvider
42 import com.android.settings.spa.app.specialaccess.InstallUnknownAppsListProvider
43 import com.android.settings.spa.app.specialaccess.ModifySystemSettingsAppListProvider
44 import com.android.settings.spa.app.specialaccess.PictureInPictureListProvider
45 import com.android.settingslib.spa.framework.common.SettingsPageProvider
46 import com.android.settingslib.spa.framework.compose.navigator
47 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
48 import com.android.settingslib.spa.widget.ui.Category
49 import com.android.settingslib.spaprivileged.model.app.toRoute
50 import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
51 import kotlinx.coroutines.flow.MutableStateFlow
52 import android.content.pm.FeatureFlags as PmFeatureFlags
53 import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
54 
55 private const val PACKAGE_NAME = "packageName"
56 private const val USER_ID = "userId"
57 
58 object AppInfoSettingsProvider : SettingsPageProvider {
59     override val name = "AppInfoSettings"
60 
61     override val parameter = listOf(
62         navArgument(PACKAGE_NAME) { type = NavType.StringType },
63         navArgument(USER_ID) { type = NavType.IntType },
64     )
65 
66     const val METRICS_CATEGORY = SettingsEnums.APPLICATIONS_INSTALLED_APP_DETAILS
67 
68     @Composable
69     override fun Page(arguments: Bundle?) {
70         val packageName = arguments!!.getString(PACKAGE_NAME)!!
71         val userId = arguments.getInt(USER_ID)
72         val context = LocalContext.current
73         val coroutineScope = rememberCoroutineScope()
74         val packageInfoPresenter = remember {
75             PackageInfoPresenter(context, packageName, userId, coroutineScope)
76         }
77         AppInfoSettings(packageInfoPresenter)
78         packageInfoPresenter.PackageFullyRemovedEffect()
79     }
80 
81     @Composable
82     fun navigator(app: ApplicationInfo) = navigator(route = "$name/${app.toRoute()}")
83 
84     /**
85      * Gets the route to the App Info Settings page.
86      *
87      * Expose route to enable enter from non-SPA pages.
88      */
89     fun getRoute(packageName: String, userId: Int): String = "$name/$packageName/$userId"
90 
91     /**
92      * Starts the App Info Settings page from non-SPA.
93      *
94      * Will starts SPA version if flag [FeatureFlagUtils.SETTINGS_ENABLE_SPA] is true.
95      */
96     @JvmStatic
97     fun startAppInfoSettings(
98         packageName: String,
99         uid: Int,
100         source: Fragment,
101         request: Int,
102         sourceMetricsCategory: Int,
103     ) {
104         val context = source.context ?: return
105         if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_ENABLE_SPA)) {
106             context.startSpaActivity(getRoute(packageName, UserHandle.getUserId(uid)))
107         } else {
108             AppInfoBase.startAppInfoFragment(
109                 AppInfoDashboardFragment::class.java,
110                 context.getString(R.string.application_info_label),
111                 packageName,
112                 uid,
113                 source,
114                 request,
115                 sourceMetricsCategory,
116             )
117         }
118     }
119 }
120 
121 @Composable
AppInfoSettingsnull122 private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
123     val packageInfoState = packageInfoPresenter.flow.collectAsStateWithLifecycle()
124     val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl()
125     RegularScaffold(
126         title = stringResource(R.string.application_info_label),
127         actions = {
128             packageInfoState.value?.applicationInfo?.let { app ->
129                 if (isArchivingEnabled(featureFlags)) TopBarAppLaunchButton(packageInfoPresenter, app)
130                 AppInfoSettingsMoreOptions(packageInfoPresenter, app)
131             }
132         }
133     ) {
134         val packageInfo = packageInfoState.value ?: return@RegularScaffold
135         val app = packageInfo.applicationInfo ?: return@RegularScaffold
136         val appInfoProvider = remember(packageInfo) { AppInfoProvider(packageInfo) }
137         val isHibernationSwitchEnabledStateFlow = MutableStateFlow(false)
138 
139         appInfoProvider.AppInfo()
140 
141         AppButtons(packageInfoPresenter, isHibernationSwitchEnabledStateFlow)
142 
143         AppSettingsPreference(app)
144         AppAllServicesPreference(app)
145         AppNotificationPreference(app)
146         AppPermissionPreference(app)
147         AppStoragePreference(app)
148         InstantAppDomainsPreference(app)
149         AppDataUsagePreference(app)
150         AppTimeSpentPreference(app)
151         AppBatteryPreference(app)
152         AppLocalePreference(app)
153         AppOpenByDefaultPreference(app)
154         DefaultAppShortcuts(app)
155 
156         Category(title = stringResource(R.string.unused_apps_category)) {
157             HibernationSwitchPreference(app, isHibernationSwitchEnabledStateFlow)
158         }
159 
160         Category(title = stringResource(R.string.advanced_apps)) {
161             UserAspectRatioAppPreference(app)
162             DisplayOverOtherAppsAppListProvider.InfoPageEntryItem(app)
163             ModifySystemSettingsAppListProvider.InfoPageEntryItem(app)
164             PictureInPictureListProvider.InfoPageEntryItem(app)
165             InstallUnknownAppsListProvider.InfoPageEntryItem(app)
166             InteractAcrossProfilesDetailsPreference(app)
167             AlarmsAndRemindersAppListProvider.InfoPageEntryItem(app)
168         }
169 
170         Category(title = stringResource(R.string.app_install_details_group_title)) {
171             AppInstallerInfoPreference(app)
172         }
173         appInfoProvider.FooterAppVersion()
174     }
175 }
176 
isArchivingEnablednull177 fun isArchivingEnabled(featureFlags: PmFeatureFlags) =
178         featureFlags.archiving() || Flags.appArchiving()