Merge changes I81879e60,Ief02e781
* changes: Move Complication logic out of DreamOverlay. Do not specify root view in TouchInsetManager.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,14 +101,6 @@ public abstract class DreamOverlayModule {
|
||||
return manager.createSession();
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@DreamOverlayComponent.DreamOverlayScope
|
||||
public static TouchInsetManager providesTouchInsetManager(@Main Executor executor,
|
||||
DreamOverlayContainerView view) {
|
||||
return new TouchInsetManager(executor, view);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@DreamOverlayComponent.DreamOverlayScope
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
private void updateTouchRegions() {
|
||||
mExecutor.execute(() -> {
|
||||
final HashMap<AttachedSurfaceControl, Region> 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 +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();
|
||||
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());
|
||||
}
|
||||
|
||||
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<AttachedSurfaceControl, Region> 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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user