Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ec65e25 authored by Bryce Lee's avatar Bryce Lee
Browse files

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
parent 2cdded15
Loading
Loading
Loading
Loading
+13 −12
Original line number Diff line number Diff line
@@ -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.Choreographer;
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 @@ public class InputSession {

    /**
     * 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.
+5 −3
Original line number Diff line number Diff line
@@ -24,16 +24,18 @@ import android.view.GestureDetector;
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}.
+50 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+140 −0
Original line number Diff line number Diff line
/*
 * 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();
    }
}