Prune unavailable complications.

This changelist checks the availability of a complication based on its required available complication types and trims ineligible complications from participating at the LiveData level. By default, the DreamOverlayStateController now only returns available complications.

Bug: 214039870
Test: atest DreamOverlayStateControllerTest ComplicationCollectionLiveDataTest

Change-Id: If1fa63b46e409dce944b6e0ae54d80c2c44f7024
This commit is contained in:
Bryce Lee
2022-01-28 14:35:02 -08:00
committed by brycelee
parent 32c231ec19
commit 1e8b9618ef
5 changed files with 106 additions and 1 deletions

View File

@@ -33,6 +33,7 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -69,11 +70,20 @@ public class DreamOverlayStateController implements
*/
default void onStateChanged() {
}
/**
* Called when the available complication types changes.
*/
default void onAvailableComplicationTypesChanged() {
}
}
private final Executor mExecutor;
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
@Complication.ComplicationType
private int mAvailableComplicationTypes = Complication.COMPLICATION_TYPE_NONE;
private final Collection<Complication> mComplications = new HashSet();
@VisibleForTesting
@@ -108,7 +118,25 @@ public class DreamOverlayStateController implements
* Returns collection of present {@link Complication}.
*/
public Collection<Complication> getComplications() {
return Collections.unmodifiableCollection(mComplications);
return getComplications(true);
}
/**
* Returns collection of present {@link Complication}.
*/
public Collection<Complication> getComplications(boolean filterByAvailability) {
return Collections.unmodifiableCollection(filterByAvailability
? mComplications
.stream()
.filter(complication -> {
@Complication.ComplicationType
final int requiredTypes = complication.getRequiredTypeAvailability();
return requiredTypes == Complication.COMPLICATION_TYPE_NONE
|| (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
})
.collect(Collectors.toCollection(HashSet::new))
: mComplications);
}
private void notifyCallbacks(Consumer<Callback> callbackConsumer) {
@@ -180,4 +208,22 @@ public class DreamOverlayStateController implements
public void setOverlayActive(boolean active) {
modifyState(active ? OP_SET_STATE : OP_CLEAR_STATE, STATE_DREAM_OVERLAY_ACTIVE);
}
/**
* Returns the available complication types.
*/
@Complication.ComplicationType
public int getAvailableComplicationTypes() {
return mAvailableComplicationTypes;
}
/**
* Sets the available complication types for the dream overlay.
*/
public void setAvailableComplicationTypes(@Complication.ComplicationType int types) {
mExecutor.execute(() -> {
mAvailableComplicationTypes = types;
mCallbacks.forEach(callback -> callback.onAvailableComplicationTypesChanged());
});
}
}

View File

@@ -228,4 +228,15 @@ public interface Complication {
* @return a {@link ViewHolder} for this {@link Complication} instance.
*/
ViewHolder createView(ComplicationViewModel model);
/**
* Returns the types that must be present in order for this complication to participate on
* the dream overlay. By default, this method returns
* {@code Complication.COMPLICATION_TYPE_NONE} to indicate no types are required.
* @return
*/
@Complication.ComplicationType
default int getRequiredTypeAvailability() {
return Complication.COMPLICATION_TYPE_NONE;
}
}

View File

@@ -42,6 +42,10 @@ public class ComplicationCollectionLiveData extends LiveData<Collection<Complica
setValue(mDreamOverlayStateController.getComplications());
}
@Override
public void onAvailableComplicationTypesChanged() {
setValue(mDreamOverlayStateController.getComplications());
}
};
}

View File

@@ -24,6 +24,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -120,4 +121,43 @@ public class DreamOverlayStateControllerTest extends SysuiTestCase {
mExecutor.runAllReady();
verify(mCallback, times(1)).onComplicationsChanged();
}
@Test
public void testComplicationFiltering() {
final DreamOverlayStateController stateController =
new DreamOverlayStateController(mExecutor);
final Complication alwaysAvailableComplication = Mockito.mock(Complication.class);
final Complication weatherComplication = Mockito.mock(Complication.class);
when(alwaysAvailableComplication.getRequiredTypeAvailability())
.thenReturn(Complication.COMPLICATION_TYPE_NONE);
when(weatherComplication.getRequiredTypeAvailability())
.thenReturn(Complication.COMPLICATION_TYPE_WEATHER);
stateController.addComplication(alwaysAvailableComplication);
stateController.addComplication(weatherComplication);
final DreamOverlayStateController.Callback callback =
Mockito.mock(DreamOverlayStateController.Callback.class);
stateController.addCallback(callback);
mExecutor.runAllReady();
{
final Collection<Complication> complications = stateController.getComplications();
assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
assertThat(complications.contains(weatherComplication)).isFalse();
}
stateController.setAvailableComplicationTypes(Complication.COMPLICATION_TYPE_WEATHER);
mExecutor.runAllReady();
verify(callback).onAvailableComplicationTypesChanged();
{
final Collection<Complication> complications = stateController.getComplications();
assertThat(complications.contains(alwaysAvailableComplication)).isTrue();
assertThat(complications.contains(weatherComplication)).isTrue();
}
}
}

View File

@@ -75,6 +75,10 @@ public class ComplicationCollectionLiveDataTest extends SysuiTestCase {
callbackCaptor.getValue().onComplicationsChanged();
verifyUpdate(observer, complications);
callbackCaptor.getValue().onAvailableComplicationTypesChanged();
verifyUpdate(observer, complications);
});
}