Merge "Fix NPE of handling ACTION_MOVE in StatusBarTouchController and added unit test" into udc-dev

This commit is contained in:
Fengjiang Li
2023-06-06 18:19:38 +00:00
committed by Android (Google) Code Review
2 changed files with 164 additions and 9 deletions

View File

@@ -30,6 +30,8 @@ import android.view.ViewConfiguration;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -50,12 +52,13 @@ public class StatusBarTouchController implements TouchController {
private final Launcher mLauncher;
private final SystemUiProxy mSystemUiProxy;
private final float mTouchSlop;
@VisibleForTesting final float mTouchSlop;
private int mLastAction;
private final SparseArray<PointF> mDownEvents;
/* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/
private boolean mCanIntercept;
@VisibleForTesting
boolean mCanIntercept;
public StatusBarTouchController(Launcher l) {
mLauncher = l;
@@ -82,9 +85,9 @@ public class StatusBarTouchController implements TouchController {
@Override
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
int action = ev.getActionMasked();
int idx = ev.getActionIndex();
int pid = ev.getPointerId(idx);
final int action = ev.getActionMasked();
final int idx = ev.getActionIndex();
final int pid = ev.getPointerId(idx);
if (action == ACTION_DOWN) {
mCanIntercept = canInterceptTouch(ev);
if (!mCanIntercept) {
@@ -92,14 +95,14 @@ public class StatusBarTouchController implements TouchController {
}
mDownEvents.clear();
mDownEvents.put(pid, new PointF(ev.getX(), ev.getY()));
} else if (ev.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
} else if (action == MotionEvent.ACTION_POINTER_DOWN) {
// Check!! should only set it only when threshold is not entered.
mDownEvents.put(pid, new PointF(ev.getX(idx), ev.getY(idx)));
}
if (!mCanIntercept) {
return false;
}
if (action == ACTION_MOVE) {
if (action == ACTION_MOVE && mDownEvents.contains(pid)) {
float dy = ev.getY(idx) - mDownEvents.get(pid).y;
float dx = ev.getX(idx) - mDownEvents.get(pid).x;
// Currently input dispatcher will not do touch transfer if there are more than
@@ -126,7 +129,6 @@ public class StatusBarTouchController implements TouchController {
mLauncher.getStatsLogManager().logger()
.log(LAUNCHER_SWIPE_DOWN_WORKSPACE_NOTISHADE_OPEN);
setWindowSlippery(false);
return true;
}
return true;
}
@@ -140,7 +142,8 @@ public class StatusBarTouchController implements TouchController {
* Touches can slide out of the window but they cannot necessarily slide
* back in (unless the other window with touch focus permits it).
*/
private void setWindowSlippery(boolean enable) {
@VisibleForTesting
void setWindowSlippery(boolean enable) {
Window w = mLauncher.getWindow();
WindowManager.LayoutParams wlp = w.getAttributes();
if (enable) {

View File

@@ -0,0 +1,152 @@
/*
* Copyright (C) 202 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.launcher3.uioverrides.touchcontrollers
import android.view.MotionEvent
import android.view.WindowManager
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.launcher3.Launcher
import com.android.launcher3.ui.AbstractLauncherUiTest
import com.android.launcher3.ui.TaplTestsLauncher3
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class StatusBarTouchControllerTest : AbstractLauncherUiTest() {
@Before
@Throws(Exception::class)
fun setup() {
TaplTestsLauncher3.initialize(this)
}
@Test
fun interceptActionDown_canIntercept() {
executeOnLauncher { launcher: Launcher? ->
val underTest = StatusBarTouchController(launcher)
assertFalse(underTest.mCanIntercept)
val downEvent = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
underTest.onControllerInterceptTouchEvent(downEvent)
assertTrue(underTest.mCanIntercept)
}
}
@Test
fun interceptActionMove_handledAndSetSlippery() {
executeOnLauncher { launcher: Launcher ->
val underTest = StatusBarTouchController(launcher)
val downEvent = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
underTest.onControllerInterceptTouchEvent(downEvent)
val w = launcher.window
assertEquals(0, w.attributes.flags and WindowManager.LayoutParams.FLAG_SLIPPERY)
val moveEvent =
MotionEvent.obtain(
2,
2,
MotionEvent.ACTION_MOVE,
underTest.mTouchSlop,
underTest.mTouchSlop + 10,
0
)
val handled = underTest.onControllerInterceptTouchEvent(moveEvent)
assertTrue(handled)
assertEquals(
WindowManager.LayoutParams.FLAG_SLIPPERY,
w.attributes.flags and WindowManager.LayoutParams.FLAG_SLIPPERY
)
}
}
@Test
fun interceptActionMove_not_handled() {
executeOnLauncher { launcher: Launcher? ->
val underTest = StatusBarTouchController(launcher)
val downEvent = MotionEvent.obtain(1, 1, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
underTest.onControllerInterceptTouchEvent(downEvent)
val moveEvent =
MotionEvent.obtain(
2,
2,
MotionEvent.ACTION_MOVE,
underTest.mTouchSlop + 10,
underTest.mTouchSlop,
0
)
val handled = underTest.onControllerInterceptTouchEvent(moveEvent)
assertFalse(handled)
}
}
@Test
fun interceptActionMoveAsFirstGestureEvent_notCrashedNorHandled() {
executeOnLauncher { launcher: Launcher? ->
val underTest = StatusBarTouchController(launcher)
underTest.mCanIntercept = true
val moveEvent = MotionEvent.obtain(2, 2, MotionEvent.ACTION_MOVE, 10f, 10f, 0)
val handled = underTest.onControllerInterceptTouchEvent(moveEvent)
assertFalse(handled)
}
}
@Test
fun handleActionUp_setNotSlippery() {
executeOnLauncher { launcher: Launcher ->
val underTest = StatusBarTouchController(launcher)
underTest.mCanIntercept = true
underTest.setWindowSlippery(true)
val moveEvent = MotionEvent.obtain(2, 2, MotionEvent.ACTION_UP, 10f, 10f, 0)
val handled = underTest.onControllerTouchEvent(moveEvent)
assertTrue(handled)
assertEquals(
0,
launcher.window.attributes.flags and WindowManager.LayoutParams.FLAG_SLIPPERY
)
}
}
@Test
fun handleActionCancel_setNotSlippery() {
executeOnLauncher { launcher: Launcher ->
val underTest = StatusBarTouchController(launcher)
underTest.mCanIntercept = true
underTest.setWindowSlippery(true)
val moveEvent = MotionEvent.obtain(2, 2, MotionEvent.ACTION_CANCEL, 10f, 10f, 0)
val handled = underTest.onControllerTouchEvent(moveEvent)
assertTrue(handled)
assertEquals(
0,
launcher.window.attributes.flags and WindowManager.LayoutParams.FLAG_SLIPPERY
)
}
}
}