summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java202
13 files changed, 508 insertions, 10 deletions
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 83e6a54e272b..a0a876825a6f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -701,4 +701,10 @@
<!-- How long in milliseconds before full burn-in protection is achieved. -->
<integer name="config_dreamOverlayMillisUntilFullJitter">240000</integer>
+
+ <integer name="complicationFadeOutMs">500</integer>
+
+ <integer name="complicationFadeInMs">500</integer>
+
+ <integer name="complicationRestoreMs">1000</integer>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
index fe458f4c5318..51bd31100ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/Complication.java
@@ -186,6 +186,19 @@ public interface Complication {
}
/**
+ * The implementation of this interface is in charge of managing the visible state of
+ * the shown complication.
+ */
+ interface VisibilityController {
+ /**
+ * Called to set the visibility of all shown and future complications.
+ * @param visibility The desired future visibility.
+ * @param animate whether the change should be animated.
+ */
+ void setVisibility(@View.Visibility int visibility, boolean animate);
+ }
+
+ /**
* Returned through {@link Complication#createView(ComplicationViewModel)}, {@link ViewHolder}
* is a container for a single {@link Complication} instance. The {@link Host} guarantees that
* the {@link ViewHolder} will be retained for the lifetime of the {@link Complication}
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 2999c723f634..aa433832d462 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -16,17 +16,23 @@
package com.android.systemui.dreams.complication;
+import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION;
+import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION;
import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN;
import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.Constraints;
import com.android.systemui.R;
+import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.touch.TouchInsetManager;
import java.util.ArrayList;
@@ -43,7 +49,8 @@ import javax.inject.Named;
* their layout parameters and attributes. The management of this set is done by
* {@link ComplicationHostViewController}.
*/
-public class ComplicationLayoutEngine {
+@DreamOverlayComponent.DreamOverlayScope
+public class ComplicationLayoutEngine implements Complication.VisibilityController {
public static final String TAG = "ComplicationLayoutEngine";
/**
@@ -454,15 +461,45 @@ public class ComplicationLayoutEngine {
private final HashMap<ComplicationId, ViewEntry> mEntries = new HashMap<>();
private final HashMap<Integer, PositionGroup> mPositions = new HashMap<>();
private final TouchInsetManager.TouchInsetSession mSession;
+ private final int mFadeInDuration;
+ private final int mFadeOutDuration;
+ private ViewPropertyAnimator mViewPropertyAnimator;
/** */
@Inject
public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout,
@Named(COMPLICATION_MARGIN) int margin,
- TouchInsetManager.TouchInsetSession session) {
+ TouchInsetManager.TouchInsetSession session,
+ @Named(COMPLICATIONS_FADE_IN_DURATION) int fadeInDuration,
+ @Named(COMPLICATIONS_FADE_OUT_DURATION) int fadeOutDuration) {
mLayout = layout;
mMargin = margin;
mSession = session;
+ mFadeInDuration = fadeInDuration;
+ mFadeOutDuration = fadeOutDuration;
+ }
+
+ @Override
+ public void setVisibility(int visibility, boolean animate) {
+ final boolean appearing = visibility == View.VISIBLE;
+
+ if (mViewPropertyAnimator != null) {
+ mViewPropertyAnimator.cancel();
+ }
+
+ if (appearing) {
+ mLayout.setVisibility(View.VISIBLE);
+ }
+
+ mViewPropertyAnimator = mLayout.animate()
+ .alpha(appearing ? 1f : 0f)
+ .setDuration(appearing ? mFadeInDuration : mFadeOutDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLayout.setVisibility(visibility);
+ }
+ });
}
/**
@@ -477,6 +514,8 @@ public class ComplicationLayoutEngine {
*/
public void addComplication(ComplicationId id, View view,
ComplicationLayoutParams lp, @Complication.Category int category) {
+ Log.d(TAG, "engine: " + this + " addComplication");
+
// If the complication is present, remove.
if (mEntries.containsKey(id)) {
removeComplication(id);
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 f701173c26f6..11d89d2dc816 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
@@ -38,6 +38,9 @@ import dagger.Provides;
public abstract class ComplicationHostViewModule {
public static final String SCOPED_COMPLICATIONS_LAYOUT = "scoped_complications_layout";
public static final String COMPLICATION_MARGIN = "complication_margin";
+ public static final String COMPLICATIONS_FADE_OUT_DURATION = "complications_fade_out_duration";
+ public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration";
+ public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout";
/**
* Generates a {@link ConstraintLayout}, which can host
@@ -60,4 +63,34 @@ public abstract class ComplicationHostViewModule {
static int providesComplicationPadding(@Main Resources resources) {
return resources.getDimensionPixelSize(R.dimen.dream_overlay_complication_margin);
}
+
+ /**
+ * Provides the fade out duration for complications.
+ */
+ @Provides
+ @Named(COMPLICATIONS_FADE_OUT_DURATION)
+ @DreamOverlayComponent.DreamOverlayScope
+ static int providesComplicationsFadeOutDuration(@Main Resources resources) {
+ return resources.getInteger(R.integer.complicationFadeOutMs);
+ }
+
+ /**
+ * Provides the fade in duration for complications.
+ */
+ @Provides
+ @Named(COMPLICATIONS_FADE_IN_DURATION)
+ @DreamOverlayComponent.DreamOverlayScope
+ static int providesComplicationsFadeInDuration(@Main Resources resources) {
+ return resources.getInteger(R.integer.complicationFadeInMs);
+ }
+
+ /**
+ * Provides the timeout for restoring complication visibility.
+ */
+ @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 785a95df930d..5c2fdf5c9af4 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
@@ -21,7 +21,9 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import androidx.lifecycle.ViewModelProvider;
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 java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -62,4 +64,13 @@ public interface ComplicationModule {
return provider.get(ComplicationCollectionViewModel.class);
}
+
+ /**
+ * Provides the visibility controller for display complications.
+ */
+ @Provides
+ static Complication.VisibilityController providesVisibilityController(
+ ComplicationLayoutEngine engine) {
+ return engine;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
index 65f060b43c08..de5b4bb9e520 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamModule.java
@@ -21,7 +21,6 @@ import android.content.Context;
import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dreams.complication.dagger.DreamPreviewComplicationComponent;
import com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule;
-import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
import dagger.Module;
import dagger.Provides;
@@ -30,7 +29,6 @@ import dagger.Provides;
* Dagger Module providing Communal-related functionality.
*/
@Module(includes = {
- DreamTouchModule.class,
RegisteredComplicationsModule.class,
},
subcomponents = {
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 05ab9015fecc..f927ba64a92b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -26,6 +26,7 @@ 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.touch.DreamOverlayTouchMonitor;
+import com.android.systemui.dreams.touch.dagger.DreamTouchModule;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -39,6 +40,7 @@ import dagger.Subcomponent;
* Dagger subcomponent for {@link DreamOverlayModule}.
*/
@Subcomponent(modules = {
+ DreamTouchModule.class,
DreamOverlayModule.class,
ComplicationModule.class,
})
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
new file mode 100644
index 000000000000..d4ba2d82f38a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/HideComplicationTouchHandler.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch;
+
+import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_RESTORE_TIMEOUT;
+
+import android.os.Handler;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.touch.TouchInsetManager;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * {@link HideComplicationTouchHandler} is responsible for hiding the overlay complications from
+ * visibility whenever there is touch interactions outside the overlay. The overlay interaction
+ * scope includes touches to the complication plus any touch entry region for gestures as specified
+ * to the {@link DreamOverlayTouchMonitor}.
+ *
+ * This {@link DreamTouchHandler} is also responsible for fading in the complications at the end
+ * of the {@link com.android.systemui.dreams.touch.DreamTouchHandler.TouchSession}.
+ */
+public class HideComplicationTouchHandler implements DreamTouchHandler {
+ private static final String TAG = "HideComplicationHandler";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Complication.VisibilityController mVisibilityController;
+ private final int mRestoreTimeout;
+ private final Handler mHandler;
+ private final Executor mExecutor;
+ private final TouchInsetManager mTouchInsetManager;
+
+ private final Runnable mRestoreComplications = new Runnable() {
+ @Override
+ public void run() {
+ mVisibilityController.setVisibility(View.VISIBLE, true);
+ }
+ };
+
+ @Inject
+ HideComplicationTouchHandler(Complication.VisibilityController visibilityController,
+ @Named(COMPLICATIONS_RESTORE_TIMEOUT) int restoreTimeout,
+ TouchInsetManager touchInsetManager,
+ @Main Executor executor,
+ @Main Handler handler) {
+ mVisibilityController = visibilityController;
+ mRestoreTimeout = restoreTimeout;
+ mHandler = handler;
+ mTouchInsetManager = touchInsetManager;
+ mExecutor = executor;
+ }
+
+ @Override
+ public void onSessionStart(TouchSession session) {
+ if (DEBUG) {
+ Log.d(TAG, "onSessionStart");
+ }
+
+ // If other sessions are interested in this touch, do not fade out elements.
+ if (session.getActiveSessionCount() > 1) {
+ if (DEBUG) {
+ Log.d(TAG, "multiple active touch sessions, not fading");
+ }
+ session.pop();
+ return;
+ }
+
+ session.registerInputListener(ev -> {
+ if (!(ev instanceof MotionEvent)) {
+ return;
+ }
+
+ final MotionEvent motionEvent = (MotionEvent) ev;
+
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_DOWN received");
+ }
+
+ final ListenableFuture<Boolean> touchCheck = mTouchInsetManager
+ .checkWithinTouchRegion(Math.round(motionEvent.getX()),
+ Math.round(motionEvent.getY()));
+
+ touchCheck.addListener(() -> {
+ try {
+ if (!touchCheck.get()) {
+ mHandler.removeCallbacks(mRestoreComplications);
+ mVisibilityController.setVisibility(View.INVISIBLE, true);
+ } else {
+ // If a touch occurred inside the dream overlay touch insets, do not
+ // handle the touch.
+ session.pop();
+ }
+ } catch (InterruptedException | ExecutionException exception) {
+ Log.e(TAG, "could not check TouchInsetManager:" + exception);
+ }
+ }, mExecutor);
+ } else if (motionEvent.getAction() == MotionEvent.ACTION_CANCEL
+ || motionEvent.getAction() == MotionEvent.ACTION_UP) {
+ // End session and initiate delayed reappearance of the complications.
+ session.pop();
+ mHandler.postDelayed(mRestoreComplications, mRestoreTimeout);
+ }
+ });
+ }
+
+ @Override
+ public void onSessionEnd(TouchSession session) {
+ if (DEBUG) {
+ Log.d(TAG, "onSessionEnd");
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
index dad0004613f6..7338ecba8cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/DreamTouchModule.java
@@ -23,6 +23,7 @@ import dagger.Module;
*/
@Module(includes = {
BouncerSwipeModule.class,
+ HideComplicationModule.class,
}, subcomponents = {
InputSessionComponent.class,
})
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java
new file mode 100644
index 000000000000..3800ff75aed0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/HideComplicationModule.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch.dagger;
+
+import com.android.systemui.dreams.touch.DreamTouchHandler;
+import com.android.systemui.dreams.touch.HideComplicationTouchHandler;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoSet;
+
+/**
+ * Module for {@link HideComplicationTouchHandler}.
+ */
+@Module
+public class HideComplicationModule {
+ /**
+ * Provides {@link HideComplicationTouchHandler} for inclusion in touch handling over the dream.
+ */
+ @Provides
+ @IntoSet
+ public static DreamTouchHandler providesHideComplicationTouchHandler(
+ HideComplicationTouchHandler touchHandler) {
+ return touchHandler;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
index de4e1e2f5886..3d07491283c5 100644
--- a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
@@ -21,6 +21,10 @@ import android.graphics.Region;
import android.view.View;
import android.view.ViewRootImpl;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.Executor;
@@ -141,6 +145,18 @@ public class TouchInsetManager {
return new TouchInsetSession(this, mExecutor);
}
+ /**
+ * Checks to see if the given point coordinates fall within an inset region.
+ */
+ 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))));
+
+ return "DreamOverlayTouchMonitor::checkWithinTouchRegion";
+ });
+ }
+
private void updateTouchInset() {
final ViewRootImpl viewRootImpl = mRootView.getViewRootImpl();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index 51dcf2ec18f4..d1d9ec3af711 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -117,7 +117,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
mLayout);
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -145,7 +145,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
mLayout);
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -162,7 +162,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
@Test
public void testDirectionLayout() {
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -211,7 +211,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
@Test
public void testPositionLayout() {
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -299,7 +299,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
public void testMargin() {
final int margin = 5;
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, margin, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, margin, mTouchSession, 0, 0);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -374,7 +374,7 @@ public class ComplicationLayoutEngineTest extends SysuiTestCase {
@Test
public void testRemoval() {
final ComplicationLayoutEngine engine =
- new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
new file mode 100644
index 000000000000..0a021331d9d1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/HideComplicationTouchHandlerTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dreams.touch;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.touch.TouchInsetManager;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class HideComplicationTouchHandlerTest extends SysuiTestCase {
+ private static final int RESTORE_TIMEOUT = 1000;
+
+ @Mock
+ Complication.VisibilityController mVisibilityController;
+
+ @Mock
+ TouchInsetManager mTouchInsetManager;
+
+ @Mock
+ Handler mHandler;
+
+ @Mock
+ MotionEvent mMotionEvent;
+
+ @Mock
+ DreamTouchHandler.TouchSession mSession;
+
+ FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Ensures no actions are taken when there multiple sessions.
+ */
+ @Test
+ public void testSessionEndOnMultipleSessions() {
+ final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
+ mVisibilityController,
+ RESTORE_TIMEOUT,
+ mTouchInsetManager,
+ mFakeExecutor,
+ mHandler);
+
+ // Report multiple active sessions.
+ when(mSession.getActiveSessionCount()).thenReturn(2);
+
+ // Start session.
+ touchHandler.onSessionStart(mSession);
+
+ // Verify session end.
+ verify(mSession).pop();
+
+ // Verify no interaction with visibility controller.
+ verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ }
+
+ /**
+ * Ensures no actions are taken when there multiple sessions.
+ */
+ @Test
+ public void testSessionEndWithTouchInInset() {
+ final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
+ mVisibilityController,
+ RESTORE_TIMEOUT,
+ mTouchInsetManager,
+ mFakeExecutor,
+ mHandler);
+
+ // Report one session
+ when(mSession.getActiveSessionCount()).thenReturn(1);
+
+ // Start session
+ touchHandler.onSessionStart(mSession);
+
+ // Capture input listener
+ final ArgumentCaptor<InputChannelCompat.InputEventListener> inputEventListenerCaptor =
+ ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
+ verify(mSession).registerInputListener(inputEventListenerCaptor.capture());
+
+ // Report touch within the inset
+ when(mTouchInsetManager.checkWithinTouchRegion(anyInt(), anyInt())).thenReturn(
+ CallbackToFutureAdapter.getFuture(completer -> {
+ completer.set(true);
+ return "testSessionEndWithTouchInInset";
+ })
+ );
+
+ inputEventListenerCaptor.getValue().onInputEvent(mMotionEvent);
+ mFakeExecutor.runAllReady();
+
+ // Verify session ended.
+ verify(mSession).pop();
+
+ // Verify no interaction with visibility controller.
+ verify(mVisibilityController, never()).setVisibility(anyInt(), anyBoolean());
+ }
+
+ /**
+ * Make sure visibility changes are triggered from session events.
+ */
+ @Test
+ public void testSessionLifecycle() {
+ final HideComplicationTouchHandler touchHandler = new HideComplicationTouchHandler(
+ mVisibilityController,
+ RESTORE_TIMEOUT,
+ mTouchInsetManager,
+ mFakeExecutor,
+ mHandler);
+
+ // Report one session
+ when(mSession.getActiveSessionCount()).thenReturn(1);
+
+ // Start session
+ touchHandler.onSessionStart(mSession);
+
+ // Capture input listener
+ final ArgumentCaptor<InputChannelCompat.InputEventListener> inputEventListenerCaptor =
+ ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
+ verify(mSession).registerInputListener(inputEventListenerCaptor.capture());
+
+ // Report touch outside the inset
+ when(mTouchInsetManager.checkWithinTouchRegion(anyInt(), anyInt())).thenReturn(
+ CallbackToFutureAdapter.getFuture(completer -> {
+ completer.set(false);
+ return "testSessionEndWithTouchInInset";
+ })
+ );
+
+ // Send down event.
+ when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN);
+ inputEventListenerCaptor.getValue().onInputEvent(mMotionEvent);
+ mFakeExecutor.runAllReady();
+
+ // Verify callback to restore visibility cancelled.
+ verify(mHandler).removeCallbacks(any());
+
+ // Verify visibility controller told to hide complications.
+ verify(mVisibilityController).setVisibility(eq(View.INVISIBLE), anyBoolean());
+
+ Mockito.clearInvocations(mVisibilityController, mHandler);
+
+ // Send up event.
+ when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_UP);
+ inputEventListenerCaptor.getValue().onInputEvent(mMotionEvent);
+ mFakeExecutor.runAllReady();
+
+ // Verify visibility controller told to show complications.
+ ArgumentCaptor<Runnable> delayRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mHandler).postDelayed(delayRunnableCaptor.capture(),
+ eq(Long.valueOf(RESTORE_TIMEOUT)));
+ delayRunnableCaptor.getValue().run();
+ verify(mVisibilityController).setVisibility(eq(View.VISIBLE), anyBoolean());
+
+ // Verify session ended.
+ verify(mSession).pop();
+ }
+}