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.role.RoleManager 20 import android.content.Context 21 import android.content.Intent 22 import android.content.pm.ApplicationInfo 23 import androidx.annotation.StringRes 24 import androidx.compose.runtime.Composable 25 import androidx.compose.runtime.getValue 26 import androidx.compose.runtime.livedata.observeAsState 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 androidx.lifecycle.liveData 32 import com.android.settings.R 33 import com.android.settingslib.spa.widget.preference.Preference 34 import com.android.settingslib.spa.widget.preference.PreferenceModel 35 import com.android.settingslib.spaprivileged.framework.common.userManager 36 import com.android.settingslib.spaprivileged.model.app.userHandle 37 import com.android.settingslib.spaprivileged.model.app.userId 38 import kotlin.coroutines.resume 39 import kotlin.coroutines.suspendCoroutine 40 import kotlinx.coroutines.Dispatchers 41 import kotlinx.coroutines.asExecutor 42 import kotlinx.coroutines.async 43 import kotlinx.coroutines.coroutineScope 44 import kotlinx.coroutines.flow.flow 45 import kotlinx.coroutines.flow.flowOn 46 47 data class DefaultAppShortcut( 48 val roleName: String, 49 @StringRes val titleResId: Int, 50 ) 51 52 @Composable 53 fun DefaultAppShortcutPreference(shortcut: DefaultAppShortcut, app: ApplicationInfo) { 54 val context = LocalContext.current 55 val presenter = remember(shortcut.roleName, app) { 56 DefaultAppShortcutPresenter(context, shortcut.roleName, app) 57 } 58 if (remember(presenter) { !presenter.isAvailable() }) return 59 if (presenter.isVisible().observeAsState().value != true) return 60 61 val summary by presenter.summaryFlow.collectAsStateWithLifecycle( 62 initialValue = stringResource(R.string.summary_placeholder), 63 ) 64 Preference(object : PreferenceModel { 65 override val title = stringResource(shortcut.titleResId) 66 override val summary = { summary } 67 override val onClick = presenter::startActivity 68 }) 69 } 70 71 private class DefaultAppShortcutPresenter( 72 private val context: Context, 73 private val roleName: String, 74 private val app: ApplicationInfo, 75 ) { 76 private val roleManager = context.getSystemService(RoleManager::class.java)!! 77 private val executor = Dispatchers.IO.asExecutor() 78 isAvailablenull79 fun isAvailable() = !context.userManager.isManagedProfile(app.userId) 80 81 fun isVisible() = liveData { 82 coroutineScope { 83 val roleVisible = async { isRoleVisible() } 84 val applicationVisibleForRole = async { isApplicationVisibleForRole() } 85 emit(roleVisible.await() && applicationVisibleForRole.await()) 86 } 87 } 88 isRoleVisiblenull89 private suspend fun isRoleVisible(): Boolean { 90 return suspendCoroutine { continuation -> 91 roleManager.isRoleVisible(roleName, executor) { 92 continuation.resume(it) 93 } 94 } 95 } 96 isApplicationVisibleForRolenull97 private suspend fun isApplicationVisibleForRole() = suspendCoroutine { continuation -> 98 roleManager.isApplicationVisibleForRole(roleName, app.packageName, executor) { 99 continuation.resume(it) 100 } 101 } 102 <lambda>null103 val summaryFlow = flow { emit(getSummary()) }.flowOn(Dispatchers.IO) 104 getSummarynull105 private fun getSummary(): String { 106 val defaultApp = roleManager.getRoleHoldersAsUser(roleName, app.userHandle).firstOrNull() 107 return context.getString( 108 if (defaultApp == app.packageName) R.string.yes else R.string.no 109 ) 110 } 111 startActivitynull112 fun startActivity() { 113 val intent = Intent(Intent.ACTION_MANAGE_DEFAULT_APP).apply { 114 putExtra(Intent.EXTRA_ROLE_NAME, roleName) 115 } 116 context.startActivityAsUser(intent, app.userHandle) 117 } 118 } 119