summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSantiago Etchebehere <santie@google.com>2023-03-03 14:33:30 -0800
committerSantiago Etchebehere <santie@google.com>2023-03-03 15:06:55 -0800
commit433e13b452bd151ee06179cd512f0d83447b7940 (patch)
treebc3b4322d1834f3a4ed0d029864a8a2d802dc186
parent5577bacd945abdad388d1e2ee27f7ea90b41b49c (diff)
downloadThemePicker-433e13b452bd151ee06179cd512f0d83447b7940.tar.gz
Handle the case of no grid options available
Fixes: 271343879 Test: manually checked with a fake empty URI and added unit test in GridInteractorTest to test new behavior Change-Id: I95918b5a73711efb137cbcc35cea1a36324f25a6 Change-Id: I25b83eb5e31cbd0d27e1f599fc5aaa6018fdb20a
-rw-r--r--src/com/android/customization/model/grid/GridOptionsManager.java20
-rw-r--r--src/com/android/customization/model/grid/GridSectionController.java2
-rw-r--r--src/com/android/customization/model/grid/LauncherGridOptionsProvider.java1
-rw-r--r--src/com/android/customization/model/grid/data/repository/GridRepository.kt9
-rw-r--r--src/com/android/customization/model/grid/domain/interactor/GridInteractor.kt43
-rw-r--r--tests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt6
-rw-r--r--tests/src/com/android/customization/model/grid/domain/interactor/GridInteractorTest.kt8
7 files changed, 60 insertions, 29 deletions
diff --git a/src/com/android/customization/model/grid/GridOptionsManager.java b/src/com/android/customization/model/grid/GridOptionsManager.java
index bff7933d..b7ee37fd 100644
--- a/src/com/android/customization/model/grid/GridOptionsManager.java
+++ b/src/com/android/customization/model/grid/GridOptionsManager.java
@@ -49,6 +49,7 @@ public class GridOptionsManager implements CustomizationManager<GridOption> {
private final LauncherGridOptionsProvider mProvider;
private final ThemesUserEventLogger mEventLogger;
+ private int mGridOptionSize = -1;
/** Returns the {@link GridOptionsManager} instance. */
public static GridOptionsManager getInstance(Context context) {
@@ -73,16 +74,17 @@ public class GridOptionsManager implements CustomizationManager<GridOption> {
@Override
public boolean isAvailable() {
- int gridOptionSize = 0;
- try {
- gridOptionSize = sExecutorService.submit(() -> {
- List<GridOption> gridOptions = mProvider.fetch(/* reload= */true);
- return gridOptions == null ? 0 : gridOptions.size();
- }).get();
- } catch (InterruptedException | ExecutionException e) {
- Log.w(TAG, "could not get gridOptionSize", e);
+ if (mGridOptionSize < 0) {
+ try {
+ mGridOptionSize = sExecutorService.submit(() -> {
+ List<GridOption> gridOptions = mProvider.fetch(/* reload= */true);
+ return gridOptions == null ? 0 : gridOptions.size();
+ }).get();
+ } catch (InterruptedException | ExecutionException e) {
+ Log.w(TAG, "could not get gridOptionSize", e);
+ }
}
- return gridOptionSize > 1 && mProvider.areGridsAvailable();
+ return mGridOptionSize > 1 && mProvider.areGridsAvailable();
}
@Override
diff --git a/src/com/android/customization/model/grid/GridSectionController.java b/src/com/android/customization/model/grid/GridSectionController.java
index 3e5dba0f..c50bfcc2 100644
--- a/src/com/android/customization/model/grid/GridSectionController.java
+++ b/src/com/android/customization/model/grid/GridSectionController.java
@@ -96,7 +96,7 @@ public class GridSectionController implements CustomizationSectionController<Gri
@Override
public void release() {
- if (mIsRevampedUiEnabled) {
+ if (mIsRevampedUiEnabled && mGridOptionsManager.isAvailable()) {
mGridOptionsManager.getOptionChangeObservable(/* handler= */ null).removeObserver(
mOptionChangeObserver
);
diff --git a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
index 5ae283a7..4e775c62 100644
--- a/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
+++ b/src/com/android/customization/model/grid/LauncherGridOptionsProvider.java
@@ -126,6 +126,7 @@ public class LauncherGridOptionsProvider {
/**
* Returns an observable that receives a new value each time that the grid options are changed.
+ * Do not call if {@link #areGridsAvailable()} returns false
*/
public LiveData<Object> getOptionChangeObservable(
@Nullable Handler handler) {
diff --git a/src/com/android/customization/model/grid/data/repository/GridRepository.kt b/src/com/android/customization/model/grid/data/repository/GridRepository.kt
index 7c84aec7..9a3be0cc 100644
--- a/src/com/android/customization/model/grid/data/repository/GridRepository.kt
+++ b/src/com/android/customization/model/grid/data/repository/GridRepository.kt
@@ -35,7 +35,8 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
interface GridRepository {
- val optionChanges: Flow<Unit>
+ suspend fun isAvailable(): Boolean
+ fun getOptionChanges(): Flow<Unit>
suspend fun getOptions(): GridOptionItemsModel
}
@@ -45,7 +46,11 @@ class GridRepositoryImpl(
private val backgroundDispatcher: CoroutineDispatcher,
) : GridRepository {
- override val optionChanges: Flow<Unit> =
+ override suspend fun isAvailable(): Boolean {
+ return withContext(backgroundDispatcher) { manager.isAvailable }
+ }
+
+ override fun getOptionChanges(): Flow<Unit> =
manager.getOptionChangeObservable(/* handler= */ null).asFlow().map {}
private val selectedOption = MutableStateFlow<GridOption?>(null)
diff --git a/src/com/android/customization/model/grid/domain/interactor/GridInteractor.kt b/src/com/android/customization/model/grid/domain/interactor/GridInteractor.kt
index 5ab9e1fa..cdb679dd 100644
--- a/src/com/android/customization/model/grid/domain/interactor/GridInteractor.kt
+++ b/src/com/android/customization/model/grid/domain/interactor/GridInteractor.kt
@@ -24,6 +24,9 @@ import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
@@ -34,22 +37,30 @@ class GridInteractor(
private val snapshotRestorer: Provider<GridSnapshotRestorer>,
) {
val options: Flow<GridOptionItemsModel> =
- // this upstream flow tells us each time the options are changed.
- repository.optionChanges
- // when we start, we pretend the options _just_ changed. This way, we load something as
- // soon as possible into the flow so it's ready by the time the first observer starts to
- // observe.
- .onStart { emit(Unit) }
- // each time the options changed, we load them.
- .map { reload() }
- // we place the loaded options in a SharedFlow so downstream observers all
- // share the same flow and don't trigger a new one each time they want to start
- // observing.
- .shareIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- replay = 1,
- )
+ flow { emit(repository.isAvailable()) }
+ .flatMapLatest { isAvailable ->
+ if (isAvailable) {
+ // this upstream flow tells us each time the options are changed.
+ repository
+ .getOptionChanges()
+ // when we start, we pretend the options _just_ changed. This way, we load
+ // something as soon as possible into the flow so it's ready by the time the
+ // first observer starts to observe.
+ .onStart { emit(Unit) }
+ // each time the options changed, we load them.
+ .map { reload() }
+ // we place the loaded options in a SharedFlow so downstream observers all
+ // share the same flow and don't trigger a new one each time they want to
+ // start observing.
+ .shareIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ replay = 1,
+ )
+ } else {
+ emptyFlow()
+ }
+ }
suspend fun setSelectedOption(model: GridOptionItemModel) {
model.onSelected.invoke()
diff --git a/tests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt b/tests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
index 6291c219..59539379 100644
--- a/tests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
+++ b/tests/src/com/android/customization/model/grid/data/repository/FakeGridRepository.kt
@@ -32,13 +32,17 @@ import kotlinx.coroutines.flow.stateIn
class FakeGridRepository(
private val scope: CoroutineScope,
initialOptionCount: Int,
+ var available: Boolean = true
) : GridRepository {
private val _optionChanges =
MutableSharedFlow<Unit>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
- override val optionChanges: Flow<Unit> = _optionChanges.asSharedFlow()
+
+ override suspend fun isAvailable(): Boolean = available
+
+ override fun getOptionChanges(): Flow<Unit> = _optionChanges.asSharedFlow()
private val selectedOptionIndex = MutableStateFlow(0)
private var options: GridOptionItemsModel = createOptions(count = initialOptionCount)
diff --git a/tests/src/com/android/customization/model/grid/domain/interactor/GridInteractorTest.kt b/tests/src/com/android/customization/model/grid/domain/interactor/GridInteractorTest.kt
index 20dd300b..f73d5a38 100644
--- a/tests/src/com/android/customization/model/grid/domain/interactor/GridInteractorTest.kt
+++ b/tests/src/com/android/customization/model/grid/domain/interactor/GridInteractorTest.kt
@@ -135,4 +135,12 @@ class GridInteractorTest {
// External updates do not record a new snapshot with the undo system.
assertThat(store.retrieve()).isEqualTo(storedSnapshot)
}
+
+ @Test
+ fun unavailableRepository_emptyOptions() =
+ testScope.runTest {
+ repository.available = false
+ val options = collectLastValue(underTest.options)
+ assertThat(options()).isNull()
+ }
}