diff options
| author | 2022-12-13 23:05:33 +0000 | |
|---|---|---|
| committer | 2022-12-13 23:05:33 +0000 | |
| commit | e6cf58ac7cb981fa0c2315d93c27725b6282a88c (patch) | |
| tree | 1866bd6fb9ce9720b3f696bafee553483ac0d8a7 | |
| parent | a942c6c9d8b255877327f22d68b6edf3095eabde (diff) | |
| parent | 1a33563df31a1fbb4573915d3d666aa35cfc1f1c (diff) | |
Merge changes I81879e60,Ief02e781
* changes:
Move Complication logic out of DreamOverlay.
Do not specify root view in TouchInsetManager.
10 files changed, 249 insertions, 147 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 8fdcb0df6900..16b4f99da894 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 46ce7a90f5a3..3e9b0103470c 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 89497098f8ae..8d133bd25275 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 09cc7c51ccf4..797906fbaf8e 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 5c2fdf5c9af4..dbf5ab000a8a 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 584829074cf4..0332f888c866 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<DreamTouchHandler> 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 67e25713987f..448538193eaf 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; @@ -109,14 +104,6 @@ public abstract class DreamOverlayModule { /** */ @Provides @DreamOverlayComponent.DreamOverlayScope - public static TouchInsetManager providesTouchInsetManager(@Main Executor executor, - DreamOverlayContainerView view) { - return new TouchInsetManager(executor, view); - } - - /** */ - @Provides - @DreamOverlayComponent.DreamOverlayScope public static DreamOverlayStatusBarView providesDreamOverlayStatusBarView( DreamOverlayContainerView view) { return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_status_bar), @@ -264,18 +251,4 @@ public abstract class DreamOverlayModule { @Named(DREAM_TOUCH_HANDLERS) @Nullable Set<DreamTouchHandler> 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 3d07491283c5..166ac9e737f3 100644 --- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java +++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java @@ -18,41 +18,58 @@ 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; +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. */ 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<View> 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 +85,9 @@ public class TouchInsetManager { public void addViewToTracking(View view) { mExecutor.execute(() -> { mTrackedViews.add(view); + view.addOnAttachStateChangeListener(mAttachListener); view.addOnLayoutChangeListener(mOnLayoutChangeListener); - updateTouchRegion(); + updateTouchRegions(); }); } @@ -81,22 +99,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(); - - mTrackedViews.stream().forEach(view -> { - final Rect boundaries = new Rect(); - view.getBoundsOnScreen(boundaries); - cumulativeRegion.op(boundaries, Region.Op.UNION); + private void updateTouchRegions() { + mExecutor.execute(() -> { + final HashMap<AttachedSurfaceControl, Region> affectedSurfaces = new HashMap<>(); + mTrackedViews.stream().forEach(view -> { + if (!view.isAttachedToWindow()) { + return; + } + + 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 +136,18 @@ public class TouchInsetManager { } } - private final HashMap<TouchInsetSession, Region> mDefinedRegions = new HashMap<>(); + private final HashMap<TouchInsetSession, HashMap<AttachedSurfaceControl, Region>> + mSessionRegions = new HashMap<>(); + private final HashMap<AttachedSurfaceControl, Region> 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) { + @Inject + public TouchInsetManager(@Main Executor executor) { mExecutor = executor; - mRootView = rootView; - mRootView.addOnAttachStateChangeListener(mAttachListener); - } /** @@ -151,47 +163,68 @@ public class TouchInsetManager { public ListenableFuture<Boolean> 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(); - - if (viewRootImpl == null) { - return; - } + private void updateTouchInsets() { + // Get affected + final HashMap<AttachedSurfaceControl, Region> 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()); + } - final Region aggregateRegion = Region.obtain(); + affectedSurfaces.get(surface).op(entry.getValue(), Region.Op.UNION); + }); + }); - for (Region region : mDefinedRegions.values()) { - aggregateRegion.op(region, Region.Op.UNION); - } + affectedSurfaces.entrySet().stream().forEach(entry -> { + entry.getKey().setTouchableRegion(entry.getValue()); + }); - viewRootImpl.setTouchableRegion(aggregateRegion); + mLastAffectedSurfaces.entrySet().forEach(entry -> { + final AttachedSurfaceControl surface = entry.getKey(); + if (!affectedSurfaces.containsKey(surface)) { + surface.setTouchableRegion(null); + } + entry.getValue().recycle(); + }); - aggregateRegion.recycle(); + mLastAffectedSurfaces.clear(); + mLastAffectedSurfaces.putAll(affectedSurfaces); } - protected void setTouchRegion(TouchInsetSession session, Region region) { - final Region introducedRegion = Region.obtain(region); + protected void setTouchRegions(TouchInsetSession session, + HashMap<AttachedSurfaceControl, Region> regions) { mExecutor.execute(() -> { - mDefinedRegions.put(session, introducedRegion); - updateTouchInset(); + recycleRegions(session); + mSessionRegions.put(session, regions); + updateTouchInsets(); }); } - private void clearRegion(TouchInsetSession session) { - mExecutor.execute(() -> { - final Region storedRegion = mDefinedRegions.remove(session); + private void recycleRegions(TouchInsetSession session) { + if (!mSessionRegions.containsKey(session)) { + Log.w(TAG, "Removing a session with no regions:" + session); + return; + } - if (storedRegion != null) { - storedRegion.recycle(); - } + for (Region region : mSessionRegions.get(session).values()) { + region.recycle(); + } + } - updateTouchInset(); + private void clearRegion(TouchInsetSession session) { + mExecutor.execute(() -> { + recycleRegions(session); + mSessionRegions.remove(session); + updateTouchInsets(); }); } } 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 67cf2fcfd1a4..430575c1d0c5 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; @@ -94,6 +96,20 @@ public class DreamOverlayServiceTest extends SysuiTestCase { 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; @Mock @@ -118,6 +134,9 @@ public class DreamOverlayServiceTest extends SysuiTestCase { ViewGroup mDreamOverlayContainerViewParent; @Mock + TouchInsetManager mTouchInsetManager; + + @Mock UiEventLogger mUiEventLogger; @Captor @@ -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); } 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 14b9bfb1393f..a7072225baa7 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<View.OnAttachStateChangeListener> 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<View.OnAttachStateChangeListener> 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; } |