From c960b0b22bb2e14f8180784ce9dd543fba9d3538 Mon Sep 17 00:00:00 2001 From: Darrell Shi Date: Fri, 19 Nov 2021 18:46:39 +0000 Subject: [PATCH] Introduction to communal conditions monitor. Communal conditions monitor takes a set of conditions, monitors whether all have been fulfilled, and informs its registered listeners. Test: atest CommunalConditionTest CommunalConditionsMonitorTest Bug: 202778351 Change-Id: I5b09ec1d678864141788a84eefe5d6de80bfcb77 --- .../conditions/CommunalCondition.java | 130 +++++++++++++ .../conditions/CommunalConditionsMonitor.java | 154 +++++++++++++++ .../communal/dagger/CommunalModule.java | 16 ++ .../communal/CommunalConditionTest.java | 133 +++++++++++++ .../CommunalConditionsMonitorTest.java | 178 ++++++++++++++++++ .../communal/FakeCommunalCondition.java | 35 ++++ 6 files changed, 646 insertions(+) create mode 100644 packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalCondition.java create mode 100644 packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalConditionsMonitor.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionsMonitorTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/communal/FakeCommunalCondition.java diff --git a/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalCondition.java b/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalCondition.java new file mode 100644 index 0000000000000..734ab6323ca05 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalCondition.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 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.systemui.communal.conditions; + +import android.util.Log; + +import com.android.systemui.statusbar.policy.CallbackController; + +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Base class for a condition that needs to be fulfilled in order for Communal Mode to display. + */ +public abstract class CommunalCondition implements CallbackController { + private final String mTag = getClass().getSimpleName(); + + private final ArrayList> mCallbacks = new ArrayList<>(); + private boolean mIsConditionMet = false; + private boolean mStarted = false; + + /** + * Starts monitoring the condition. + */ + protected abstract void start(); + + /** + * Stops monitoring the condition. + */ + protected abstract void stop(); + + /** + * Registers a callback to receive updates once started. This should be called before + * {@link #start()}. Also triggers the callback immediately if already started. + */ + @Override + public void addCallback(@NotNull Callback callback) { + if (shouldLog()) Log.d(mTag, "adding callback"); + mCallbacks.add(new WeakReference<>(callback)); + + if (mStarted) { + callback.onConditionChanged(this, mIsConditionMet); + return; + } + + start(); + mStarted = true; + } + + /** + * Removes the provided callback from further receiving updates. + */ + @Override + public void removeCallback(@NotNull Callback callback) { + if (shouldLog()) Log.d(mTag, "removing callback"); + final Iterator> iterator = mCallbacks.iterator(); + while (iterator.hasNext()) { + final Callback cb = iterator.next().get(); + if (cb == null || cb == callback) { + iterator.remove(); + } + } + + if (!mCallbacks.isEmpty() || !mStarted) { + return; + } + + stop(); + mStarted = false; + } + + /** + * Updates the value for whether the condition has been fulfilled, and sends an update if the + * value changes and any callback is registered. + * + * @param isConditionMet True if the condition has been fulfilled. False otherwise. + */ + protected void updateCondition(boolean isConditionMet) { + if (mIsConditionMet == isConditionMet) { + return; + } + + if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet); + mIsConditionMet = isConditionMet; + + final Iterator> iterator = mCallbacks.iterator(); + while (iterator.hasNext()) { + final Callback cb = iterator.next().get(); + if (cb == null) { + iterator.remove(); + } else { + cb.onConditionChanged(this, mIsConditionMet); + } + } + } + + private boolean shouldLog() { + return Log.isLoggable(mTag, Log.DEBUG); + } + + /** + * Callback that receives updates about whether the condition has been fulfilled. + */ + public interface Callback { + /** + * Called when the fulfillment of the condition changes. + * + * @param condition The condition in question. + * @param isConditionMet True if the condition has been fulfilled. False otherwise. + */ + void onConditionChanged(CommunalCondition condition, boolean isConditionMet); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalConditionsMonitor.java b/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalConditionsMonitor.java new file mode 100644 index 0000000000000..4f772da487687 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/communal/conditions/CommunalConditionsMonitor.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2021 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.systemui.communal.conditions; + +import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS; + +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.statusbar.policy.CallbackController; + +import org.jetbrains.annotations.NotNull; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * {@link CommunalConditionsMonitor} takes in a set of conditions, monitors whether all of them have + * been fulfilled, and informs any registered listeners. + */ +@SysUISingleton +public class CommunalConditionsMonitor implements + CallbackController { + private final String mTag = getClass().getSimpleName(); + + private final ArrayList> mCallbacks = new ArrayList<>(); + + // Set of all conditions that need to be monitored. + private final Set mConditions; + + // Map of values of each condition. + private final HashMap mConditionsMap = new HashMap<>(); + + // Whether all conditions have been met. + private boolean mAllConditionsMet = false; + + // Whether the monitor has started listening for all the conditions. + private boolean mHaveConditionsStarted = false; + + // Callback for when each condition has been updated. + private final CommunalCondition.Callback mConditionCallback = (condition, isConditionMet) -> { + mConditionsMap.put(condition, isConditionMet); + + final boolean newAllConditionsMet = !mConditionsMap.containsValue(false); + + if (newAllConditionsMet == mAllConditionsMet) { + return; + } + + if (shouldLog()) Log.d(mTag, "all conditions met: " + newAllConditionsMet); + mAllConditionsMet = newAllConditionsMet; + + // Updates all callbacks. + final Iterator> iterator = mCallbacks.iterator(); + while (iterator.hasNext()) { + final Callback callback = iterator.next().get(); + if (callback == null) { + iterator.remove(); + } else { + callback.onConditionsChanged(mAllConditionsMet); + } + } + }; + + @Inject + public CommunalConditionsMonitor( + @Named(COMMUNAL_CONDITIONS) Set communalConditions) { + mConditions = communalConditions; + + // Initializes the conditions map and registers a callback for each condition. + mConditions.forEach((condition -> mConditionsMap.put(condition, false))); + } + + @Override + public void addCallback(@NotNull Callback callback) { + if (shouldLog()) Log.d(mTag, "adding callback"); + mCallbacks.add(new WeakReference<>(callback)); + + // Updates the callback immediately. + callback.onConditionsChanged(mAllConditionsMet); + + if (!mHaveConditionsStarted) { + if (shouldLog()) Log.d(mTag, "starting all conditions"); + mConditions.forEach(condition -> condition.addCallback(mConditionCallback)); + mHaveConditionsStarted = true; + } + } + + @Override + public void removeCallback(@NotNull Callback callback) { + if (shouldLog()) Log.d(mTag, "removing callback"); + final Iterator> iterator = mCallbacks.iterator(); + while (iterator.hasNext()) { + final Callback cb = iterator.next().get(); + if (cb == null || cb == callback) { + iterator.remove(); + } + } + + if (mCallbacks.isEmpty() && mHaveConditionsStarted) { + if (shouldLog()) Log.d(mTag, "stopping all conditions"); + mConditions.forEach(condition -> condition.removeCallback(mConditionCallback)); + + mAllConditionsMet = false; + mHaveConditionsStarted = false; + } + } + + /** + * Force updates each condition to the value provided. + */ + @VisibleForTesting + public void overrideAllConditionsMet(boolean value) { + mConditions.forEach(condition -> condition.updateCondition(value)); + } + + private boolean shouldLog() { + return Log.isLoggable(mTag, Log.DEBUG); + } + + /** + * Callback that receives updates of whether all conditions have been fulfilled. + */ + public interface Callback { + /** + * Triggered when the fulfillment of all conditions have been met. + * + * @param allConditionsMet True if all conditions have been fulfilled. False if none or + * only partial conditions have been fulfilled. + */ + void onConditionsChanged(boolean allConditionsMet); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java index 31dd82d986f80..f739ae57fc9f0 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java +++ b/packages/SystemUI/src/com/android/systemui/communal/dagger/CommunalModule.java @@ -20,15 +20,20 @@ import android.content.Context; import android.view.View; import android.widget.FrameLayout; +import com.android.systemui.communal.conditions.CommunalCondition; import com.android.systemui.idle.AmbientLightModeMonitor; import com.android.systemui.idle.LightSensorEventsDebounceAlgorithm; import com.android.systemui.idle.dagger.IdleViewComponent; +import java.util.HashSet; +import java.util.Set; + import javax.inject.Named; import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.ElementsIntoSet; /** * Dagger Module providing Communal-related functionality. @@ -39,6 +44,7 @@ import dagger.Provides; }) public interface CommunalModule { String IDLE_VIEW = "idle_view"; + String COMMUNAL_CONDITIONS = "communal_conditions"; /** */ @Provides @@ -56,4 +62,14 @@ public interface CommunalModule { @Binds AmbientLightModeMonitor.DebounceAlgorithm ambientLightDebounceAlgorithm( LightSensorEventsDebounceAlgorithm algorithm); + + /** + * Provides a set of conditions that need to be fulfilled in order for Communal Mode to display. + */ + @Provides + @ElementsIntoSet + @Named(COMMUNAL_CONDITIONS) + static Set provideCommunalConditions() { + return new HashSet<>(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionTest.java new file mode 100644 index 0000000000000..9d7ef0f68bd69 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2021 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.systemui.communal; + +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.communal.conditions.CommunalCondition; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class CommunalConditionTest extends SysuiTestCase { + private FakeCommunalCondition mCondition; + + @Before + public void setup() { + mCondition = spy(new FakeCommunalCondition()); + } + + @Test + public void addCallback_addFirstCallback_triggerStart() { + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + verify(mCondition).start(); + } + + @Test + public void addCallback_addMultipleCallbacks_triggerStartOnlyOnce() { + final CommunalCondition.Callback callback1 = mock(CommunalCondition.Callback.class); + final CommunalCondition.Callback callback2 = mock(CommunalCondition.Callback.class); + final CommunalCondition.Callback callback3 = mock(CommunalCondition.Callback.class); + + mCondition.addCallback(callback1); + mCondition.addCallback(callback2); + mCondition.addCallback(callback3); + + verify(mCondition, times(1)).start(); + } + + @Test + public void addCallback_alreadyStarted_triggerUpdate() { + final CommunalCondition.Callback callback1 = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback1); + + mCondition.fakeUpdateCondition(true); + + final CommunalCondition.Callback callback2 = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback2); + verify(callback2).onConditionChanged(mCondition, true); + } + + @Test + public void removeCallback_removeLastCallback_triggerStop() { + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + verify(mCondition, never()).stop(); + + mCondition.removeCallback(callback); + verify(mCondition).stop(); + } + + @Test + public void updateCondition_falseToTrue_reportTrue() { + mCondition.fakeUpdateCondition(false); + + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + + mCondition.fakeUpdateCondition(true); + verify(callback).onConditionChanged(eq(mCondition), eq(true)); + } + + @Test + public void updateCondition_trueToFalse_reportFalse() { + mCondition.fakeUpdateCondition(true); + + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + + mCondition.fakeUpdateCondition(false); + verify(callback).onConditionChanged(eq(mCondition), eq(false)); + } + + @Test + public void updateCondition_trueToTrue_reportNothing() { + mCondition.fakeUpdateCondition(true); + + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + + mCondition.fakeUpdateCondition(true); + verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean()); + } + + @Test + public void updateCondition_falseToFalse_reportNothing() { + mCondition.fakeUpdateCondition(false); + + final CommunalCondition.Callback callback = mock(CommunalCondition.Callback.class); + mCondition.addCallback(callback); + + mCondition.fakeUpdateCondition(false); + verify(callback, never()).onConditionChanged(eq(mCondition), anyBoolean()); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionsMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionsMonitorTest.java new file mode 100644 index 0000000000000..59ddba1b45977 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalConditionsMonitorTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2021 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.systemui.communal; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.communal.conditions.CommunalCondition; +import com.android.systemui.communal.conditions.CommunalConditionsMonitor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.HashSet; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class CommunalConditionsMonitorTest extends SysuiTestCase { + private FakeCommunalCondition mCondition1; + private FakeCommunalCondition mCondition2; + private FakeCommunalCondition mCondition3; + private HashSet mConditions; + + private CommunalConditionsMonitor mCommunalConditionsMonitor; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + mCondition1 = spy(new FakeCommunalCondition()); + mCondition2 = spy(new FakeCommunalCondition()); + mCondition3 = spy(new FakeCommunalCondition()); + mConditions = new HashSet<>(Arrays.asList(mCondition1, mCondition2, mCondition3)); + + mCommunalConditionsMonitor = new CommunalConditionsMonitor(mConditions); + } + + @Test + public void addCallback_addFirstCallback_addCallbackToAllConditions() { + final CommunalConditionsMonitor.Callback callback1 = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback1); + mConditions.forEach(condition -> verify(condition).addCallback(any())); + + final CommunalConditionsMonitor.Callback callback2 = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback2); + mConditions.forEach(condition -> verify(condition, times(1)).addCallback(any())); + } + + @Test + public void addCallback_addFirstCallback_reportWithDefaultValue() { + final CommunalConditionsMonitor.Callback callback = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback); + verify(callback).onConditionsChanged(false); + } + + @Test + public void addCallback_addSecondCallback_reportWithExistingValue() { + final CommunalConditionsMonitor.Callback callback1 = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback1); + + mCommunalConditionsMonitor.overrideAllConditionsMet(true); + + final CommunalConditionsMonitor.Callback callback2 = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback2); + verify(callback2).onConditionsChanged(true); + } + + @Test + public void removeCallback_shouldNoLongerReceiveUpdate() { + final CommunalConditionsMonitor.Callback callback = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback); + clearInvocations(callback); + mCommunalConditionsMonitor.removeCallback(callback); + + mCommunalConditionsMonitor.overrideAllConditionsMet(true); + verify(callback, never()).onConditionsChanged(true); + + mCommunalConditionsMonitor.overrideAllConditionsMet(false); + verify(callback, never()).onConditionsChanged(false); + } + + @Test + public void removeCallback_removeLastCallback_removeCallbackFromAllConditions() { + final CommunalConditionsMonitor.Callback callback1 = + mock(CommunalConditionsMonitor.Callback.class); + final CommunalConditionsMonitor.Callback callback2 = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback1); + mCommunalConditionsMonitor.addCallback(callback2); + + mCommunalConditionsMonitor.removeCallback(callback1); + mConditions.forEach(condition -> verify(condition, never()).removeCallback(any())); + + mCommunalConditionsMonitor.removeCallback(callback2); + mConditions.forEach(condition -> verify(condition).removeCallback(any())); + } + + @Test + public void updateCallbacks_allConditionsMet_reportTrue() { + final CommunalConditionsMonitor.Callback callback = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback); + clearInvocations(callback); + + mCondition1.fakeUpdateCondition(true); + mCondition2.fakeUpdateCondition(true); + mCondition3.fakeUpdateCondition(true); + + verify(callback).onConditionsChanged(true); + } + + @Test + public void updateCallbacks_oneConditionStoppedMeeting_reportFalse() { + final CommunalConditionsMonitor.Callback callback = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback); + + mCondition1.fakeUpdateCondition(true); + mCondition2.fakeUpdateCondition(true); + mCondition3.fakeUpdateCondition(true); + clearInvocations(callback); + + mCondition1.fakeUpdateCondition(false); + verify(callback).onConditionsChanged(false); + } + + @Test + public void updateCallbacks_shouldOnlyUpdateWhenValueChanges() { + final CommunalConditionsMonitor.Callback callback = + mock(CommunalConditionsMonitor.Callback.class); + mCommunalConditionsMonitor.addCallback(callback); + verify(callback).onConditionsChanged(false); + clearInvocations(callback); + + mCondition1.fakeUpdateCondition(true); + verify(callback, never()).onConditionsChanged(anyBoolean()); + + mCondition2.fakeUpdateCondition(true); + verify(callback, never()).onConditionsChanged(anyBoolean()); + + mCondition3.fakeUpdateCondition(true); + verify(callback).onConditionsChanged(true); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/FakeCommunalCondition.java b/packages/SystemUI/tests/src/com/android/systemui/communal/FakeCommunalCondition.java new file mode 100644 index 0000000000000..882effd8f1f25 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/communal/FakeCommunalCondition.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 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.systemui.communal; + +import com.android.systemui.communal.conditions.CommunalCondition; + +/** + * Fake implementation of {@link CommunalCondition}, and provides a way for tests to update + * condition fulfillment. + */ +public class FakeCommunalCondition extends CommunalCondition { + @Override + public void start() {} + + @Override + public void stop() {} + + public void fakeUpdateCondition(boolean isConditionMet) { + updateCondition(isConditionMet); + } +}