1 /*
2  * 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.Intent
21 import android.content.pm.ApplicationInfo
22 import android.content.pm.PackageManager
23 import android.content.pm.PackageManager.ResolveInfoFlags
24 import android.net.Uri
25 import androidx.compose.runtime.Composable
26 import androidx.compose.runtime.getValue
27 import androidx.compose.runtime.remember
28 import androidx.compose.ui.platform.LocalContext
29 import androidx.compose.ui.res.stringResource
30 import androidx.lifecycle.compose.collectAsStateWithLifecycle
31 import com.android.settings.R
32 import com.android.settings.applications.AppInfoBase
33 import com.android.settings.applications.AppLocaleUtil
34 import com.android.settings.applications.appinfo.AppLocaleDetails
35 import com.android.settings.localepicker.AppLocalePickerActivity
36 import com.android.settingslib.spa.widget.preference.Preference
37 import com.android.settingslib.spa.widget.preference.PreferenceModel
38 import com.android.settingslib.spaprivileged.model.app.userHandle
39 import com.android.settingslib.spaprivileged.model.app.userId
40 import kotlinx.coroutines.Dispatchers
41 import kotlinx.coroutines.flow.flow
42 import kotlinx.coroutines.withContext
43 
44 @Composable
AppLocalePreferencenull45 fun AppLocalePreference(app: ApplicationInfo) {
46     val context = LocalContext.current
47     val presenter = remember { AppLocalePresenter(context, app) }
48     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
49 
50     val summary by presenter.summaryFlow.collectAsStateWithLifecycle(
51         initialValue = stringResource(R.string.summary_placeholder),
52     )
53     Preference(object : PreferenceModel {
54         override val title = stringResource(R.string.app_locale_preference_title)
55         override val summary = { summary }
56         override val onClick = presenter::startActivity
57     })
58 }
59 
60 private class AppLocalePresenter(
61     private val context: Context,
62     private val app: ApplicationInfo,
63 ) {
64     private val packageManager = context.packageManager
65 
<lambda>null66     val isAvailableFlow = flow { emit(isAvailable()) }
67 
<lambda>null68     private suspend fun isAvailable(): Boolean = withContext(Dispatchers.IO) {
69         val resolveInfos = packageManager.queryIntentActivitiesAsUser(
70             AppLocaleUtil.LAUNCHER_ENTRY_INTENT,
71             ResolveInfoFlags.of(PackageManager.GET_META_DATA.toLong()),
72             app.userId,
73         )
74         AppLocaleUtil.canDisplayLocaleUi(context, app, resolveInfos)
75     }
76 
<lambda>null77     val summaryFlow = flow { emit(getSummary()) }
78 
<lambda>null79     private suspend fun getSummary() = withContext(Dispatchers.IO) {
80         AppLocaleDetails.getSummary(context, app).toString()
81     }
82 
startActivitynull83     fun startActivity() {
84         val intent = Intent(context, AppLocalePickerActivity::class.java).apply {
85             data = Uri.parse("package:" + app.packageName)
86             putExtra(AppInfoBase.ARG_PACKAGE_UID, app.uid)
87         }
88         context.startActivityAsUser(intent, app.userHandle)
89     }
90 }
91