diff options
| author | 2024-02-29 15:03:11 -0500 | |
|---|---|---|
| committer | 2024-02-29 15:03:11 -0500 | |
| commit | 8f881cd027e8d970ed9e2040f4dbe218038e8b88 (patch) | |
| tree | 36d6227449e0590b9e2e2eaf9bb2e9f9cd7d0876 /java | |
| parent | c5aac7a24e3aa9b3ff80b6f13702d39df0a2f557 (diff) | |
ProfileHelper: compat helper class for Profile flows in existing Java
This is a temporary measure to bring up the app with an initial
set of user profile data sourced from UserInteractor. This is
effectively a snapshot of current profile state, combined with
a wrapper to access the availability StateFlow via an interface
(hiding a suspend call).
Test: atest IntentResolver-tests-unit:ProfileHelperTest
Bug: 311348033
Flag: ACONFIG com.android.intentresolver.ENABLE_PRIVATE_PROFILE
Change-Id: I6db6ece3bebbed22d0a6b7cf981873f96dd97745
Diffstat (limited to 'java')
| -rw-r--r-- | java/src/com/android/intentresolver/v2/ProfileAvailability.kt | 79 | ||||
| -rw-r--r-- | java/src/com/android/intentresolver/v2/ProfileHelper.kt | 74 |
2 files changed, 153 insertions, 0 deletions
diff --git a/java/src/com/android/intentresolver/v2/ProfileAvailability.kt b/java/src/com/android/intentresolver/v2/ProfileAvailability.kt new file mode 100644 index 00000000..4d689724 --- /dev/null +++ b/java/src/com/android/intentresolver/v2/ProfileAvailability.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.v2 + +import com.android.intentresolver.v2.domain.interactor.UserInteractor +import com.android.intentresolver.v2.shared.model.Profile +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout + +/** Provides availability status for profiles */ +class ProfileAvailability( + private val scope: CoroutineScope, + private val userInteractor: UserInteractor +) { + private val availability = + userInteractor.availability.stateIn(scope, SharingStarted.Eagerly, mapOf()) + + /** Used by WorkProfilePausedEmptyStateProvider */ + var waitingToEnableProfile = false + private set + + private var waitJob: Job? = null + /** Query current profile availability. An unavailable profile is one which is not active. */ + fun isAvailable(profile: Profile) = availability.value[profile] ?: false + + /** Used by WorkProfilePausedEmptyStateProvider */ + fun requestQuietModeState(profile: Profile, quietMode: Boolean) { + val enableProfile = !quietMode + + // Check if the profile is already in the correct state + if (isAvailable(profile) == enableProfile) { + return // No-op + } + + // Support existing code + if (enableProfile) { + waitingToEnableProfile = true + waitJob?.cancel() + + val job = scope.launch { + // Wait for the profile to become available + // Wait for the profile to be enabled, then clear this flag + userInteractor.availability.filter { it[profile] == true }.first() + waitingToEnableProfile = false + } + job.invokeOnCompletion { + waitingToEnableProfile = false + } + waitJob = job + } + + // Apply the change + scope.launch { userInteractor.updateState(profile, enableProfile) } + } +}
\ No newline at end of file diff --git a/java/src/com/android/intentresolver/v2/ProfileHelper.kt b/java/src/com/android/intentresolver/v2/ProfileHelper.kt new file mode 100644 index 00000000..784096b4 --- /dev/null +++ b/java/src/com/android/intentresolver/v2/ProfileHelper.kt @@ -0,0 +1,74 @@ +/* +* Copyright (C) 2024 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.android.intentresolver.v2 + +import android.os.UserHandle +import com.android.intentresolver.inject.IntentResolverFlags +import com.android.intentresolver.v2.domain.interactor.UserInteractor +import com.android.intentresolver.v2.shared.model.Profile +import com.android.intentresolver.v2.shared.model.User +import javax.inject.Inject + +class ProfileHelper @Inject constructor( + interactor: UserInteractor, + private val flags: IntentResolverFlags, + profiles: List<Profile>, + launchedAsProfile: Profile, +) { + private val launchedByHandle: UserHandle = interactor.launchedAs + + // Map UserHandle back to a user within launchedByProfile + private val launchedByUser = when (launchedByHandle) { + launchedAsProfile.primary.handle -> launchedAsProfile.primary + launchedAsProfile.clone?.handle -> launchedAsProfile.clone + else -> error("launchedByUser must be a member of launchedByProfile") + } + val launchedAsProfileType: Profile.Type = launchedAsProfile.type + + val personalProfile = profiles.single { it.type == Profile.Type.PERSONAL } + val workProfile = profiles.singleOrNull { it.type == Profile.Type.WORK } + val privateProfile = profiles.singleOrNull { it.type == Profile.Type.PRIVATE } + + val personalHandle = personalProfile.primary.handle + val workHandle = workProfile?.primary?.handle + val privateHandle = privateProfile?.primary?.handle?.takeIf { flags.enablePrivateProfile() } + val cloneHandle = personalProfile.clone?.handle + + val isLaunchedAsCloneProfile = launchedByUser == launchedAsProfile.clone + + val cloneUserPresent = personalProfile.clone != null + val workProfilePresent = workProfile != null + val privateProfilePresent = privateProfile != null + + // Name retained for ease of review, to be renamed later + val tabOwnerUserHandleForLaunch = if (launchedByUser.role == User.Role.CLONE) { + // When started by clone user, return the profile owner instead + launchedAsProfile.primary.handle + } else { + // Otherwise the launched user is used + launchedByUser.handle + } + + // Name retained for ease of review, to be renamed later + fun getQueryIntentsHandle(handle: UserHandle): UserHandle? { + return if (isLaunchedAsCloneProfile && handle == personalHandle) { + cloneHandle + } else { + handle + } + } +} |