From bdd33e3b59d95df0ab6e80fa59556a29266c357f Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Tue, 6 Dec 2022 16:37:39 -0800 Subject: [PATCH 1/2] Do not specify root view in TouchInsetManager. TouchInsetManager helps limit the touch targets for a surface to a given set of child views. Previously, a root view was specified at construction, from which the attached surface was retrieved from. Since this information is associated with each tracked view, providing this information upfront is not necessary. This changelist updates TouchInsetManager to retrieve the attached surface from the views rather than at construction. The logic has been updated to support multiple root surfaces, allowing the same TouchInsetManager to be used across surfaces. Test: atest TouchInsetManagertest Bug: 261781069 Change-Id: Ief02e781fd3b2beb1373f05192690f664cacb6c1 --- .../dreams/dagger/DreamOverlayModule.java | 5 +- .../systemui/touch/TouchInsetManager.java | 152 +++++++++++------- .../systemui/touch/TouchInsetManagerTest.java | 93 +++++++---- 3 files changed, 157 insertions(+), 93 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index 67e25713987f8..4e0f86c8b146f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -109,9 +109,8 @@ public abstract class DreamOverlayModule { /** */ @Provides @DreamOverlayComponent.DreamOverlayScope - public static TouchInsetManager providesTouchInsetManager(@Main Executor executor, - DreamOverlayContainerView view) { - return new TouchInsetManager(executor, view); + public static TouchInsetManager providesTouchInsetManager(@Main Executor executor) { + return new TouchInsetManager(executor); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java index 3d07491283c5d..8450c1e6e9d08 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -18,8 +18,9 @@ package com.android.systemui.touch; import android.graphics.Rect; import android.graphics.Region; +import android.util.Log; +import android.view.AttachedSurfaceControl; import android.view.View; -import android.view.ViewRootImpl; import androidx.concurrent.futures.CallbackToFutureAdapter; @@ -34,25 +35,37 @@ import java.util.concurrent.Executor; * is useful for passing through touch events for all but select areas. */ public class TouchInsetManager { + private static final String TAG = "TouchInsetManager"; /** * {@link TouchInsetSession} provides an individualized session with the * {@link TouchInsetManager}, linking any action to the client. */ public static class TouchInsetSession { private final TouchInsetManager mManager; - private final HashSet mTrackedViews; private final Executor mExecutor; private final View.OnLayoutChangeListener mOnLayoutChangeListener = (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) - -> updateTouchRegion(); + -> updateTouchRegions(); + + private final View.OnAttachStateChangeListener mAttachListener = + new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + updateTouchRegions(); + } + + @Override + public void onViewDetachedFromWindow(View v) { + updateTouchRegions(); + } + }; /** * Default constructor * @param manager The parent {@link TouchInsetManager} which will be affected by actions on * this session. - * @param rootView The parent of views that will be tracked. * @param executor An executor for marshalling operations. */ TouchInsetSession(TouchInsetManager manager, Executor executor) { @@ -68,8 +81,9 @@ public class TouchInsetManager { public void addViewToTracking(View view) { mExecutor.execute(() -> { mTrackedViews.add(view); + view.addOnAttachStateChangeListener(mAttachListener); view.addOnLayoutChangeListener(mOnLayoutChangeListener); - updateTouchRegion(); + updateTouchRegions(); }); } @@ -81,22 +95,30 @@ public class TouchInsetManager { mExecutor.execute(() -> { mTrackedViews.remove(view); view.removeOnLayoutChangeListener(mOnLayoutChangeListener); - updateTouchRegion(); + view.removeOnAttachStateChangeListener(mAttachListener); + updateTouchRegions(); }); } - private void updateTouchRegion() { - final Region cumulativeRegion = Region.obtain(); + private void updateTouchRegions() { + mExecutor.execute(() -> { + final HashMap affectedSurfaces = new HashMap<>(); + mTrackedViews.stream().forEach(view -> { + if (!view.isAttachedToWindow()) { + return; + } - mTrackedViews.stream().forEach(view -> { - final Rect boundaries = new Rect(); - view.getBoundsOnScreen(boundaries); - cumulativeRegion.op(boundaries, Region.Op.UNION); + final AttachedSurfaceControl surface = view.getRootSurfaceControl(); + + if (!affectedSurfaces.containsKey(surface)) { + affectedSurfaces.put(surface, Region.obtain()); + } + final Rect boundaries = new Rect(); + view.getBoundsOnScreen(boundaries); + affectedSurfaces.get(surface).op(boundaries, Region.Op.UNION); + }); + mManager.setTouchRegions(this, affectedSurfaces); }); - - mManager.setTouchRegion(this, cumulativeRegion); - - cumulativeRegion.recycle(); } /** @@ -110,32 +132,17 @@ public class TouchInsetManager { } } - private final HashMap mDefinedRegions = new HashMap<>(); + private final HashMap> + mSessionRegions = new HashMap<>(); + private final HashMap mLastAffectedSurfaces = new HashMap(); private final Executor mExecutor; - private final View mRootView; - - private final View.OnAttachStateChangeListener mAttachListener = - new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - updateTouchInset(); - } - - @Override - public void onViewDetachedFromWindow(View v) { - } - }; /** * Default constructor. * @param executor An {@link Executor} to marshal all operations on. - * @param rootView The root {@link View} for all views in sessions. */ - public TouchInsetManager(Executor executor, View rootView) { + public TouchInsetManager(Executor executor) { mExecutor = executor; - mRootView = rootView; - mRootView.addOnAttachStateChangeListener(mAttachListener); - } /** @@ -151,47 +158,68 @@ public class TouchInsetManager { public ListenableFuture checkWithinTouchRegion(int x, int y) { return CallbackToFutureAdapter.getFuture(completer -> { mExecutor.execute(() -> completer.set( - mDefinedRegions.values().stream().anyMatch(region -> region.contains(x, y)))); + mLastAffectedSurfaces.values().stream().anyMatch( + region -> region.contains(x, y)))); return "DreamOverlayTouchMonitor::checkWithinTouchRegion"; }); } - private void updateTouchInset() { - final ViewRootImpl viewRootImpl = mRootView.getViewRootImpl(); + private void updateTouchInsets() { + // Get affected + final HashMap affectedSurfaces = new HashMap<>(); + mSessionRegions.values().stream().forEach(regionMapping -> { + regionMapping.entrySet().stream().forEach(entry -> { + final AttachedSurfaceControl surface = entry.getKey(); + if (!affectedSurfaces.containsKey(surface)) { + affectedSurfaces.put(surface, Region.obtain()); + } - if (viewRootImpl == null) { + affectedSurfaces.get(surface).op(entry.getValue(), Region.Op.UNION); + }); + }); + + affectedSurfaces.entrySet().stream().forEach(entry -> { + entry.getKey().setTouchableRegion(entry.getValue()); + }); + + mLastAffectedSurfaces.entrySet().forEach(entry -> { + final AttachedSurfaceControl surface = entry.getKey(); + if (!affectedSurfaces.containsKey(surface)) { + surface.setTouchableRegion(null); + } + entry.getValue().recycle(); + }); + + mLastAffectedSurfaces.clear(); + mLastAffectedSurfaces.putAll(affectedSurfaces); + } + + protected void setTouchRegions(TouchInsetSession session, + HashMap regions) { + mExecutor.execute(() -> { + recycleRegions(session); + mSessionRegions.put(session, regions); + updateTouchInsets(); + }); + } + + private void recycleRegions(TouchInsetSession session) { + if (!mSessionRegions.containsKey(session)) { + Log.w(TAG, "Removing a session with no regions:" + session); return; } - final Region aggregateRegion = Region.obtain(); - - for (Region region : mDefinedRegions.values()) { - aggregateRegion.op(region, Region.Op.UNION); + for (Region region : mSessionRegions.get(session).values()) { + region.recycle(); } - - viewRootImpl.setTouchableRegion(aggregateRegion); - - aggregateRegion.recycle(); - } - - protected void setTouchRegion(TouchInsetSession session, Region region) { - final Region introducedRegion = Region.obtain(region); - mExecutor.execute(() -> { - mDefinedRegions.put(session, introducedRegion); - updateTouchInset(); - }); } private void clearRegion(TouchInsetSession session) { mExecutor.execute(() -> { - final Region storedRegion = mDefinedRegions.remove(session); - - if (storedRegion != null) { - storedRegion.recycle(); - } - - updateTouchInset(); + recycleRegions(session); + mSessionRegions.remove(session); + updateTouchInsets(); }); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java index 14b9bfb1393f9..a7072225baa74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java @@ -26,8 +26,8 @@ import static org.mockito.Mockito.when; import android.graphics.Rect; import android.graphics.Region; import android.testing.AndroidTestingRunner; +import android.view.AttachedSurfaceControl; import android.view.View; -import android.view.ViewRootImpl; import androidx.test.filters.SmallTest; @@ -47,41 +47,78 @@ import org.mockito.MockitoAnnotations; @RunWith(AndroidTestingRunner.class) public class TouchInsetManagerTest extends SysuiTestCase { @Mock - private View mRootView; - - @Mock - private ViewRootImpl mRootViewImpl; + private AttachedSurfaceControl mAttachedSurfaceControl; private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock()); @Before public void setup() { MockitoAnnotations.initMocks(this); - when(mRootView.getViewRootImpl()).thenReturn(mRootViewImpl); } @Test - public void testRootViewOnAttachedHandling() { + public void testViewOnAttachedHandling() { // Create inset manager - final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor, - mRootView); + final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor); final ArgumentCaptor listener = ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); + final View view = createView(new Rect(0, 0, 0, 0)); + when(view.isAttachedToWindow()).thenReturn(false); + + // Create session + final TouchInsetManager.TouchInsetSession session = insetManager.createSession(); + session.addViewToTracking(view); + + mFakeExecutor.runAllReady(); // Ensure manager has registered to listen to attached state of root view. - verify(mRootView).addOnAttachStateChangeListener(listener.capture()); + verify(view).addOnAttachStateChangeListener(listener.capture()); + + clearInvocations(mAttachedSurfaceControl); + when(view.isAttachedToWindow()).thenReturn(true); // Trigger attachment and verify touchable region is set. - listener.getValue().onViewAttachedToWindow(mRootView); - verify(mRootViewImpl).setTouchableRegion(any()); + listener.getValue().onViewAttachedToWindow(view); + + mFakeExecutor.runAllReady(); + + verify(mAttachedSurfaceControl).setTouchableRegion(any()); + } + + @Test + public void testViewOnDetachedHandling() { + // Create inset manager + final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor); + + final ArgumentCaptor listener = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); + final View view = createView(new Rect(0, 0, 0, 0)); + when(view.isAttachedToWindow()).thenReturn(true); + + // Create session + final TouchInsetManager.TouchInsetSession session = insetManager.createSession(); + session.addViewToTracking(view); + + mFakeExecutor.runAllReady(); + // Ensure manager has registered to listen to attached state of root view. + verify(view).addOnAttachStateChangeListener(listener.capture()); + + clearInvocations(mAttachedSurfaceControl); + when(view.isAttachedToWindow()).thenReturn(false); + + // Trigger detachment and verify touchable region is set. + listener.getValue().onViewDetachedFromWindow(view); + + mFakeExecutor.runAllReady(); + + verify(mAttachedSurfaceControl).setTouchableRegion(any()); } @Test public void testInsetRegionPropagation() { // Create inset manager - final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor, - mRootView); + final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor); // Create session final TouchInsetManager.TouchInsetSession session = insetManager.createSession(); @@ -95,14 +132,13 @@ public class TouchInsetManagerTest extends SysuiTestCase { // Check to see if view was properly accounted for. final Region expectedRegion = Region.obtain(); expectedRegion.op(rect, Region.Op.UNION); - verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion)); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(expectedRegion)); } @Test public void testMultipleRegions() { // Create inset manager - final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor, - mRootView); + final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor); // Create session final TouchInsetManager.TouchInsetSession session = insetManager.createSession(); @@ -112,7 +148,7 @@ public class TouchInsetManagerTest extends SysuiTestCase { session.addViewToTracking(createView(firstBounds)); mFakeExecutor.runAllReady(); - clearInvocations(mRootViewImpl); + clearInvocations(mAttachedSurfaceControl); // Create second session final TouchInsetManager.TouchInsetSession secondSession = insetManager.createSession(); @@ -128,27 +164,26 @@ public class TouchInsetManagerTest extends SysuiTestCase { final Region expectedRegion = Region.obtain(); expectedRegion.op(firstBounds, Region.Op.UNION); expectedRegion.op(secondBounds, Region.Op.UNION); - verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion)); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(expectedRegion)); } - clearInvocations(mRootViewImpl); + clearInvocations(mAttachedSurfaceControl); // clear first session, ensure second session is still reflected. session.clear(); mFakeExecutor.runAllReady(); { final Region expectedRegion = Region.obtain(); - expectedRegion.op(firstBounds, Region.Op.UNION); - verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion)); + expectedRegion.op(secondBounds, Region.Op.UNION); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(expectedRegion)); } } @Test public void testMultipleViews() { // Create inset manager - final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor, - mRootView); + final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor); // Create session final TouchInsetManager.TouchInsetSession session = insetManager.createSession(); @@ -159,7 +194,7 @@ public class TouchInsetManagerTest extends SysuiTestCase { // only capture second invocation. mFakeExecutor.runAllReady(); - clearInvocations(mRootViewImpl); + clearInvocations(mAttachedSurfaceControl); // Add a second view to the session final Rect secondViewBounds = new Rect(4, 4, 9, 10); @@ -173,20 +208,20 @@ public class TouchInsetManagerTest extends SysuiTestCase { final Region expectedRegion = Region.obtain(); expectedRegion.op(firstViewBounds, Region.Op.UNION); expectedRegion.op(secondViewBounds, Region.Op.UNION); - verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion)); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(expectedRegion)); } // Remove second view. session.removeViewFromTracking(secondView); - clearInvocations(mRootViewImpl); + clearInvocations(mAttachedSurfaceControl); mFakeExecutor.runAllReady(); // Ensure first view still reflected in touch region. { final Region expectedRegion = Region.obtain(); expectedRegion.op(firstViewBounds, Region.Op.UNION); - verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion)); + verify(mAttachedSurfaceControl).setTouchableRegion(eq(expectedRegion)); } } @@ -197,6 +232,8 @@ public class TouchInsetManagerTest extends SysuiTestCase { ((Rect) invocation.getArgument(0)).set(rect); return null; }).when(view).getBoundsOnScreen(any()); + when(view.isAttachedToWindow()).thenReturn(true); + when(view.getRootSurfaceControl()).thenReturn(mAttachedSurfaceControl); return view; } From 1a33563df31a1fbb4573915d3d666aa35cfc1f1c Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Wed, 7 Dec 2022 11:18:28 -0800 Subject: [PATCH 2/2] Move Complication logic out of DreamOverlay. This changelist lifts the complication logic, including the ComplicatHostViewController and ComplicationLayoutEngine, out of DreamOverlay. This allows these components to be used elsewhere. Complications are now bound into the DreamOverlayComponent, passed through from the DreamOverlayService. Test: atest DreamOverlayServiceTest Bug: 261781069 Change-Id: I81879e6050d4d0cdeeac69b74acb4fbd548647f5 --- .../systemui/dreams/DreamOverlayService.java | 20 ++++++++-- .../ComplicationLayoutEngine.java | 4 +- .../dagger/ComplicationComponent.kt | 21 +++++++++- .../dagger/ComplicationHostViewModule.java | 12 ++---- .../dagger/ComplicationModule.java | 17 ++++++-- .../dreams/dagger/DreamOverlayComponent.java | 10 ++--- .../dreams/dagger/DreamOverlayModule.java | 26 ------------- .../systemui/touch/TouchInsetManager.java | 7 +++- .../dreams/DreamOverlayServiceTest.java | 39 ++++++++++++++++--- 9 files changed, 97 insertions(+), 59 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 8fdcb0df69000..16b4f99da894b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -45,7 +45,10 @@ import com.android.systemui.dreams.complication.Complication; import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; +import com.android.systemui.touch.TouchInsetManager; +import java.util.Arrays; +import java.util.HashSet; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -84,6 +87,9 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ private final ComplicationComponent mComplicationComponent; + private final com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent + mDreamComplicationComponent; + private final DreamOverlayComponent mDreamOverlayComponent; private final DreamOverlayLifecycleOwner mLifecycleOwner; @@ -135,10 +141,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ DreamOverlayLifecycleOwner lifecycleOwner, WindowManager windowManager, ComplicationComponent.Factory complicationComponentFactory, + com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent.Factory + dreamComplicationComponentFactory, DreamOverlayComponent.Factory dreamOverlayComponentFactory, DreamOverlayStateController stateController, KeyguardUpdateMonitor keyguardUpdateMonitor, UiEventLogger uiEventLogger, + TouchInsetManager touchInsetManager, @Nullable @Named(LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT) ComponentName lowLightDreamComponent) { mContext = context; @@ -154,9 +163,14 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ final Complication.Host host = () -> mExecutor.execute(DreamOverlayService.this::requestExit); - mComplicationComponent = complicationComponentFactory.create(); - mDreamOverlayComponent = - dreamOverlayComponentFactory.create(lifecycleOwner, viewModelStore, host, null); + mComplicationComponent = complicationComponentFactory.create(lifecycleOwner, host, + viewModelStore, touchInsetManager); + mDreamComplicationComponent = dreamComplicationComponentFactory.create( + mComplicationComponent.getVisibilityController(), touchInsetManager); + mDreamOverlayComponent = dreamOverlayComponentFactory.create(lifecycleOwner, + mComplicationComponent.getComplicationHostViewController(), touchInsetManager, + new HashSet<>(Arrays.asList( + mDreamComplicationComponent.getHideComplicationTouchHandler()))); mLifecycleOwner = lifecycleOwner; mLifecycleRegistry = mLifecycleOwner.getRegistry(); diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java index 46ce7a90f5a31..3e9b0103470cb 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java @@ -30,7 +30,7 @@ import androidx.constraintlayout.widget.Constraints; import com.android.systemui.R; import com.android.systemui.dreams.complication.ComplicationLayoutParams.Position; -import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.dreams.complication.dagger.ComplicationModule; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.touch.TouchInsetManager; @@ -50,7 +50,7 @@ import javax.inject.Named; * their layout parameters and attributes. The management of this set is done by * {@link ComplicationHostViewController}. */ -@DreamOverlayComponent.DreamOverlayScope +@ComplicationModule.ComplicationScope public class ComplicationLayoutEngine implements Complication.VisibilityController { public static final String TAG = "ComplicationLayoutEng"; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt index 89497098f8ae2..8d133bd252752 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationComponent.kt @@ -1,12 +1,29 @@ package com.android.systemui.dreams.complication.dagger +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ViewModelStore +import com.android.systemui.dreams.complication.Complication +import com.android.systemui.dreams.complication.ComplicationHostViewController +import com.android.systemui.dreams.complication.ComplicationLayoutEngine +import com.android.systemui.touch.TouchInsetManager +import dagger.BindsInstance import dagger.Subcomponent -@Subcomponent +@Subcomponent(modules = [ComplicationModule::class]) +@ComplicationModule.ComplicationScope interface ComplicationComponent { /** Factory for generating [ComplicationComponent]. */ @Subcomponent.Factory interface Factory { - fun create(): ComplicationComponent + fun create( + @BindsInstance lifecycleOwner: LifecycleOwner, + @BindsInstance host: Complication.Host, + @BindsInstance viewModelStore: ViewModelStore, + @BindsInstance touchInsetManager: TouchInsetManager + ): ComplicationComponent } + + fun getComplicationHostViewController(): ComplicationHostViewController + + fun getVisibilityController(): ComplicationLayoutEngine } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java index 09cc7c51ccf4e..797906fbaf8e0 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java @@ -24,13 +24,12 @@ import androidx.constraintlayout.widget.ConstraintLayout; import com.android.internal.util.Preconditions; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.dreams.dagger.DreamOverlayComponent; - -import javax.inject.Named; import dagger.Module; import dagger.Provides; +import javax.inject.Named; + /** * Module for providing a scoped host view. */ @@ -49,7 +48,7 @@ public abstract class ComplicationHostViewModule { */ @Provides @Named(SCOPED_COMPLICATIONS_LAYOUT) - @DreamOverlayComponent.DreamOverlayScope + @ComplicationModule.ComplicationScope static ConstraintLayout providesComplicationHostView( LayoutInflater layoutInflater) { return Preconditions.checkNotNull((ConstraintLayout) @@ -60,7 +59,6 @@ public abstract class ComplicationHostViewModule { @Provides @Named(COMPLICATION_MARGIN_DEFAULT) - @DreamOverlayComponent.DreamOverlayScope static int providesComplicationPadding(@Main Resources resources) { return resources.getDimensionPixelSize(R.dimen.dream_overlay_complication_margin); } @@ -70,7 +68,6 @@ public abstract class ComplicationHostViewModule { */ @Provides @Named(COMPLICATIONS_FADE_OUT_DURATION) - @DreamOverlayComponent.DreamOverlayScope static int providesComplicationsFadeOutDuration(@Main Resources resources) { return resources.getInteger(R.integer.complicationFadeOutMs); } @@ -80,7 +77,6 @@ public abstract class ComplicationHostViewModule { */ @Provides @Named(COMPLICATIONS_FADE_OUT_DELAY) - @DreamOverlayComponent.DreamOverlayScope static int providesComplicationsFadeOutDelay(@Main Resources resources) { return resources.getInteger(R.integer.complicationFadeOutDelayMs); } @@ -90,7 +86,6 @@ public abstract class ComplicationHostViewModule { */ @Provides @Named(COMPLICATIONS_FADE_IN_DURATION) - @DreamOverlayComponent.DreamOverlayScope static int providesComplicationsFadeInDuration(@Main Resources resources) { return resources.getInteger(R.integer.complicationFadeInMs); } @@ -100,7 +95,6 @@ public abstract class ComplicationHostViewModule { */ @Provides @Named(COMPLICATIONS_RESTORE_TIMEOUT) - @DreamOverlayComponent.DreamOverlayScope static int providesComplicationsRestoreTimeout(@Main Resources resources) { return resources.getInteger(R.integer.complicationRestoreMs); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java index 5c2fdf5c9af4a..dbf5ab000a8a6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java @@ -24,16 +24,16 @@ import androidx.lifecycle.ViewModelStore; import com.android.systemui.dreams.complication.Complication; import com.android.systemui.dreams.complication.ComplicationCollectionViewModel; import com.android.systemui.dreams.complication.ComplicationLayoutEngine; +import com.android.systemui.touch.TouchInsetManager; + +import dagger.Module; +import dagger.Provides; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import javax.inject.Named; import javax.inject.Scope; - -import dagger.Module; -import dagger.Provides; - /** * Module for housing components related to rendering complications. */ @@ -73,4 +73,13 @@ public interface ComplicationModule { ComplicationLayoutEngine engine) { return engine; } + + /** + * Provides a new touch inset session instance for complication logic. + */ + @Provides + static TouchInsetManager.TouchInsetSession providesTouchInsetSession( + TouchInsetManager manager) { + return manager.createSession(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java index 584829074cf45..0332f888c866a 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java @@ -23,14 +23,13 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import android.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.ViewModelStore; import com.android.systemui.dreams.DreamOverlayContainerViewController; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.complication.dagger.ComplicationModule; +import com.android.systemui.dreams.complication.ComplicationHostViewController; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; import com.android.systemui.dreams.touch.DreamTouchHandler; import com.android.systemui.dreams.touch.dagger.DreamTouchModule; +import com.android.systemui.touch.TouchInsetManager; import dagger.BindsInstance; import dagger.Subcomponent; @@ -48,7 +47,6 @@ import javax.inject.Scope; @Subcomponent(modules = { DreamTouchModule.class, DreamOverlayModule.class, - ComplicationModule.class, }) @DreamOverlayComponent.DreamOverlayScope public interface DreamOverlayComponent { @@ -57,8 +55,8 @@ public interface DreamOverlayComponent { interface Factory { DreamOverlayComponent create( @BindsInstance LifecycleOwner lifecycleOwner, - @BindsInstance ViewModelStore store, - @BindsInstance Complication.Host host, + @BindsInstance ComplicationHostViewController complicationHostViewController, + @BindsInstance TouchInsetManager touchInsetManager, @BindsInstance @Named(DREAM_TOUCH_HANDLERS) @Nullable Set dreamTouchHandlers); } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java index 4e0f86c8b146f..448538193eaf9 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java @@ -29,20 +29,15 @@ import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.DreamOverlayContainerView; import com.android.systemui.dreams.DreamOverlayStatusBarView; -import com.android.systemui.dreams.complication.Complication; -import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler; -import com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent; import com.android.systemui.dreams.touch.DreamTouchHandler; import com.android.systemui.touch.TouchInsetManager; import dagger.Module; import dagger.Provides; import dagger.multibindings.ElementsIntoSet; -import dagger.multibindings.IntoSet; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.Executor; import javax.inject.Named; @@ -106,13 +101,6 @@ public abstract class DreamOverlayModule { return manager.createSession(); } - /** */ - @Provides - @DreamOverlayComponent.DreamOverlayScope - public static TouchInsetManager providesTouchInsetManager(@Main Executor executor) { - return new TouchInsetManager(executor); - } - /** */ @Provides @DreamOverlayComponent.DreamOverlayScope @@ -263,18 +251,4 @@ public abstract class DreamOverlayModule { @Named(DREAM_TOUCH_HANDLERS) @Nullable Set touchHandlers) { return touchHandlers != null ? touchHandlers : new HashSet<>(); } - - /** - * Provides {@link HideComplicationTouchHandler} for inclusion in touch handling over the dream. - */ - @Provides - @IntoSet - public static DreamTouchHandler providesHideComplicationTouchHandler( - ComplicationComponent.Factory componentFactory, - Complication.VisibilityController visibilityController, - TouchInsetManager touchInsetManager) { - ComplicationComponent component = - componentFactory.create(visibilityController, touchInsetManager); - return component.getHideComplicationTouchHandler(); - } } diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java index 8450c1e6e9d08..166ac9e737f3b 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -24,12 +24,16 @@ import android.view.View; import androidx.concurrent.futures.CallbackToFutureAdapter; +import com.android.systemui.dagger.qualifiers.Main; + import com.google.common.util.concurrent.ListenableFuture; import java.util.HashMap; import java.util.HashSet; import java.util.concurrent.Executor; +import javax.inject.Inject; + /** * {@link TouchInsetManager} handles setting the touchable inset regions for a given View. This * is useful for passing through touch events for all but select areas. @@ -141,7 +145,8 @@ public class TouchInsetManager { * Default constructor. * @param executor An {@link Executor} to marshal all operations on. */ - public TouchInsetManager(Executor executor) { + @Inject + public TouchInsetManager(@Main Executor executor) { mExecutor = executor; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 67cf2fcfd1a4b..430575c1d0c59 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -19,7 +19,6 @@ package com.android.systemui.dreams; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -45,9 +44,12 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.UiEventLogger; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.complication.ComplicationLayoutEngine; import com.android.systemui.dreams.complication.dagger.ComplicationComponent; import com.android.systemui.dreams.dagger.DreamOverlayComponent; +import com.android.systemui.dreams.dreamcomplication.HideComplicationTouchHandler; import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor; +import com.android.systemui.touch.TouchInsetManager; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.utils.leaks.LeakCheckedTest; @@ -93,6 +95,20 @@ public class DreamOverlayServiceTest extends SysuiTestCase { @Mock ComplicationComponent mComplicationComponent; + @Mock + ComplicationLayoutEngine mComplicationVisibilityController; + + @Mock + com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent.Factory + mDreamComplicationComponentFactory; + + @Mock + com.android.systemui.dreams.dreamcomplication.dagger.ComplicationComponent + mDreamComplicationComponent; + + @Mock + HideComplicationTouchHandler mHideComplicationTouchHandler; + @Mock DreamOverlayComponent.Factory mDreamOverlayComponentFactory; @@ -117,6 +133,9 @@ public class DreamOverlayServiceTest extends SysuiTestCase { @Mock ViewGroup mDreamOverlayContainerViewParent; + @Mock + TouchInsetManager mTouchInsetManager; + @Mock UiEventLogger mUiEventLogger; @@ -136,25 +155,33 @@ public class DreamOverlayServiceTest extends SysuiTestCase { when(mDreamOverlayComponent.getDreamOverlayTouchMonitor()) .thenReturn(mDreamOverlayTouchMonitor); when(mComplicationComponentFactory - .create()) + .create(any(), any(), any(), any())) .thenReturn(mComplicationComponent); - // TODO(b/261781069): A touch handler should be passed in from the complication component - // when the complication component is introduced. + when(mComplicationComponent.getVisibilityController()) + .thenReturn(mComplicationVisibilityController); + when(mDreamComplicationComponent.getHideComplicationTouchHandler()) + .thenReturn(mHideComplicationTouchHandler); + when(mDreamComplicationComponentFactory + .create(any(), any())) + .thenReturn(mDreamComplicationComponent); when(mDreamOverlayComponentFactory - .create(any(), any(), any(), isNull())) + .create(any(), any(), any(), any())) .thenReturn(mDreamOverlayComponent); when(mDreamOverlayContainerViewController.getContainerView()) .thenReturn(mDreamOverlayContainerView); - mService = new DreamOverlayService(mContext, + mService = new DreamOverlayService( + mContext, mMainExecutor, mLifecycleOwner, mWindowManager, mComplicationComponentFactory, + mDreamComplicationComponentFactory, mDreamOverlayComponentFactory, mStateController, mKeyguardUpdateMonitor, mUiEventLogger, + mTouchInsetManager, LOW_LIGHT_COMPONENT); }