Condition Refactor.
This changelist modifies conditions in two ways: 1. Conditions now can be unset. In the unset state, the condition is no longer considered when evaluating whether all conditions are met by the monitor. 2. The overriding feature of a condition is a construction time decision. Test: atest ConditionMonitorTest Test: atest ConditionTest Bug: 252888175 Change-Id: If254657ef87d12778850a44e1e99fe69d0460476
This commit is contained in:
@@ -34,9 +34,26 @@ public abstract class Condition implements CallbackController<Condition.Callback
|
||||
private final String mTag = getClass().getSimpleName();
|
||||
|
||||
private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
|
||||
private boolean mIsConditionMet = false;
|
||||
private final boolean mOverriding;
|
||||
private Boolean mIsConditionMet;
|
||||
private boolean mStarted = false;
|
||||
private boolean mOverriding = false;
|
||||
|
||||
/**
|
||||
* By default, conditions have an initial value of false and are not overriding.
|
||||
*/
|
||||
public Condition() {
|
||||
this(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for specifying initial state and overriding condition attribute.
|
||||
* @param initialConditionMet Initial state of the condition.
|
||||
* @param overriding Whether this condition overrides others.
|
||||
*/
|
||||
protected Condition(Boolean initialConditionMet, boolean overriding) {
|
||||
mIsConditionMet = initialConditionMet;
|
||||
mOverriding = overriding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts monitoring the condition.
|
||||
@@ -48,14 +65,6 @@ public abstract class Condition implements CallbackController<Condition.Callback
|
||||
*/
|
||||
protected abstract void stop();
|
||||
|
||||
/**
|
||||
* Sets whether this condition's value overrides others in determining the overall state.
|
||||
*/
|
||||
public void setOverriding(boolean overriding) {
|
||||
mOverriding = overriding;
|
||||
updateCondition(mIsConditionMet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the current condition overrides
|
||||
*/
|
||||
@@ -110,13 +119,31 @@ public abstract class Condition implements CallbackController<Condition.Callback
|
||||
* @param isConditionMet True if the condition has been fulfilled. False otherwise.
|
||||
*/
|
||||
protected void updateCondition(boolean isConditionMet) {
|
||||
if (mIsConditionMet == isConditionMet) {
|
||||
if (mIsConditionMet != null && mIsConditionMet == isConditionMet) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet);
|
||||
mIsConditionMet = isConditionMet;
|
||||
sendUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the set condition value. This is purposefully separate from
|
||||
* {@link #updateCondition(boolean)} to avoid confusion around {@code null} values.
|
||||
*/
|
||||
protected void clearCondition() {
|
||||
if (mIsConditionMet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldLog()) Log.d(mTag, "clearing condition");
|
||||
|
||||
mIsConditionMet = null;
|
||||
sendUpdate();
|
||||
}
|
||||
|
||||
private void sendUpdate() {
|
||||
final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Callback cb = iterator.next().get();
|
||||
@@ -128,8 +155,21 @@ public abstract class Condition implements CallbackController<Condition.Callback
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the condition is set. This method should be consulted to understand the
|
||||
* value of {@link #isConditionMet()}.
|
||||
* @return {@code true} if value is present, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isConditionSet() {
|
||||
return mIsConditionMet != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the condition has been met. Note that this method will return {@code false}
|
||||
* if the condition is not set as well.
|
||||
*/
|
||||
public boolean isConditionMet() {
|
||||
return mIsConditionMet;
|
||||
return Boolean.TRUE.equals(mIsConditionMet);
|
||||
}
|
||||
|
||||
private boolean shouldLog() {
|
||||
|
||||
@@ -57,12 +57,16 @@ public class Monitor {
|
||||
}
|
||||
|
||||
public void update() {
|
||||
// Only consider set conditions.
|
||||
final Collection<Condition> setConditions = mSubscription.mConditions.stream()
|
||||
.filter(Condition::isConditionSet).collect(Collectors.toSet());
|
||||
|
||||
// Overriding conditions do not override each other
|
||||
final Collection<Condition> overridingConditions = mSubscription.mConditions.stream()
|
||||
final Collection<Condition> overridingConditions = setConditions.stream()
|
||||
.filter(Condition::isOverridingCondition).collect(Collectors.toSet());
|
||||
|
||||
final Collection<Condition> targetCollection = overridingConditions.isEmpty()
|
||||
? mSubscription.mConditions : overridingConditions;
|
||||
? setConditions : overridingConditions;
|
||||
|
||||
final boolean newAllConditionsMet = targetCollection.isEmpty() ? true : targetCollection
|
||||
.stream()
|
||||
|
||||
@@ -73,10 +73,16 @@ public class ConditionMonitorTest extends SysuiTestCase {
|
||||
.addConditions(mConditions);
|
||||
}
|
||||
|
||||
private Condition createMockCondition() {
|
||||
final Condition condition = Mockito.mock(Condition.class);
|
||||
when(condition.isConditionSet()).thenReturn(true);
|
||||
return condition;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverridingCondition() {
|
||||
final Condition overridingCondition = Mockito.mock(Condition.class);
|
||||
final Condition regularCondition = Mockito.mock(Condition.class);
|
||||
final Condition overridingCondition = createMockCondition();
|
||||
final Condition regularCondition = createMockCondition();
|
||||
final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
|
||||
|
||||
final Monitor.Callback referenceCallback = Mockito.mock(Monitor.Callback.class);
|
||||
@@ -127,9 +133,9 @@ public class ConditionMonitorTest extends SysuiTestCase {
|
||||
*/
|
||||
@Test
|
||||
public void testMultipleOverridingConditions() {
|
||||
final Condition overridingCondition = Mockito.mock(Condition.class);
|
||||
final Condition overridingCondition2 = Mockito.mock(Condition.class);
|
||||
final Condition regularCondition = Mockito.mock(Condition.class);
|
||||
final Condition overridingCondition = createMockCondition();
|
||||
final Condition overridingCondition2 = createMockCondition();
|
||||
final Condition regularCondition = createMockCondition();
|
||||
final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
|
||||
|
||||
final Monitor monitor = new Monitor(mExecutor);
|
||||
@@ -340,4 +346,114 @@ public class ConditionMonitorTest extends SysuiTestCase {
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearCondition_shouldUpdateValue() {
|
||||
mCondition1.fakeUpdateCondition(false);
|
||||
mCondition2.fakeUpdateCondition(true);
|
||||
mCondition3.fakeUpdateCondition(true);
|
||||
|
||||
final Monitor.Callback callback =
|
||||
mock(Monitor.Callback.class);
|
||||
mConditionMonitor.addSubscription(getDefaultBuilder(callback).build());
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(false);
|
||||
|
||||
mCondition1.clearCondition();
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsetCondition_shouldNotAffectValue() {
|
||||
final FakeCondition settableCondition = new FakeCondition(null, false);
|
||||
mCondition1.fakeUpdateCondition(true);
|
||||
mCondition2.fakeUpdateCondition(true);
|
||||
mCondition3.fakeUpdateCondition(true);
|
||||
|
||||
final Monitor.Callback callback =
|
||||
mock(Monitor.Callback.class);
|
||||
|
||||
mConditionMonitor.addSubscription(getDefaultBuilder(callback)
|
||||
.addCondition(settableCondition)
|
||||
.build());
|
||||
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setUnsetCondition_shouldAffectValue() {
|
||||
final FakeCondition settableCondition = new FakeCondition(null, false);
|
||||
mCondition1.fakeUpdateCondition(true);
|
||||
mCondition2.fakeUpdateCondition(true);
|
||||
mCondition3.fakeUpdateCondition(true);
|
||||
|
||||
final Monitor.Callback callback =
|
||||
mock(Monitor.Callback.class);
|
||||
|
||||
mConditionMonitor.addSubscription(getDefaultBuilder(callback)
|
||||
.addCondition(settableCondition)
|
||||
.build());
|
||||
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
clearInvocations(callback);
|
||||
|
||||
settableCondition.fakeUpdateCondition(false);
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(false);
|
||||
clearInvocations(callback);
|
||||
|
||||
|
||||
settableCondition.clearCondition();
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearingOverridingCondition_shouldBeExcluded() {
|
||||
final FakeCondition overridingCondition = new FakeCondition(true, true);
|
||||
mCondition1.fakeUpdateCondition(false);
|
||||
mCondition2.fakeUpdateCondition(false);
|
||||
mCondition3.fakeUpdateCondition(false);
|
||||
|
||||
final Monitor.Callback callback =
|
||||
mock(Monitor.Callback.class);
|
||||
|
||||
mConditionMonitor.addSubscription(getDefaultBuilder(callback)
|
||||
.addCondition(overridingCondition)
|
||||
.build());
|
||||
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
clearInvocations(callback);
|
||||
|
||||
overridingCondition.clearCondition();
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void settingUnsetOverridingCondition_shouldBeIncluded() {
|
||||
final FakeCondition overridingCondition = new FakeCondition(null, true);
|
||||
mCondition1.fakeUpdateCondition(false);
|
||||
mCondition2.fakeUpdateCondition(false);
|
||||
mCondition3.fakeUpdateCondition(false);
|
||||
|
||||
final Monitor.Callback callback =
|
||||
mock(Monitor.Callback.class);
|
||||
|
||||
mConditionMonitor.addSubscription(getDefaultBuilder(callback)
|
||||
.addCondition(overridingCondition)
|
||||
.build());
|
||||
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(false);
|
||||
clearInvocations(callback);
|
||||
|
||||
overridingCondition.fakeUpdateCondition(true);
|
||||
mExecutor.runAllReady();
|
||||
verify(callback).onConditionsChanged(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,4 +133,12 @@ public class ConditionTest extends SysuiTestCase {
|
||||
mCondition.fakeUpdateCondition(false);
|
||||
verify(callback, never()).onConditionChanged(eq(mCondition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearCondition_reportsNotSet() {
|
||||
mCondition.fakeUpdateCondition(false);
|
||||
assertThat(mCondition.isConditionSet()).isTrue();
|
||||
mCondition.clearCondition();
|
||||
assertThat(mCondition.isConditionSet()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,14 @@ package com.android.systemui.util.condition;
|
||||
* condition fulfillment.
|
||||
*/
|
||||
public class FakeCondition extends Condition {
|
||||
FakeCondition() {
|
||||
super();
|
||||
}
|
||||
|
||||
FakeCondition(Boolean initialValue, Boolean overriding) {
|
||||
super(initialValue, overriding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user