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

Commit ceb129e9 authored by Brad Hinegardner's avatar Brad Hinegardner Committed by Android (Google) Code Review
Browse files

Merge "Skip falsing on non-touchscreen device sources" into main

parents 11721d01 e1c367eb
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1396,3 +1396,9 @@ flag {
    }
}

flag {
   name: "non_touchscreen_devices_bypass_falsing"
   namespace: "systemui"
   description: "Allow non-touchscreen devices to bypass falsing"
   bug: "319809270"
}
 No newline at end of file
+8 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
        when(mFalsingDataProvider.getRecentMotionEvents()).thenReturn(mMotionEventList);
        when(mKeyguardStateController.isShowing()).thenReturn(true);
        when(mFalsingDataProvider.isUnfolded()).thenReturn(false);
        when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(true);
        mBrightLineFalsingManager = new BrightLineFalsingManager(mFalsingDataProvider,
                mMetricsLogger, mClassifiers, mSingleTapClassifier, mLongTapClassifier,
                mDoubleTapClassifier, mHistoryTracker, mKeyguardStateController,
@@ -192,6 +193,13 @@ public class BrightLineFalsingManagerTest extends SysuiTestCase {
        assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
    }

    @Test
    public void testSkipNonTouchscreenDevices() {
        assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
        when(mFalsingDataProvider.isTouchScreenSource()).thenReturn(false);
        assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isFalse();
    }

    @Test
    public void testTrackpadGesture() {
        assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
+88 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.classifier;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -25,13 +26,20 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.hardware.devicestate.DeviceStateManager.FoldStateListener;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManagerGlobal;
import android.os.RemoteException;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.util.DisplayMetrics;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.systemui.Flags;
import com.android.systemui.classifier.FalsingDataProvider.GestureFinalizedListener;
import com.android.systemui.dock.DockManagerFake;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -56,11 +64,15 @@ public class FalsingDataProviderTest extends ClassifierTest {
    private FoldStateListener mFoldStateListener;
    private final DockManagerFake mDockManager = new DockManagerFake();
    private DisplayMetrics mDisplayMetrics;
    private IInputManager mIInputManager;
    private InputManagerGlobal.TestSession inputManagerGlobalTestSession;

    @Before
    public void setup() {
        super.setup();
        MockitoAnnotations.initMocks(this);
        mIInputManager = mock(IInputManager.Stub.class);
        inputManagerGlobalTestSession = InputManagerGlobal.createTestSession(mIInputManager);
        mDisplayMetrics = new DisplayMetrics();
        mDisplayMetrics.xdpi = 100;
        mDisplayMetrics.ydpi = 100;
@@ -73,6 +85,7 @@ public class FalsingDataProviderTest extends ClassifierTest {
    public void tearDown() {
        super.tearDown();
        mDataProvider.onSessionEnd();
        inputManagerGlobalTestSession.close();
    }

    @Test
@@ -377,6 +390,79 @@ public class FalsingDataProviderTest extends ClassifierTest {
        assertThat(mDataProvider.isA11yAction()).isTrue();
    }

    @Test
    @DisableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
    public void test_isTouchscreenSource_flagOff_alwaysTrue() {
        assertThat(mDataProvider.isTouchScreenSource()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
    public void test_isTouchscreenSource_recentEventsEmpty_true() {
        //send no events into the data provider
        assertThat(mDataProvider.isTouchScreenSource()).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
    public void test_isTouchscreenSource_latestDeviceTouchscreen_true() throws RemoteException {
        int deviceId = 999;

        InputDevice device = new InputDevice.Builder()
                .setSources(InputDevice.SOURCE_CLASS_TRACKBALL | InputDevice.SOURCE_TOUCHSCREEN)
                .setId(deviceId)
                .build();
        when(mIInputManager.getInputDeviceIds()).thenReturn(new int[]{deviceId});
        when(mIInputManager.getInputDevice(anyInt())).thenReturn(device);

        MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
                MotionEvent.PointerProperties.createArray(1),
                MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, deviceId, 0,
                InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);

        mDataProvider.onMotionEvent(event);
        boolean result = mDataProvider.isTouchScreenSource();
        assertThat(result).isTrue();
    }

    @Test
    @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
    public void test_isTouchscreenSource_latestDeviceNonTouchscreen_false() throws RemoteException {
        int deviceId = 9999;

        InputDevice device = new InputDevice.Builder()
                .setSources(InputDevice.SOURCE_CLASS_TRACKBALL)
                .setId(deviceId)
                .build();
        when(mIInputManager.getInputDeviceIds()).thenReturn(new int[]{deviceId});
        when(mIInputManager.getInputDevice(anyInt())).thenReturn(device);

        MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
                MotionEvent.PointerProperties.createArray(1),
                MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, deviceId, 0,
                InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);

        mDataProvider.onMotionEvent(event);
        boolean result = mDataProvider.isTouchScreenSource();
        assertThat(result).isFalse();
    }

    @Test
    @EnableFlags(Flags.FLAG_NON_TOUCHSCREEN_DEVICES_BYPASS_FALSING)
    public void test_isTouchscreenSource_latestDeviceNull_true() {
        // Do not mock InputManager for this test
        inputManagerGlobalTestSession.close();

        int nonExistentDeviceId = 9997;
        MotionEvent event = MotionEvent.obtain(1, 0, MotionEvent.ACTION_UP, 1,
                MotionEvent.PointerProperties.createArray(1),
                MotionEvent.PointerCoords.createArray(1), 0, 0, 1.0f, 1.0f, nonExistentDeviceId, 0,
                InputDevice.SOURCE_CLASS_NONE, 0, 0, 0);

        mDataProvider.onMotionEvent(event);
        assertThat(mDataProvider.isTouchScreenSource()).isTrue();
    }

    @Test
    public void test_UnfoldedState_Folded() {
        FalsingDataProvider falsingDataProvider = createWithFoldCapability(true);
@@ -413,7 +499,7 @@ public class FalsingDataProviderTest extends ClassifierTest {
    }

    private FalsingDataProvider createWithFoldCapability(boolean foldable) {
        return new FalsingDataProvider(
                mDisplayMetrics, mBatteryController, mFoldStateListener, mDockManager, foldable);
        return new FalsingDataProvider(mDisplayMetrics, mBatteryController, mFoldStateListener,
                mDockManager, foldable);
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -34,8 +34,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.systemui.classifier.FalsingDataProvider.SessionListener;
import com.android.systemui.classifier.HistoryTracker.BeliefListener;
import com.android.systemui.dagger.qualifiers.TestHarness;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;

@@ -396,6 +394,7 @@ public class BrightLineFalsingManager implements FalsingManager {
                || mDataProvider.isA11yAction()
                || mDataProvider.isFromTrackpad()
                || mDataProvider.isFromKeyboard()
                || !mDataProvider.isTouchScreenSource()
                || mDataProvider.isUnfolded();
    }

+21 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.systemui.dock.DockManager.DockEventListener;
import android.hardware.SensorManager;
import android.hardware.biometrics.BiometricSourceType;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;

@@ -28,6 +29,7 @@ import androidx.annotation.VisibleForTesting;

import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.Flags;
import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -343,7 +345,9 @@ class FalsingCollectorImpl implements FalsingCollector {
        // will be ignored by the collector until another MotionEvent.ACTION_DOWN is passed in.
        // avoidGesture must be called immediately following the MotionEvent.ACTION_DOWN, before
        // any other events are processed, otherwise the whole gesture will be recorded.
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
        //
        // We should only delay processing of these events for touchscreen sources
        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN && isTouchscreenSource(ev)) {
            // Make a copy of ev, since it will be recycled after we exit this method.
            mPendingDownEvent = MotionEvent.obtain(ev);
            mAvoidGesture = false;
@@ -410,6 +414,22 @@ class FalsingCollectorImpl implements FalsingCollector {
        mFalsingDataProvider.onA11yAction();
    }

    /**
     * returns {@code true} if the device supports Touchscreen, {@code false} otherwise. Defaults to
     * {@code true} if the device is {@code null}
     */
    private boolean isTouchscreenSource(MotionEvent ev) {
        if (!Flags.nonTouchscreenDevicesBypassFalsing()) {
            return true;
        }
        InputDevice device = ev.getDevice();
        if (device != null) {
            return device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN);
        } else {
            return true;
        }
    }

    private boolean shouldSessionBeActive() {
        return mScreenOn
                && (mState == StatusBarState.KEYGUARD)
Loading