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

Commit f5d210eb authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Refactor BrightLineClassifier tests to use significantly less memory.

Stop relying so heavily on mockito when it's not necessary. This also
makes tests run significantly faster. Memory usage is now basically flat.

Bug: 135715570
Test: atest SystemUITests
Change-Id: Ifd71e092b19068817600631b5b98a4a8e80a0126
parent cc28d7b6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -96,7 +96,7 @@ public class FalsingManagerProxy implements FalsingManager {
            mInternalFalsingManager = new FalsingManagerImpl(context);
        } else {
            mInternalFalsingManager = new BrightLineFalsingManager(
                    new FalsingDataProvider(context),
                    new FalsingDataProvider(context.getResources().getDisplayMetrics()),
                    Dependency.get(AsyncSensorManager.class)
            );
        }
+22 −5
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.classifier.brightline;

import android.content.Context;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
@@ -51,8 +50,7 @@ public class FalsingDataProvider {
    private MotionEvent mFirstRecentMotionEvent;
    private MotionEvent mLastMotionEvent;

    public FalsingDataProvider(Context context) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    public FalsingDataProvider(DisplayMetrics displayMetrics) {
        mXdpi = displayMetrics.xdpi;
        mYdpi = displayMetrics.ydpi;
        mWidthPixels = displayMetrics.widthPixels;
@@ -145,12 +143,20 @@ public class FalsingDataProvider {

    boolean isHorizontal() {
        recalculateData();
        if (mRecentMotionEvents.isEmpty()) {
            return false;
        }

        return Math.abs(mFirstRecentMotionEvent.getX() - mLastMotionEvent.getX()) > Math
                .abs(mFirstRecentMotionEvent.getY() - mLastMotionEvent.getY());
    }

    boolean isRight() {
        recalculateData();
        if (mRecentMotionEvents.isEmpty()) {
            return false;
        }

        return mLastMotionEvent.getX() > mFirstRecentMotionEvent.getX();
    }

@@ -160,6 +166,10 @@ public class FalsingDataProvider {

    boolean isUp() {
        recalculateData();
        if (mRecentMotionEvents.isEmpty()) {
            return false;
        }

        return mLastMotionEvent.getY() < mFirstRecentMotionEvent.getY();
    }

@@ -168,8 +178,13 @@ public class FalsingDataProvider {
            return;
        }

        if (mRecentMotionEvents.isEmpty()) {
            mFirstRecentMotionEvent = null;
            mLastMotionEvent = null;
        } else {
            mFirstRecentMotionEvent = mRecentMotionEvents.get(0);
            mLastMotionEvent = mRecentMotionEvents.get(mRecentMotionEvents.size() - 1);
        }

        calculateAngleInternal();

@@ -245,5 +260,7 @@ public class FalsingDataProvider {
        }

        mRecentMotionEvents.clear();

        mDirty = true;
    }
}
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.classifier.brightline;

import android.util.DisplayMetrics;
import android.view.MotionEvent;

import com.android.systemui.SysuiTestCase;

import org.junit.After;
import org.junit.Before;

import java.util.ArrayList;
import java.util.List;

public class ClassifierTest extends SysuiTestCase {

    private FalsingDataProvider mDataProvider;
    private List<MotionEvent> mMotionEvents = new ArrayList<>();
    private float mOffsetX = 0;
    private float mOffsetY = 0;

    @Before
    public void setup() {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        displayMetrics.xdpi = 100;
        displayMetrics.ydpi = 100;
        displayMetrics.widthPixels = 1000;
        displayMetrics.heightPixels = 1000;
        mDataProvider = new FalsingDataProvider(displayMetrics);
    }

    @After
    public void tearDown() {
        resetDataProvider();
    }

    FalsingDataProvider getDataProvider() {
        return mDataProvider;
    }

    void setOffsetX(float offsetX) {
        mOffsetX = offsetX;
    }

    void setOffsetY(float offsetY) {
        mOffsetY = offsetY;
    }

    void resetDataProvider() {
        for (MotionEvent motionEvent : mMotionEvents) {
            motionEvent.recycle();
        }

        mMotionEvents.clear();

        mDataProvider.onSessionEnd();
    }

    MotionEvent appendDownEvent(float x, float y) {
        return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y);
    }

    MotionEvent appendDownEvent(float x, float y, long eventTime) {
        return appendMotionEvent(MotionEvent.ACTION_DOWN, x, y, eventTime);
    }

    MotionEvent appendMoveEvent(float x, float y) {
        return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y);
    }

    MotionEvent appendMoveEvent(float x, float y, long eventTime) {
        return appendMotionEvent(MotionEvent.ACTION_MOVE, x, y, eventTime);
    }


    MotionEvent appendUpEvent(float x, float y) {
        return appendMotionEvent(MotionEvent.ACTION_UP, x, y);
    }

    MotionEvent appendUpEvent(float x, float y, long eventTime) {
        return appendMotionEvent(MotionEvent.ACTION_UP, x, y, eventTime);
    }

    private MotionEvent appendMotionEvent(int actionType, float x, float y) {

        long eventTime = mMotionEvents.isEmpty() ? 1 : mMotionEvents.get(
                mMotionEvents.size() - 1).getEventTime() + 1;
        return appendMotionEvent(actionType, x, y, eventTime);
    }

    private MotionEvent appendMotionEvent(int actionType, float x, float y, long eventTime) {
        x += mOffsetX;
        y += mOffsetY;

        MotionEvent motionEvent = MotionEvent.obtain(1, eventTime, actionType, x, y,
                0);
        mMotionEvents.add(motionEvent);

        mDataProvider.onMotionEvent(motionEvent);

        return motionEvent;
    }
}
+8 −14
Original line number Diff line number Diff line
@@ -28,10 +28,8 @@ import android.testing.TestableLooper;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -40,7 +38,7 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class DiagonalClassifierTest extends SysuiTestCase {
public class DiagonalClassifierTest extends ClassifierTest {

    // Next variable is not actually five, but is very close. 5 degrees is currently the value
    // used in the diagonal classifier, so we want slightly less than that to deal with
@@ -57,21 +55,24 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    private FalsingClassifier mClassifier;

    @Before
    @Ignore("Memory Leak?")
    public void setup() {
        super.setup();
        MockitoAnnotations.initMocks(this);
        mClassifier = new DiagonalClassifier(mDataProvider);
    }

    @After
    public void tearDown() {
        super.tearDown();
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_UnknownAngle() {
        when(mDataProvider.getAngle()).thenReturn(Float.MAX_VALUE);
        assertThat(mClassifier.isFalseTouch(), is(false));
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_VerticalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS);
        assertThat(mClassifier.isFalseTouch(), is(false));
@@ -81,7 +82,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_MostlyVerticalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(UP_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
        assertThat(mClassifier.isFalseTouch(), is(false));
@@ -97,7 +97,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_BarelyVerticalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(
                UP_IN_RADIANS - FORTY_FIVE_DEG_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
@@ -117,7 +116,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_HorizontalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS);
        assertThat(mClassifier.isFalseTouch(), is(false));
@@ -127,7 +125,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_MostlyHorizontalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(RIGHT_IN_RADIANS + 2 * FIVE_DEG_IN_RADIANS);
        assertThat(mClassifier.isFalseTouch(), is(false));
@@ -143,7 +140,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_BarelyHorizontalSwipe() {
        when(mDataProvider.getAngle()).thenReturn(
                RIGHT_IN_RADIANS + FORTY_FIVE_DEG_IN_RADIANS - 2 * FIVE_DEG_IN_RADIANS);
@@ -163,7 +159,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_AffordanceSwipe() {
        when(mDataProvider.getInteractionType()).thenReturn(LEFT_AFFORDANCE);
        when(mDataProvider.getAngle()).thenReturn(
@@ -182,7 +177,6 @@ public class DiagonalClassifierTest extends SysuiTestCase {
    }

    @Test
    @Ignore("Memory Leak?")
    public void testFail_DiagonalSwipe() {
        // Horizontal Swipes
        when(mDataProvider.isVertical()).thenReturn(false);
+25 −92
Original line number Diff line number Diff line
@@ -18,159 +18,92 @@ package com.android.systemui.classifier.brightline;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.MotionEvent;

import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.List;

@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class DistanceClassifierTest extends SysuiTestCase {
public class DistanceClassifierTest extends ClassifierTest {

    @Mock
    private FalsingDataProvider mDataProvider;
    private FalsingClassifier mClassifier;
    private List<MotionEvent> mMotionEvents = new ArrayList<>();

    private static final float DPI = 100;
    private static final int SCREEN_SIZE = (int) (DPI * 10);

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        when(mDataProvider.getHeightPixels()).thenReturn(SCREEN_SIZE);
        when(mDataProvider.getWidthPixels()).thenReturn(SCREEN_SIZE);
        when(mDataProvider.getXdpi()).thenReturn(DPI);
        when(mDataProvider.getYdpi()).thenReturn(DPI);
        super.setup();
        mDataProvider = getDataProvider();
        mClassifier = new DistanceClassifier(mDataProvider);
    }

    @After
    public void tearDown() {
        super.tearDown();
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_noPointer() {
        assertThat(mClassifier.isFalseTouch(), is(true));
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_fling() {
        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 2, 0);
        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_UP, 1, 40, 0);

        appendMotionEvent(motionEventA);
        mClassifier.onTouchEvent(appendDownEvent(1, 1));
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventB);
        mClassifier.onTouchEvent(appendMoveEvent(1, 2));
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventC);
        mClassifier.onTouchEvent(appendUpEvent(1, 40));
        assertThat(mClassifier.isFalseTouch(), is(false));

        motionEventA.recycle();
        motionEventB.recycle();
        motionEventC.recycle();
    }

    @Test
    @Ignore("Memory Leak?")
    public void testFail_flingShort() {
        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 2, 0);
        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_UP, 1, 10, 0);

        appendMotionEvent(motionEventA);
        mClassifier.onTouchEvent(appendDownEvent(1, 1));
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventB);
        mClassifier.onTouchEvent(appendMoveEvent(1, 2));
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventC);
        mClassifier.onTouchEvent(appendUpEvent(1, 10));
        assertThat(mClassifier.isFalseTouch(), is(true));

        motionEventA.recycle();
        motionEventB.recycle();
        motionEventC.recycle();
    }

    @Test
    @Ignore("Memory Leak?")
    public void testFail_flingSlowly() {
        // These events, in testing, result in a fling that falls just short of the threshold.
        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
        MotionEvent motionEventB = MotionEvent.obtain(1, 2, MotionEvent.ACTION_MOVE, 1, 15, 0);
        MotionEvent motionEventC = MotionEvent.obtain(1, 3, MotionEvent.ACTION_MOVE, 1, 16, 0);
        MotionEvent motionEventD = MotionEvent.obtain(1, 300, MotionEvent.ACTION_MOVE, 1, 17, 0);
        MotionEvent motionEventE = MotionEvent.obtain(1, 301, MotionEvent.ACTION_MOVE, 1, 18, 0);
        MotionEvent motionEventF = MotionEvent.obtain(1, 500, MotionEvent.ACTION_UP, 1, 19, 0);

        appendMotionEvent(motionEventA);
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventB);
        mClassifier.onTouchEvent(appendDownEvent(1, 1, 1));
        assertThat(mClassifier.isFalseTouch(), is(true));

        appendMotionEvent(motionEventC);
        appendMotionEvent(motionEventD);
        appendMotionEvent(motionEventE);
        appendMotionEvent(motionEventF);
        mClassifier.onTouchEvent(appendMoveEvent(1, 15, 2));
        assertThat(mClassifier.isFalseTouch(), is(true));

        motionEventA.recycle();
        motionEventB.recycle();
        motionEventC.recycle();
        motionEventD.recycle();
        motionEventE.recycle();
        motionEventF.recycle();
        mClassifier.onTouchEvent(appendMoveEvent(1, 16, 3));
        mClassifier.onTouchEvent(appendMoveEvent(1, 17, 300));
        mClassifier.onTouchEvent(appendMoveEvent(1, 18, 301));
        mClassifier.onTouchEvent(appendUpEvent(1, 19, 501));
        assertThat(mClassifier.isFalseTouch(), is(true));
    }

    @Test
    @Ignore("Memory Leak?")
    public void testPass_swipe() {
        MotionEvent motionEventA = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 1, 1, 0);
        MotionEvent motionEventB = MotionEvent.obtain(1, 3, MotionEvent.ACTION_MOVE, 1, DPI * 3, 0);
        MotionEvent motionEventC = MotionEvent.obtain(1, 1000, MotionEvent.ACTION_UP, 1, DPI * 3,
                0);

        appendMotionEvent(motionEventA);
        mClassifier.onTouchEvent(appendDownEvent(1, 1));
        assertThat(mClassifier.isFalseTouch(), is(true));


        appendMotionEvent(motionEventB);
        appendMotionEvent(motionEventC);
        mClassifier.onTouchEvent(appendMoveEvent(1, mDataProvider.getYdpi() * 3, 3));
        mClassifier.onTouchEvent(appendUpEvent(1, mDataProvider.getYdpi() * 3, 300));
        assertThat(mClassifier.isFalseTouch(), is(false));

        motionEventA.recycle();
        motionEventB.recycle();
        motionEventC.recycle();
    }

    private void appendMotionEvent(MotionEvent motionEvent) {
        if (mMotionEvents.isEmpty()) {
            when(mDataProvider.getFirstRecentMotionEvent()).thenReturn(motionEvent);
        }

        mMotionEvents.add(motionEvent);
        when(mDataProvider.getRecentMotionEvents()).thenReturn(mMotionEvents);

        when(mDataProvider.getLastMotionEvent()).thenReturn(motionEvent);

        mClassifier.onTouchEvent(motionEvent);
    }
}
Loading