1 /* 2 * Copyright (C) 2024 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.intentresolver 18 19 import android.os.UserHandle 20 import androidx.annotation.MainThread 21 import com.android.intentresolver.annotation.JavaInterop 22 import com.android.intentresolver.domain.interactor.UserInteractor 23 import com.android.intentresolver.inject.IntentResolverFlags 24 import com.android.intentresolver.shared.model.Profile 25 import com.android.intentresolver.shared.model.User 26 import javax.inject.Inject 27 import kotlinx.coroutines.CoroutineDispatcher 28 import kotlinx.coroutines.CoroutineScope 29 import kotlinx.coroutines.flow.first 30 import kotlinx.coroutines.runBlocking 31 32 @JavaInterop 33 @MainThread 34 class ProfileHelper 35 @Inject 36 constructor( 37 interactor: UserInteractor, 38 private val scope: CoroutineScope, 39 private val background: CoroutineDispatcher, 40 private val flags: IntentResolverFlags, 41 ) { 42 private val launchedByHandle: UserHandle = interactor.launchedAs 43 <lambda>null44 val launchedAsProfile by lazy { 45 runBlocking(background) { interactor.launchedAsProfile.first() } 46 } <lambda>null47 val profiles by lazy { runBlocking(background) { interactor.profiles.first() } } 48 49 // Map UserHandle back to a user within launchedByProfile 50 private val launchedByUser: User = 51 when (launchedByHandle) { 52 launchedAsProfile.primary.handle -> launchedAsProfile.primary 53 launchedAsProfile.clone?.handle -> requireNotNull(launchedAsProfile.clone) 54 else -> error("launchedByUser must be a member of launchedByProfile") 55 } 56 val launchedAsProfileType: Profile.Type = launchedAsProfile.type 57 <lambda>null58 val personalProfile = profiles.single { it.type == Profile.Type.PERSONAL } <lambda>null59 val workProfile = profiles.singleOrNull { it.type == Profile.Type.WORK } <lambda>null60 val privateProfile = profiles.singleOrNull { it.type == Profile.Type.PRIVATE } 61 62 val personalHandle = personalProfile.primary.handle 63 val workHandle = workProfile?.primary?.handle 64 val privateHandle = privateProfile?.primary?.handle 65 val cloneHandle = personalProfile.clone?.handle 66 67 val isLaunchedAsCloneProfile = launchedByUser == launchedAsProfile.clone 68 69 val cloneUserPresent = personalProfile.clone != null 70 val workProfilePresent = workProfile != null 71 val privateProfilePresent = privateProfile != null 72 73 // Name retained for ease of review, to be renamed later 74 val tabOwnerUserHandleForLaunch = 75 if (launchedByUser.role == User.Role.CLONE) { 76 // When started by clone user, return the profile owner instead 77 launchedAsProfile.primary.handle 78 } else { 79 // Otherwise the launched user is used 80 launchedByUser.handle 81 } 82 findProfilenull83 fun findProfile(handle: UserHandle): Profile? { 84 return profiles.firstOrNull { it.primary.handle == handle || it.clone?.handle == handle } 85 } 86 findProfileTypenull87 fun findProfileType(handle: UserHandle): Profile.Type? = findProfile(handle)?.type 88 89 // Name retained for ease of review, to be renamed later 90 fun getQueryIntentsHandle(handle: UserHandle): UserHandle? { 91 return if (isLaunchedAsCloneProfile && handle == personalHandle) { 92 cloneHandle 93 } else { 94 handle 95 } 96 } 97 } 98