summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DoubleTapHelperTest.java369
2 files changed, 371 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java
index 0d62703cbced..78ea5c03a7b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DoubleTapHelper.java
@@ -100,6 +100,7 @@ public class DoubleTapHelper {
event.getY() - mActivationY);
}
if (withinDoubleTapSlop) {
+ makeInactive();
if (!mDoubleTapListener.onDoubleTap()) {
return false;
}
@@ -134,6 +135,7 @@ public class DoubleTapHelper {
if (mActivated) {
mActivated = false;
mActivationListener.onActiveChanged(false);
+ mView.removeCallbacks(mTapTimeoutRunnable);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DoubleTapHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DoubleTapHelperTest.java
new file mode 100644
index 000000000000..df1233af6406
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DoubleTapHelperTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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.statusbar.phone;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.os.SystemClock;
+import android.testing.AndroidTestingRunner;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class DoubleTapHelperTest extends SysuiTestCase {
+
+ private DoubleTapHelper mDoubleTapHelper;
+ private int mTouchSlop;
+ private int mDoubleTouchSlop;
+ @Mock private View mView;
+ @Mock private DoubleTapHelper.ActivationListener mActivationListener;
+ @Mock private DoubleTapHelper.DoubleTapListener mDoubleTapListener;
+ @Mock private DoubleTapHelper.SlideBackListener mSlideBackListener;
+ @Mock private DoubleTapHelper.DoubleTapLogListener mDoubleTapLogListener;
+ @Mock private Resources mResources;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
+ // The double tap slop has to be less than the regular slop, otherwise it has no effect.
+ mDoubleTouchSlop = mTouchSlop - 1;
+ when(mView.getContext()).thenReturn(mContext);
+ when(mView.getResources()).thenReturn(mResources);
+ when(mResources.getDimension(R.dimen.double_tap_slop))
+ .thenReturn((float) mDoubleTouchSlop);
+
+ mDoubleTapHelper = new DoubleTapHelper(mView,
+ mActivationListener,
+ mDoubleTapListener,
+ mSlideBackListener, mDoubleTapLogListener);
+ }
+
+ @Test
+ public void testDoubleTap_success() {
+ long downtimeA = SystemClock.uptimeMillis();
+ long downtimeB = downtimeA + 100;
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownB = MotionEvent.obtain(downtimeB,
+ downtimeB,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpB = MotionEvent.obtain(downtimeB,
+ downtimeB + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener).onActiveChanged(true);
+ verify(mView).postDelayed(any(Runnable.class), anyLong());
+ verify(mDoubleTapLogListener, never()).onDoubleTapLog(anyBoolean(), anyFloat(), anyFloat());
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ mDoubleTapHelper.onTouchEvent(evDownB);
+ mDoubleTapHelper.onTouchEvent(evUpB);
+ verify(mDoubleTapLogListener).onDoubleTapLog(true, 0, 0);
+ verify(mDoubleTapListener).onDoubleTap();
+
+ evDownA.recycle();
+ evUpA.recycle();
+ evDownB.recycle();
+ evUpB.recycle();
+ }
+
+ @Test
+ public void testSingleTap_timeout() {
+ long downtimeA = SystemClock.uptimeMillis();
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener).onActiveChanged(true);
+ verify(mView).postDelayed(runnableCaptor.capture(), anyLong());
+ runnableCaptor.getValue().run();
+ verify(mActivationListener).onActiveChanged(true);
+
+ evDownA.recycle();
+ evUpA.recycle();
+ }
+
+ @Test
+ public void testSingleTap_slop() {
+ long downtimeA = SystemClock.uptimeMillis();
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1 + mTouchSlop,
+ 1,
+ 0);
+
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener, never()).onActiveChanged(true);
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ evDownA.recycle();
+ evUpA.recycle();
+ }
+
+ @Test
+ public void testDoubleTap_slop() {
+ long downtimeA = SystemClock.uptimeMillis();
+ long downtimeB = downtimeA + 100;
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownB = MotionEvent.obtain(downtimeB,
+ downtimeB,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpB = MotionEvent.obtain(downtimeB,
+ downtimeB + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1 + mDoubleTouchSlop,
+ 0);
+
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener).onActiveChanged(true);
+ verify(mView).postDelayed(any(Runnable.class), anyLong());
+
+ mDoubleTapHelper.onTouchEvent(evDownB);
+ mDoubleTapHelper.onTouchEvent(evUpB);
+ verify(mDoubleTapLogListener).onDoubleTapLog(false, 0, mDoubleTouchSlop);
+ verify(mActivationListener).onActiveChanged(false);
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ evDownA.recycle();
+ evUpA.recycle();
+ evDownB.recycle();
+ evUpB.recycle();
+ }
+
+ @Test
+ public void testSlideBack() {
+ long downtimeA = SystemClock.uptimeMillis();
+ long downtimeB = downtimeA + 100;
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownB = MotionEvent.obtain(downtimeB,
+ downtimeB,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpB = MotionEvent.obtain(downtimeB,
+ downtimeB + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+
+ when(mSlideBackListener.onSlideBack()).thenReturn(true);
+
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener, never()).onActiveChanged(true);
+ verify(mActivationListener, never()).onActiveChanged(false);
+ verify(mDoubleTapListener, never()).onDoubleTap();
+ mDoubleTapHelper.onTouchEvent(evDownB);
+ mDoubleTapHelper.onTouchEvent(evUpB);
+ verify(mActivationListener, never()).onActiveChanged(true);
+ verify(mActivationListener, never()).onActiveChanged(false);
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ evDownA.recycle();
+ evUpA.recycle();
+ evDownB.recycle();
+ evUpB.recycle();
+ }
+
+
+ @Test
+ public void testMoreThanTwoTaps() {
+ long downtimeA = SystemClock.uptimeMillis();
+ long downtimeB = downtimeA + 100;
+ long downtimeC = downtimeB + 100;
+ long downtimeD = downtimeC + 100;
+
+ MotionEvent evDownA = MotionEvent.obtain(downtimeA,
+ downtimeA,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpA = MotionEvent.obtain(downtimeA,
+ downtimeA + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownB = MotionEvent.obtain(downtimeB,
+ downtimeB,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpB = MotionEvent.obtain(downtimeB,
+ downtimeB + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownC = MotionEvent.obtain(downtimeC,
+ downtimeC,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpC = MotionEvent.obtain(downtimeC,
+ downtimeC + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+ MotionEvent evDownD = MotionEvent.obtain(downtimeD,
+ downtimeD,
+ MotionEvent.ACTION_DOWN,
+ 1,
+ 1,
+ 0);
+ MotionEvent evUpD = MotionEvent.obtain(downtimeD,
+ downtimeD + 1,
+ MotionEvent.ACTION_UP,
+ 1,
+ 1,
+ 0);
+
+ mDoubleTapHelper.onTouchEvent(evDownA);
+ mDoubleTapHelper.onTouchEvent(evUpA);
+ verify(mActivationListener).onActiveChanged(true);
+ verify(mView).postDelayed(any(Runnable.class), anyLong());
+ verify(mDoubleTapLogListener, never()).onDoubleTapLog(anyBoolean(), anyFloat(), anyFloat());
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ mDoubleTapHelper.onTouchEvent(evDownB);
+ mDoubleTapHelper.onTouchEvent(evUpB);
+ verify(mDoubleTapLogListener).onDoubleTapLog(true, 0, 0);
+ verify(mDoubleTapListener).onDoubleTap();
+
+ reset(mView);
+ reset(mActivationListener);
+ reset(mDoubleTapLogListener);
+ reset(mDoubleTapListener);
+
+ mDoubleTapHelper.onTouchEvent(evDownC);
+ mDoubleTapHelper.onTouchEvent(evUpC);
+ verify(mActivationListener).onActiveChanged(true);
+ verify(mView).postDelayed(any(Runnable.class), anyLong());
+ verify(mDoubleTapLogListener, never()).onDoubleTapLog(anyBoolean(), anyFloat(), anyFloat());
+ verify(mDoubleTapListener, never()).onDoubleTap();
+
+ mDoubleTapHelper.onTouchEvent(evDownD);
+ mDoubleTapHelper.onTouchEvent(evUpD);
+ verify(mDoubleTapLogListener).onDoubleTapLog(true, 0, 0);
+ verify(mDoubleTapListener).onDoubleTap();
+
+ evDownA.recycle();
+ evUpA.recycle();
+ evDownB.recycle();
+ evUpB.recycle();
+ }
+}