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.Intent 21 import android.content.pm.ApplicationInfo 22 import android.content.pm.PackageManager 23 import android.content.res.Resources 24 import android.os.Bundle 25 import android.util.Log 26 import androidx.compose.runtime.Composable 27 import androidx.compose.runtime.getValue 28 import androidx.compose.runtime.remember 29 import androidx.compose.runtime.rememberCoroutineScope 30 import androidx.compose.ui.platform.LocalContext 31 import androidx.compose.ui.res.stringResource 32 import androidx.lifecycle.compose.collectAsStateWithLifecycle 33 import com.android.settings.R 34 import com.android.settingslib.spa.widget.preference.Preference 35 import com.android.settingslib.spa.widget.preference.PreferenceModel 36 import com.android.settingslib.spaprivileged.model.app.resolveActionForApp 37 import com.android.settingslib.spaprivileged.model.app.userHandle 38 import kotlinx.coroutines.CoroutineScope 39 import kotlinx.coroutines.Dispatchers 40 import kotlinx.coroutines.flow.SharingStarted 41 import kotlinx.coroutines.flow.firstOrNull 42 import kotlinx.coroutines.flow.flow 43 import kotlinx.coroutines.flow.flowOn 44 import kotlinx.coroutines.flow.map 45 import kotlinx.coroutines.flow.shareIn 46 import kotlinx.coroutines.launch 47 import kotlinx.coroutines.plus 48 49 @Composable 50 fun AppAllServicesPreference(app: ApplicationInfo) { 51 val context = LocalContext.current 52 val coroutineScope = rememberCoroutineScope() 53 val presenter = remember { AppAllServicesPresenter(context, app, coroutineScope) } 54 if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return 55 56 val summary by presenter.summaryFlow.collectAsStateWithLifecycle( 57 initialValue = stringResource(R.string.summary_placeholder), 58 ) 59 Preference(object : PreferenceModel { 60 override val title = stringResource(R.string.app_info_all_services_label) 61 override val summary = { summary } 62 override val onClick = presenter::startActivity 63 }) 64 } 65 66 private class AppAllServicesPresenter( 67 private val context: Context, 68 private val app: ApplicationInfo, 69 private val coroutineScope: CoroutineScope, 70 ) { 71 private val packageManager = context.packageManager 72 <lambda>null73 private val activityInfoFlow = flow { 74 emit(packageManager.resolveActionForApp( 75 app = app, 76 action = Intent.ACTION_VIEW_APP_FEATURES, 77 flags = PackageManager.GET_META_DATA, 78 )) 79 }.shareIn(coroutineScope + Dispatchers.IO, SharingStarted.WhileSubscribed(), 1) 80 <lambda>null81 val isAvailableFlow = activityInfoFlow.map { it != null } 82 activityInfonull83 val summaryFlow = activityInfoFlow.map { activityInfo -> 84 activityInfo?.metaData?.getSummary() ?: "" 85 }.flowOn(Dispatchers.IO) 86 getSummarynull87 private fun Bundle.getSummary(): String { 88 val resources = try { 89 packageManager.getResourcesForApplication(app) 90 } catch (exception: PackageManager.NameNotFoundException) { 91 Log.d(TAG, "Name not found for the application.") 92 return "" 93 } 94 95 return try { 96 resources.getString(getInt(SUMMARY_METADATA_KEY)) 97 } catch (exception: Resources.NotFoundException) { 98 Log.d(TAG, "Resource not found for summary string.") 99 "" 100 } 101 } 102 startActivitynull103 fun startActivity() { 104 coroutineScope.launch { 105 activityInfoFlow.firstOrNull()?.let { activityInfo -> 106 val intent = Intent(Intent.ACTION_VIEW_APP_FEATURES).apply { 107 component = activityInfo.componentName 108 } 109 context.startActivityAsUser(intent, app.userHandle) 110 } 111 } 112 } 113 114 companion object { 115 private const val TAG = "AppAllServicesPresenter" 116 private const val SUMMARY_METADATA_KEY = "app_features_preference_summary" 117 } 118 } 119