blob: fed5395394bb87d7a57b549873dc2160173be31d [file] [log] [blame]
/*
* 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
import androidx.annotation.MainThread
import com.android.app.tracing.coroutines.runBlockingTraced as runBlocking
import com.android.intentresolver.annotation.JavaInterop
import com.android.intentresolver.domain.interactor.UserInteractor
import com.android.intentresolver.shared.model.Profile
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
/** Provides availability status for profiles */
@JavaInterop
class ProfileAvailability(
private val userInteractor: UserInteractor,
private val scope: CoroutineScope,
private val background: CoroutineDispatcher,
) {
/** Used by WorkProfilePausedEmptyStateProvider */
var waitingToEnableProfile = false
private set
/** Set by ChooserActivity to call onWorkProfileStatusUpdated */
var onProfileStatusChange: Runnable? = null
private var waitJob: Job? = null
/** Query current profile availability. An unavailable profile is one which is not active. */
@MainThread
fun isAvailable(profile: Profile?): Boolean {
return runBlocking(context = background) {
userInteractor.availability.map { it[profile] == true }.first()
}
}
/**
* The number of profiles which are visible. All profiles count except for private which is
* hidden when locked.
*/
fun visibleProfileCount() =
runBlocking(context = background) {
val availability = userInteractor.availability.first()
val profiles = userInteractor.profiles.first()
profiles
.filter {
when (it.type) {
Profile.Type.PRIVATE -> availability[it] == true
else -> true
}
}
.size
}
/** 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
userInteractor.availability.filter { it[profile] == true }.first()
}
job.invokeOnCompletion {
waitingToEnableProfile = false
onProfileStatusChange?.run()
}
waitJob = job
}
// Apply the change
scope.launch { userInteractor.updateState(profile, enableProfile) }
}
}