Refactor InputSession dependencies.

This changelist moves InputSession dependencies into a submodule of the
current InputSession component.

Bug: 333596426
Test: atest InputSessionTest
Flag: N/A
Change-Id: I2769b0ad21f9ed765380033b97ca9b88cb0702b6
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
index e1d0339..e72839f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/InputSession.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.dreams.touch;
 
-import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.INPUT_SESSION_NAME;
 import static com.android.systemui.dreams.touch.dagger.DreamTouchModule.PILFER_ON_GESTURE_CONSUME;
 
 import android.os.Looper;
@@ -24,7 +23,7 @@
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 
-import com.android.systemui.settings.DisplayTracker;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.shared.system.InputChannelCompat;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
@@ -44,24 +43,26 @@
 
     /**
      * Default session constructor.
-     * @param sessionName The session name that will be applied to the underlying
-     * {@link InputMonitorCompat}.
+     * @param inputMonitor Input monitor to track input events.
+     * @param gestureDetector Gesture detector for detecting gestures.
      * @param inputEventListener A listener to receive input events.
-     * @param gestureListener A listener to receive gesture events.
+     * @param choreographer Choreographer to use with the input receiver.
+     * @param looper Looper to use with the input receiver
      * @param pilferOnGestureConsume Whether touch events should be pilfered after a gesture has
      *                               been consumed.
      */
     @Inject
-    public InputSession(@Named(INPUT_SESSION_NAME) String sessionName,
+    public InputSession(
+            InputMonitorCompat inputMonitor,
+            GestureDetector gestureDetector,
             InputChannelCompat.InputEventListener inputEventListener,
-            GestureDetector.OnGestureListener gestureListener,
-            DisplayTracker displayTracker,
+            Choreographer choreographer,
+            @Main Looper looper,
             @Named(PILFER_ON_GESTURE_CONSUME) boolean pilferOnGestureConsume) {
-        mInputMonitor = new InputMonitorCompat(sessionName, displayTracker.getDefaultDisplayId());
-        mGestureDetector = new GestureDetector(gestureListener);
+        mInputMonitor = inputMonitor;
+        mGestureDetector = gestureDetector;
 
-        mInputEventReceiver = mInputMonitor.getInputReceiver(Looper.getMainLooper(),
-                Choreographer.getInstance(),
+        mInputEventReceiver = mInputMonitor.getInputReceiver(looper, choreographer,
                 ev -> {
                     // Process event. Since sometimes input may be a prerequisite for some
                     // gesture logic, process input first.
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java
index ad59a2e..0b14521 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionComponent.java
@@ -24,16 +24,18 @@
 import com.android.systemui.dreams.touch.InputSession;
 import com.android.systemui.shared.system.InputChannelCompat;
 
-import javax.inject.Named;
-
 import dagger.BindsInstance;
 import dagger.Subcomponent;
 
+import javax.inject.Named;
+
 /**
  * {@link InputSessionComponent} generates {@link InputSession} with specific instances bound for
  * the session name and whether touches should be pilfered when consumed.
  */
-@Subcomponent
+@Subcomponent(
+        modules = { InputSessionModule.class }
+)
 public interface InputSessionComponent {
     /**
      * Generates {@link InputSessionComponent}.
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java
new file mode 100644
index 0000000..dfab666
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/touch/dagger/InputSessionModule.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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 static com.android.systemui.dreams.touch.dagger.DreamTouchModule.INPUT_SESSION_NAME;
+
+import android.view.GestureDetector;
+
+import com.android.systemui.settings.DisplayTracker;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Named;
+
+
+/**
+ * Module for providing dependencies to {@link com.android.systemui.dreams.touch.InputSession}.
+ */
+@Module
+public interface InputSessionModule {
+    /** */
+    @Provides
+    static InputMonitorCompat providesInputMonitorCompat(@Named(INPUT_SESSION_NAME) String name,
+            DisplayTracker displayTracker) {
+        return new InputMonitorCompat(name, displayTracker.getDefaultDisplayId());
+    }
+
+    /** */
+    @Provides
+    static GestureDetector providesGestureDetector(
+            android.view.GestureDetector.OnGestureListener gestureListener) {
+        return new GestureDetector(gestureListener);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java
new file mode 100644
index 0000000..3180e75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/touch/InputSessionTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2024 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.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Choreographer;
+import android.view.GestureDetector;
+import android.view.InputEvent;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.shared.system.InputChannelCompat;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+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;
+
+/**
+ * A test suite for exercising {@link InputSession}.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper()
+public class InputSessionTest extends SysuiTestCase {
+    @Mock
+    InputMonitorCompat mInputMonitor;
+
+    @Mock
+    GestureDetector mGestureDetector;
+
+    @Mock
+    InputChannelCompat.InputEventListener mInputEventListener;
+
+    TestableLooper mLooper;
+
+    @Mock
+    Choreographer mChoreographer;
+
+    @Mock
+    InputChannelCompat.InputEventReceiver mInputEventReceiver;
+
+    InputSession mSession;
+
+    InputChannelCompat.InputEventListener mEventListener;
+
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mLooper = TestableLooper.get(this);
+    }
+
+    private void createSession(boolean pilfer) {
+        when(mInputMonitor.getInputReceiver(any(), any(), any()))
+                .thenReturn(mInputEventReceiver);
+        mSession = new InputSession(mInputMonitor, mGestureDetector,
+                mInputEventListener, mChoreographer, mLooper.getLooper(), pilfer);
+        final ArgumentCaptor<InputChannelCompat.InputEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class);
+        verify(mInputMonitor).getInputReceiver(any(), any(), listenerCaptor.capture());
+        mEventListener = listenerCaptor.getValue();
+    }
+
+    /**
+     * Ensures consumed motion events are pilfered when option is set.
+     */
+    @Test
+    public void testPilferOnMotionEventGestureConsume() {
+        createSession(true);
+        final MotionEvent event = Mockito.mock(MotionEvent.class);
+        when(mGestureDetector.onTouchEvent(event)).thenReturn(true);
+        mEventListener.onInputEvent(event);
+        verify(mInputEventListener).onInputEvent(eq(event));
+        verify(mInputMonitor).pilferPointers();
+    }
+
+    /**
+     * Ensures consumed motion events are not pilfered when option is not set.
+     */
+    @Test
+    public void testNoPilferOnMotionEventGestureConsume() {
+        createSession(false);
+        final MotionEvent event = Mockito.mock(MotionEvent.class);
+        when(mGestureDetector.onTouchEvent(event)).thenReturn(true);
+        mEventListener.onInputEvent(event);
+        verify(mInputEventListener).onInputEvent(eq(event));
+        verify(mInputMonitor, never()).pilferPointers();
+    }
+
+    /**
+     * Ensures input events are never pilfered.
+     */
+    @Test
+    public void testNoPilferOnInputEvent() {
+        createSession(true);
+        final InputEvent event = Mockito.mock(InputEvent.class);
+        mEventListener.onInputEvent(event);
+        verify(mInputEventListener).onInputEvent(eq(event));
+        verify(mInputMonitor, never()).pilferPointers();
+    }
+
+    /**
+     * Ensures components are properly disposed.
+     */
+    @Test
+    public void testDispose() {
+        createSession(true);
+        mSession.dispose();
+        verify(mInputMonitor).dispose();
+        verify(mInputEventReceiver).dispose();
+    }
+}