diff options
Diffstat (limited to 'java/src')
4 files changed, 43 insertions, 58 deletions
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java index d624c9e4..5f3129f8 100644 --- a/java/src/com/android/intentresolver/v2/ChooserActivity.java +++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java @@ -124,6 +124,7 @@ import com.android.intentresolver.emptystate.EmptyState; import com.android.intentresolver.emptystate.EmptyStateProvider; import com.android.intentresolver.grid.ChooserGridAdapter; import com.android.intentresolver.icons.TargetDataLoader; +import com.android.intentresolver.inject.Background; import com.android.intentresolver.logging.EventLog; import com.android.intentresolver.measurements.Tracer; import com.android.intentresolver.model.AbstractResolverComparator; @@ -185,6 +186,8 @@ import java.util.function.Supplier; import javax.inject.Inject; +import kotlinx.coroutines.CoroutineDispatcher; + /** * The Chooser Activity handles intent resolution specifically for sharing intents - * for example, as generated by {@see android.content.Intent#createChooser(Intent, CharSequence)}. @@ -265,6 +268,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements private static final int SCROLL_STATUS_SCROLLING_HORIZONTAL = 2; @Inject public UserInteractor mUserInteractor; + @Inject @Background public CoroutineDispatcher mBackgroundDispatcher; @Inject public ChooserHelper mChooserHelper; @Inject public FeatureFlags mFeatureFlags; @Inject public android.service.chooser.FeatureFlags mChooserServiceFeatureFlags; @@ -352,7 +356,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements setTheme(R.style.Theme_DeviceDefault_Chooser); // Initializer is invoked when this function returns, via Lifecycle. - mChooserHelper.setInitializer(this::initializeWith); + mChooserHelper.setInitializer(this::initialize); if (mChooserServiceFeatureFlags.chooserPayloadToggling()) { mChooserHelper.setOnChooserRequestChanged(this::onChooserRequestChanged); } @@ -467,8 +471,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements } /** DO NOT CALL. Only for use from ChooserHelper as a callback. */ - private void initializeWith(InitialState initialState) { - Log.d(TAG, "initializeWith: " + initialState); + private void initialize() { mViewModel = new ViewModelProvider(this).get(ChooserViewModel.class); mRequest = mViewModel.getRequest().getValue(); @@ -476,14 +479,14 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mProfiles = new ProfileHelper( mUserInteractor, - mFeatureFlags, - initialState.getProfiles(), - initialState.getLaunchedAs()); + getCoroutineScope(getLifecycle()), + mBackgroundDispatcher, + mFeatureFlags); mProfileAvailability = new ProfileAvailability( - getCoroutineScope(getLifecycle()), mUserInteractor, - initialState.getAvailability()); + getCoroutineScope(getLifecycle()), + mBackgroundDispatcher); mProfileAvailability.setOnProfileStatusChange(this::onWorkProfileStatusUpdated); diff --git a/java/src/com/android/intentresolver/v2/ChooserHelper.kt b/java/src/com/android/intentresolver/v2/ChooserHelper.kt index 503e46d8..9da0d605 100644 --- a/java/src/com/android/intentresolver/v2/ChooserHelper.kt +++ b/java/src/com/android/intentresolver/v2/ChooserHelper.kt @@ -31,7 +31,6 @@ import com.android.intentresolver.inject.Background import com.android.intentresolver.v2.annotation.JavaInterop import com.android.intentresolver.v2.data.model.ChooserRequest import com.android.intentresolver.v2.domain.interactor.UserInteractor -import com.android.intentresolver.v2.shared.model.Profile import com.android.intentresolver.v2.ui.viewmodel.ChooserViewModel import com.android.intentresolver.v2.validation.Invalid import com.android.intentresolver.v2.validation.Valid @@ -43,35 +42,10 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking private const val TAG: String = "ChooserHelper" /** - * Provides initial values to ChooserActivity and completes initialization from onCreate. - * - * This information is collected and provided on behalf of ChooserActivity to eliminate the need for - * suspending functions within remaining synchronous startup code. - */ -@JavaInterop -fun interface ChooserInitializer { - /** @param initialState the initial state to provide to initialization */ - fun initializeWith(initialState: InitialState) -} - -/** - * A parameter object for Initialize which contains all the values which are required "early", on - * the main thread and outside of any coroutines. This supports code which expects to be called by - * the system on the main thread only. (This includes everything originally called from onCreate). - */ -@JavaInterop -data class InitialState( - val profiles: List<Profile>, - val availability: Map<Profile, Boolean>, - val launchedAs: Profile -) - -/** * __Purpose__ * * Cleanup aid. Provides a pathway to cleaner code. @@ -113,7 +87,7 @@ constructor( private val activity: ComponentActivity = hostActivity as ComponentActivity private val viewModel by activity.viewModels<ChooserViewModel>() - private lateinit var activityInitializer: ChooserInitializer + private lateinit var activityInitializer: Runnable var onChooserRequestChanged: Consumer<ChooserRequest> = Consumer {} @@ -126,7 +100,7 @@ constructor( * * This _must_ be called from [ChooserActivity.onCreate]. */ - fun setInitializer(initializer: ChooserInitializer) { + fun setInitializer(initializer: Runnable) { check(activity.lifecycle.currentState == Lifecycle.State.INITIALIZED) { "setInitializer must be called before onCreate returns" } @@ -189,14 +163,6 @@ constructor( private fun initializeActivity(request: Valid<ChooserRequest>) { request.warnings.forEach { it.log(TAG) } - - val initialState = - runBlocking(background) { - val initialProfiles = userInteractor.profiles.first() - val initialAvailability = userInteractor.availability.first() - val launchedAsProfile = userInteractor.launchedAsProfile.first() - InitialState(initialProfiles, initialAvailability, launchedAsProfile) - } - activityInitializer.initializeWith(initialState) + activityInitializer.run() } } diff --git a/java/src/com/android/intentresolver/v2/ProfileAvailability.kt b/java/src/com/android/intentresolver/v2/ProfileAvailability.kt index ddb57991..27d8c6bb 100644 --- a/java/src/com/android/intentresolver/v2/ProfileAvailability.kt +++ b/java/src/com/android/intentresolver/v2/ProfileAvailability.kt @@ -16,27 +16,26 @@ package com.android.intentresolver.v2 +import androidx.annotation.MainThread import com.android.intentresolver.v2.annotation.JavaInterop import com.android.intentresolver.v2.domain.interactor.UserInteractor import com.android.intentresolver.v2.shared.model.Profile +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking /** Provides availability status for profiles */ @JavaInterop class ProfileAvailability( - private val scope: CoroutineScope, private val userInteractor: UserInteractor, - initialState: Map<Profile, Boolean> + private val scope: CoroutineScope, + private val background: CoroutineDispatcher, ) { - private val availability = - userInteractor.availability.stateIn(scope, SharingStarted.Eagerly, initialState) - /** Used by WorkProfilePausedEmptyStateProvider */ var waitingToEnableProfile = false private set @@ -45,8 +44,14 @@ class ProfileAvailability( var onProfileStatusChange: Runnable? = null 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 + @MainThread + fun isAvailable(profile: Profile): Boolean { + return runBlocking(background) { + userInteractor.availability.map { it[profile] == true }.first() + } + } /** Used by WorkProfilePausedEmptyStateProvider */ fun requestQuietModeState(profile: Profile, quietMode: Boolean) { @@ -65,7 +70,7 @@ class ProfileAvailability( val job = scope.launch { // Wait for the profile to become available - availability.filter { it[profile] == true }.first() + userInteractor.availability.filter { it[profile] == true }.first() } job.invokeOnCompletion { waitingToEnableProfile = false diff --git a/java/src/com/android/intentresolver/v2/ProfileHelper.kt b/java/src/com/android/intentresolver/v2/ProfileHelper.kt index 8a8e6b54..87948150 100644 --- a/java/src/com/android/intentresolver/v2/ProfileHelper.kt +++ b/java/src/com/android/intentresolver/v2/ProfileHelper.kt @@ -17,29 +17,40 @@ package com.android.intentresolver.v2 import android.os.UserHandle +import androidx.annotation.MainThread import com.android.intentresolver.inject.IntentResolverFlags import com.android.intentresolver.v2.annotation.JavaInterop 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 +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking @JavaInterop +@MainThread class ProfileHelper @Inject constructor( interactor: UserInteractor, + private val scope: CoroutineScope, + private val background: CoroutineDispatcher, private val flags: IntentResolverFlags, - val profiles: List<Profile>, - val launchedAsProfile: Profile, ) { private val launchedByHandle: UserHandle = interactor.launchedAs + val launchedAsProfile by lazy { + runBlocking(background) { interactor.launchedAsProfile.first() } + } + val profiles by lazy { runBlocking(background) { interactor.profiles.first() } } + // Map UserHandle back to a user within launchedByProfile - private val launchedByUser = + private val launchedByUser: User = when (launchedByHandle) { launchedAsProfile.primary.handle -> launchedAsProfile.primary - launchedAsProfile.clone?.handle -> launchedAsProfile.clone + launchedAsProfile.clone?.handle -> requireNotNull(launchedAsProfile.clone) else -> error("launchedByUser must be a member of launchedByProfile") } val launchedAsProfileType: Profile.Type = launchedAsProfile.type |