From daed6675fc8f837ff880ba2551221b488a4b8db2 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Fri, 10 Feb 2023 11:44:17 -0800 Subject: [PATCH 1/3] Always have ConditionalCoreStartable subscribe to monitor. Currently, ConditionalCoreStartables bypass subscribing to the condition monitor if no conditions are specified. However, a monitor might have preconditions set on it that would be ignored in this case. This changelist ensures the CoreStartable always subscribes to that any preconditions from the monitor are considered. Test: atest ConditionalCoreStartableTest Test: atest ConditionMonitorTest Bug: 261420432 Change-Id: If4e14bca8c51a7568966950c429dae7c16fdf759 --- .../condition/ConditionalCoreStartable.java | 10 ------- .../condition/ConditionMonitorTest.java | 15 ++++++++++ .../ConditionalCoreStartableTest.java | 30 +++++++++++++++++++ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java index b41bca0d77e1e..8d32a4833471e 100644 --- a/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java +++ b/packages/SystemUI/src/com/android/systemui/util/condition/ConditionalCoreStartable.java @@ -43,11 +43,6 @@ public abstract class ConditionalCoreStartable implements CoreStartable { @Override public final void start() { - if (mConditionSet == null || mConditionSet.isEmpty()) { - onStart(); - return; - } - mStartToken = mMonitor.addSubscription( new Monitor.Subscription.Builder(allConditionsMet -> { if (allConditionsMet) { @@ -63,11 +58,6 @@ public abstract class ConditionalCoreStartable implements CoreStartable { @Override public final void onBootCompleted() { - if (mConditionSet == null || mConditionSet.isEmpty()) { - bootCompleted(); - return; - } - mBootCompletedToken = mMonitor.addSubscription( new Monitor.Subscription.Builder(allConditionsMet -> { if (allConditionsMet) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java index 9eccbb6303abc..aa1636d8a0309 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/ConditionMonitorTest.java @@ -248,6 +248,21 @@ public class ConditionMonitorTest extends SysuiTestCase { verify(callback).onConditionsChanged(true); } + @Test + public void addCallback_preCondition_noConditions_reportAllConditionsMet() { + final Monitor + monitor = new Monitor(mExecutor, new HashSet<>(Arrays.asList(mCondition1))); + final Monitor.Callback callback = mock( + Monitor.Callback.class); + + monitor.addSubscription(new Monitor.Subscription.Builder(callback).build()); + mExecutor.runAllReady(); + verify(callback, never()).onConditionsChanged(true); + mCondition1.fakeUpdateCondition(true); + mExecutor.runAllReady(); + verify(callback).onConditionsChanged(true); + } + @Test public void removeCallback_noFailureOnDoubleRemove() { final Condition condition = mock( diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java index 5ef62c1e7e8dd..b367a603ec674 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionalCoreStartableTest.java @@ -60,6 +60,11 @@ public class ConditionalCoreStartableTest extends SysuiTestCase { mCallback = callback; } + public FakeConditionalCoreStartable(Monitor monitor, Callback callback) { + super(monitor); + mCallback = callback; + } + @Override protected void onStart() { mCallback.onStart(); @@ -122,6 +127,31 @@ public class ConditionalCoreStartableTest extends SysuiTestCase { verify(mMonitor).removeSubscription(mSubscriptionToken); } + @Test + public void testOnStartCallbackWithNoConditions() { + final CoreStartable coreStartable = + new FakeConditionalCoreStartable(mMonitor, + mCallback); + + when(mMonitor.addSubscription(any())).thenReturn(mSubscriptionToken); + coreStartable.start(); + + final ArgumentCaptor subscriptionCaptor = ArgumentCaptor.forClass( + Monitor.Subscription.class); + verify(mMonitor).addSubscription(subscriptionCaptor.capture()); + + final Monitor.Subscription subscription = subscriptionCaptor.getValue(); + + assertThat(subscription.getConditions()).isEmpty(); + + verify(mCallback, never()).onStart(); + + subscription.getCallback().onConditionsChanged(true); + + verify(mCallback).onStart(); + verify(mMonitor).removeSubscription(mSubscriptionToken); + } + /** * Verifies that {@link ConditionalCoreStartable#bootCompleted()} ()} is predicated on From ffbc4a29c9376c83eb6d717da0df7031d287d2e3 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Fri, 3 Feb 2023 13:28:47 -0800 Subject: [PATCH 2/3] Run dream logic only for current user process. This changelist updates dream-related components to only run in the process associated with the current user. Test: manual (exercised in upstream CLs) Fixes: 261420432 Change-Id: I856fc348bb2c606bc15f2bc42a2d743f4994de0b Merged-In: I856fc348bb2c606bc15f2bc42a2d743f4994de0b --- .../android/systemui/dreams/DreamMonitor.java | 11 +++++++-- .../dreams/DreamOverlayRegistrant.java | 12 ++++++---- .../ComplicationTypesUpdater.java | 14 +++++++---- .../DreamClockTimeComplication.java | 11 ++++++--- .../DreamHomeControlsComplication.java | 11 ++++++--- .../complication/SmartSpaceComplication.java | 11 ++++++--- .../systemui/dreams/dagger/DreamModule.java | 24 +++++++++++++++++++ .../systemui/process/ProcessWrapper.java | 5 ++++ .../ComplicationTypesUpdaterTest.java | 6 ++++- .../DreamClockTimeComplicationTest.java | 7 +++++- .../DreamHomeControlsComplicationTest.java | 16 ++++++++----- .../SmartSpaceComplicationTest.java | 12 +++++++++- 12 files changed, 112 insertions(+), 28 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java index 102f2082ebd17..055cd52b23d64 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamMonitor.java @@ -16,19 +16,23 @@ package com.android.systemui.dreams; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; + import android.util.Log; import com.android.systemui.CoreStartable; import com.android.systemui.dreams.callbacks.DreamStatusBarStateCallback; import com.android.systemui.dreams.conditions.DreamCondition; import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; +import javax.inject.Named; /** * A {@link CoreStartable} to retain a monitor for tracking dreaming. */ -public class DreamMonitor implements CoreStartable { +public class DreamMonitor extends ConditionalCoreStartable { private static final String TAG = "DreamMonitor"; // We retain a reference to the monitor so it is not garbage-collected. @@ -39,14 +43,17 @@ public class DreamMonitor implements CoreStartable { @Inject public DreamMonitor(Monitor monitor, DreamCondition dreamCondition, + @Named(DREAM_PRETEXT_MONITOR) Monitor pretextMonitor, DreamStatusBarStateCallback callback) { + super(pretextMonitor); mConditionMonitor = monitor; mDreamCondition = dreamCondition; mCallback = callback; } + @Override - public void start() { + protected void onStart() { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, "started"); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java index 87c5f51ce13ad..a2dcdf52ad3c3 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayRegistrant.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams; import static com.android.systemui.dreams.dagger.DreamModule.DREAM_OVERLAY_SERVICE_COMPONENT; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -33,8 +34,9 @@ import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.util.Log; -import com.android.systemui.CoreStartable; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; import javax.inject.Named; @@ -43,7 +45,7 @@ import javax.inject.Named; * {@link DreamOverlayRegistrant} is responsible for telling system server that SystemUI should be * the designated dream overlay component. */ -public class DreamOverlayRegistrant implements CoreStartable { +public class DreamOverlayRegistrant extends ConditionalCoreStartable { private static final String TAG = "DreamOverlayRegistrant"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final IDreamManager mDreamManager; @@ -102,7 +104,9 @@ public class DreamOverlayRegistrant implements CoreStartable { @Inject public DreamOverlayRegistrant(Context context, @Main Resources resources, - @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent) { + @Named(DREAM_OVERLAY_SERVICE_COMPONENT) ComponentName dreamOverlayServiceComponent, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mContext = context; mResources = resources; mDreamManager = IDreamManager.Stub.asInterface( @@ -111,7 +115,7 @@ public class DreamOverlayRegistrant implements CoreStartable { } @Override - public void start() { + protected void onStart() { final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); filter.addDataSchemeSpecificPart(mOverlayServiceComponent.getPackageName(), diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java index ee2f1af6a99bf..244212b457903 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationTypesUpdater.java @@ -16,27 +16,31 @@ package com.android.systemui.dreams.complication; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; + import android.database.ContentObserver; import android.os.UserHandle; import android.provider.Settings; import com.android.settingslib.dream.DreamBackend; -import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import com.android.systemui.util.settings.SecureSettings; import java.util.concurrent.Executor; import javax.inject.Inject; +import javax.inject.Named; /** * {@link ComplicationTypesUpdater} observes the state of available complication types set by the * user, and pushes updates to {@link DreamOverlayStateController}. */ @SysUISingleton -public class ComplicationTypesUpdater implements CoreStartable { +public class ComplicationTypesUpdater extends ConditionalCoreStartable { private final DreamBackend mDreamBackend; private final Executor mExecutor; private final SecureSettings mSecureSettings; @@ -48,7 +52,9 @@ public class ComplicationTypesUpdater implements CoreStartable { DreamBackend dreamBackend, @Main Executor executor, SecureSettings secureSettings, - DreamOverlayStateController dreamOverlayStateController) { + DreamOverlayStateController dreamOverlayStateController, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamBackend = dreamBackend; mExecutor = executor; mSecureSettings = secureSettings; @@ -56,7 +62,7 @@ public class ComplicationTypesUpdater implements CoreStartable { } @Override - public void start() { + public void onStart() { final ContentObserver settingsObserver = new ContentObserver(null /*handler*/) { @Override public void onChange(boolean selfChange) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java index 77e1fc91e6ee5..bb1e6e2ef06d3 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java @@ -18,11 +18,14 @@ package com.android.systemui.dreams.complication; import static com.android.systemui.dreams.complication.dagger.DreamClockTimeComplicationModule.DREAM_CLOCK_TIME_COMPLICATION_VIEW; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.view.View; import com.android.systemui.CoreStartable; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import javax.inject.Inject; import javax.inject.Named; @@ -60,7 +63,7 @@ public class DreamClockTimeComplication implements Complication { * {@link CoreStartable} responsible for registering {@link DreamClockTimeComplication} with * SystemUI. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamOverlayStateController mDreamOverlayStateController; private final DreamClockTimeComplication mComplication; @@ -70,13 +73,15 @@ public class DreamClockTimeComplication implements Complication { @Inject public Registrant( DreamOverlayStateController dreamOverlayStateController, - DreamClockTimeComplication dreamClockTimeComplication) { + DreamClockTimeComplication dreamClockTimeComplication, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamOverlayStateController = dreamOverlayStateController; mComplication = dreamClockTimeComplication; } @Override - public void start() { + public void onStart() { mDreamOverlayStateController.addComplication(mComplication); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java index 1065b94508f8b..7f395d863c3fc 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java @@ -21,6 +21,7 @@ import static com.android.systemui.controls.dagger.ControlsComponent.Visibility. import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.UNAVAILABLE; import static com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent.DreamHomeControlsModule.DREAM_HOME_CONTROLS_CHIP_VIEW; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; import android.content.Intent; @@ -42,7 +43,9 @@ import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.ViewController; +import com.android.systemui.util.condition.ConditionalCoreStartable; import java.util.List; @@ -75,7 +78,7 @@ public class DreamHomeControlsComplication implements Complication { /** * {@link CoreStartable} for registering the complication with SystemUI on startup. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamHomeControlsComplication mComplication; private final DreamOverlayStateController mDreamOverlayStateController; private final ControlsComponent mControlsComponent; @@ -105,14 +108,16 @@ public class DreamHomeControlsComplication implements Complication { @Inject public Registrant(DreamHomeControlsComplication complication, DreamOverlayStateController dreamOverlayStateController, - ControlsComponent controlsComponent) { + ControlsComponent controlsComponent, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mComplication = complication; mControlsComponent = controlsComponent; mDreamOverlayStateController = dreamOverlayStateController; } @Override - public void start() { + public void onStart() { mControlsComponent.getControlsListingController().ifPresent( c -> c.addCallback(mControlsCallback)); mDreamOverlayStateController.addCallback(mOverlayStateCallback); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java index c3aaf0cbf2d70..e39073bb6711a 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java @@ -17,6 +17,7 @@ package com.android.systemui.dreams.complication; import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_SMARTSPACE_LAYOUT_PARAMS; +import static com.android.systemui.dreams.dagger.DreamModule.DREAM_PRETEXT_MONITOR; import android.content.Context; import android.os.Parcelable; @@ -28,6 +29,8 @@ import com.android.systemui.CoreStartable; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.smartspace.DreamSmartspaceController; import com.android.systemui.plugins.BcSmartspaceDataPlugin; +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.condition.ConditionalCoreStartable; import java.util.List; @@ -61,7 +64,7 @@ public class SmartSpaceComplication implements Complication { * {@link CoreStartable} responsbile for registering {@link SmartSpaceComplication} with * SystemUI. */ - public static class Registrant implements CoreStartable { + public static class Registrant extends ConditionalCoreStartable { private final DreamSmartspaceController mSmartSpaceController; private final DreamOverlayStateController mDreamOverlayStateController; private final SmartSpaceComplication mComplication; @@ -81,14 +84,16 @@ public class SmartSpaceComplication implements Complication { public Registrant( DreamOverlayStateController dreamOverlayStateController, SmartSpaceComplication smartSpaceComplication, - DreamSmartspaceController smartSpaceController) { + DreamSmartspaceController smartSpaceController, + @Named(DREAM_PRETEXT_MONITOR) Monitor monitor) { + super(monitor); mDreamOverlayStateController = dreamOverlayStateController; mComplication = smartSpaceComplication; mSmartSpaceController = smartSpaceController; } @Override - public void start() { + public void onStart() { mDreamOverlayStateController.addCallback(new DreamOverlayStateController.Callback() { @Override public void onStateChanged() { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java index 0ab8c8e42b03b..88c02b8aa790c 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java @@ -29,13 +29,20 @@ import com.android.systemui.dreams.DreamOverlayNotificationCountProvider; import com.android.systemui.dreams.DreamOverlayService; import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule; import com.android.systemui.dreams.touch.scrim.dagger.ScrimModule; +import com.android.systemui.process.condition.UserProcessCondition; +import com.android.systemui.shared.condition.Condition; +import com.android.systemui.shared.condition.Monitor; import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Executor; import javax.inject.Named; +import dagger.Binds; import dagger.Module; import dagger.Provides; +import dagger.multibindings.IntoSet; /** * Dagger Module providing Dream-related functionality. @@ -54,6 +61,8 @@ public interface DreamModule { String DREAM_OVERLAY_ENABLED = "dream_overlay_enabled"; String DREAM_SUPPORTED = "dream_supported"; + String DREAM_PRETEXT_CONDITIONS = "dream_pretext_conditions"; + String DREAM_PRETEXT_MONITOR = "dream_prtext_monitor"; /** * Provides the dream component @@ -112,4 +121,19 @@ public interface DreamModule { static boolean providesDreamSupported(@Main Resources resources) { return resources.getBoolean(com.android.internal.R.bool.config_dreamsSupported); } + + /** */ + @Binds + @IntoSet + @Named(DREAM_PRETEXT_CONDITIONS) + Condition bindsUserProcessCondition(UserProcessCondition condition); + + /** */ + @Provides + @Named(DREAM_PRETEXT_MONITOR) + static Monitor providesDockerPretextMonitor( + @Main Executor executor, + @Named(DREAM_PRETEXT_CONDITIONS) Set pretextConditions) { + return new Monitor(executor, pretextConditions); + } } diff --git a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java index 7db293d96a503..245cf89a83379 100644 --- a/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/process/ProcessWrapper.java @@ -16,11 +16,16 @@ package com.android.systemui.process; +import javax.inject.Inject; + /** * A simple wrapper that provides access to process-related details. This facilitates testing by * providing a mockable target around these details. */ public class ProcessWrapper { + @Inject + public ProcessWrapper() {} + public int getUserHandleIdentifier() { return android.os.Process.myUserHandle().getIdentifier(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java index 9f4a7c820efca..b9db9c464d302 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java @@ -33,6 +33,7 @@ import androidx.test.filters.SmallTest; import com.android.settingslib.dream.DreamBackend; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.SecureSettings; import com.android.systemui.util.time.FakeSystemClock; @@ -66,13 +67,16 @@ public class ComplicationTypesUpdaterTest extends SysuiTestCase { private ComplicationTypesUpdater mController; + @Mock + private Monitor mMonitor; + @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>()); mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor, - mSecureSettings, mDreamOverlayStateController); + mSecureSettings, mDreamOverlayStateController, mMonitor); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java index ec448f94ba830..52aaea16ee70a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java @@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -69,6 +70,9 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase { @Mock private ComplicationLayoutParams mLayoutParams; + @Mock + private Monitor mMonitor; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -83,7 +87,8 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase { final DreamClockTimeComplication.Registrant registrant = new DreamClockTimeComplication.Registrant( mDreamOverlayStateController, - mComplication); + mComplication, + mMonitor); registrant.start(); verify(mDreamOverlayStateController).addComplication(eq(mComplication)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java index 0e249b347c95c..8534d4ff86edc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java @@ -46,6 +46,7 @@ import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent; import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -101,6 +102,9 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { @Captor private ArgumentCaptor mStateCallbackCaptor; + @Mock + private Monitor mMonitor; + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -126,7 +130,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -139,7 +143,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -152,7 +156,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_noFavorites_panel_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(false); @@ -165,7 +169,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceNotAvailable_haveFavorites_doNotAddComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(true); @@ -178,7 +182,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_serviceAvailable_haveFavorites_addComplication() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setHaveFavorites(true); @@ -191,7 +195,7 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { public void complicationAvailability_checkAvailabilityWhenDreamOverlayBecomesActive() { final DreamHomeControlsComplication.Registrant registrant = new DreamHomeControlsComplication.Registrant(mComplication, - mDreamOverlayStateController, mControlsComponent); + mDreamOverlayStateController, mControlsComponent, mMonitor); registrant.start(); setServiceAvailable(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java index c8b2b25568288..77ca9584f9e00 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java @@ -33,6 +33,8 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.smartspace.DreamSmartspaceController; import com.android.systemui.plugins.BcSmartspaceDataPlugin; +import com.android.systemui.shared.condition.Condition; +import com.android.systemui.shared.condition.Monitor; import org.junit.Before; import org.junit.Test; @@ -43,6 +45,8 @@ import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.Collections; +import java.util.HashSet; +import java.util.Set; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -60,6 +64,11 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { @Mock private View mBcSmartspaceView; + @Mock + private Monitor mMonitor; + + private final Set mPreconditions = new HashSet<>(); + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -79,7 +88,8 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { return new SmartSpaceComplication.Registrant( mDreamOverlayStateController, mComplication, - mSmartspaceController); + mSmartspaceController, + mMonitor); } @Test From 71bf33c6b92d6341cea83c082f269d85d8dfb2b8 Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Mon, 13 Feb 2023 12:25:28 -0800 Subject: [PATCH 3/3] Introduce SelfExecutingMonitor for tests. A number of tested components rely on monitors for pretext conditions. In these cases, a mocked monitor will not execute the callback in order for the logic to proceed. This change introduces and integrates SelfExecutingMonitor to handle this case. Bug: 261420432 Test: atest ComplicationTypesUpdaterTest Test: atest DreamClockTimeComplicationTest Test: atest DreamHomeControlsComplicationTest Test: atest SmartSpaceComplicationTest Change-Id: I2368bdcaa8a8a064484c160ddd95bf73882b733d --- .../ComplicationTypesUpdaterTest.java | 3 +- .../DreamClockTimeComplicationTest.java | 3 +- .../DreamHomeControlsComplicationTest.java | 4 +- .../SmartSpaceComplicationTest.java | 3 +- .../condition/SelfExecutingMonitor.java | 62 +++++++++++++++++++ 5 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java index b9db9c464d302..b3329eb5f5b2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationTypesUpdaterTest.java @@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest; import com.android.settingslib.dream.DreamBackend; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.shared.condition.Monitor; import com.android.systemui.util.concurrency.FakeExecutor; @@ -67,7 +68,6 @@ public class ComplicationTypesUpdaterTest extends SysuiTestCase { private ComplicationTypesUpdater mController; - @Mock private Monitor mMonitor; @Before @@ -75,6 +75,7 @@ public class ComplicationTypesUpdaterTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); when(mDreamBackend.getEnabledComplications()).thenReturn(new HashSet<>()); + mMonitor = SelfExecutingMonitor.createInstance(); mController = new ComplicationTypesUpdater(mDreamBackend, mExecutor, mSecureSettings, mDreamOverlayStateController, mMonitor); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java index 52aaea16ee70a..f6662d05c817b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamClockTimeComplicationTest.java @@ -29,6 +29,7 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.shared.condition.Monitor; @@ -70,13 +71,13 @@ public class DreamClockTimeComplicationTest extends SysuiTestCase { @Mock private ComplicationLayoutParams mLayoutParams; - @Mock private Monitor mMonitor; @Before public void setup() { MockitoAnnotations.initMocks(this); when(mDreamClockTimeViewHolderProvider.get()).thenReturn(mDreamClockTimeViewHolder); + mMonitor = SelfExecutingMonitor.createInstance(); } /** diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java index 8534d4ff86edc..3312c4335ab4a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java @@ -38,6 +38,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.animation.view.LaunchableImageView; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.controller.ControlsController; import com.android.systemui.controls.controller.StructureInfo; @@ -102,7 +103,6 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { @Captor private ArgumentCaptor mStateCallbackCaptor; - @Mock private Monitor mMonitor; @Before @@ -116,6 +116,8 @@ public class DreamHomeControlsComplicationTest extends SysuiTestCase { Optional.of(mControlsListingController)); when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE); when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView); + + mMonitor = SelfExecutingMonitor.createInstance(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java index 77ca9584f9e00..ef62abfe36de9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java @@ -30,6 +30,7 @@ import android.view.View; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.condition.SelfExecutingMonitor; import com.android.systemui.dreams.DreamOverlayStateController; import com.android.systemui.dreams.smartspace.DreamSmartspaceController; import com.android.systemui.plugins.BcSmartspaceDataPlugin; @@ -64,7 +65,6 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { @Mock private View mBcSmartspaceView; - @Mock private Monitor mMonitor; private final Set mPreconditions = new HashSet<>(); @@ -72,6 +72,7 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); + mMonitor = SelfExecutingMonitor.createInstance(); } /** diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java new file mode 100644 index 0000000000000..7ee05d02b3cb7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/condition/SelfExecutingMonitor.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2023 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.condition; + +import androidx.annotation.NonNull; + +import com.android.systemui.shared.condition.Monitor; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; + +/** + * {@link SelfExecutingMonitor} creates a monitor that independently executes its logic through + * a {@link FakeExecutor}, which is ran at when a subscription is added and removed. + */ +public class SelfExecutingMonitor extends Monitor { + private final FakeExecutor mExecutor; + + /** + * Default constructor that allows specifying the FakeExecutor to use. + */ + public SelfExecutingMonitor(FakeExecutor executor) { + super(executor); + mExecutor = executor; + } + + @Override + public Subscription.Token addSubscription(@NonNull Subscription subscription) { + final Subscription.Token result = super.addSubscription(subscription); + mExecutor.runAllReady(); + return result; + } + + @Override + public void removeSubscription(@NonNull Subscription.Token token) { + super.removeSubscription(token); + mExecutor.runNextReady(); + } + + /** + * Creates a {@link SelfExecutingMonitor} with a self-managed {@link FakeExecutor}. Use only + * for cases where condition state only will be set at when a subscription is added. + */ + public static SelfExecutingMonitor createInstance() { + final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + final FakeExecutor mExecutor = new FakeExecutor(mFakeSystemClock); + return new SelfExecutingMonitor(mExecutor); + } +}