Merge "TAPL: Verifying activity start/stop events" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index f79ad25..947a861 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -105,10 +105,6 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if ((ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL)
- && mCurrentAnimation == null) {
- clearState();
- }
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = !canInterceptTouch();
if (mNoIntercept) {
@@ -129,11 +125,6 @@
TaskView view = mRecentsView.getTaskViewAt(i);
if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
.isEventOverView(view, ev)) {
- // Disable swiping up and down if the task overlay is modal.
- if (view.isTaskOverlayModal()) {
- mTaskBeingDragged = null;
- break;
- }
mTaskBeingDragged = view;
if (!SysUINavigationMode.getMode(mActivity).hasGestures) {
// Don't allow swipe down to open if we don't support swipe up
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 34b2bdb..d4c746f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -3,8 +3,8 @@
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
-import android.util.Log;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
@@ -64,6 +64,12 @@
taskBaseIntentComponents);
return response;
}
+
+ case TestProtocol.REQUEST_OVERVIEW_ACTIONS_ENABLED: {
+ response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get());
+ return response;
+ }
}
return super.call(method);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
index eb3b190..ec7cddf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java
@@ -87,12 +87,5 @@
* Called when the overlay is no longer used.
*/
public void reset() { }
-
- /**
- * Whether the overlay is modal, which means only tapping is enabled, but no swiping.
- */
- public boolean isOverlayModal() {
- return false;
- }
}
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 007493d..e34e74c 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -565,13 +565,6 @@
return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
}
- @Override
- protected void determineScrollingStart(MotionEvent ev, float touchSlopScale) {
- // If the task overlay is modal, should disable left and right swiping.
- if (getCurrentPageTaskView() != null && !getCurrentPageTaskView().isTaskOverlayModal()) {
- super.determineScrollingStart(ev, touchSlopScale);
- }
- }
protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
return true;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 79b9a9d..dce92ff 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -251,10 +251,6 @@
}
}
- public boolean isTaskOverlayModal() {
- return mSnapshotView.getTaskOverlay().isOverlayModal();
- }
-
public TaskMenuView getMenuView() {
return mMenuView;
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 1229a63..cd94704 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -35,6 +35,7 @@
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.TestHelpers;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.systemui.shared.system.QuickStepContract;
@@ -199,7 +200,7 @@
+ launcher.getNavigationModeMismatchError(),
() -> launcher.getNavigationModeMismatchError() == null,
60000 /* b/148422894 */, launcher);
-
+ AbstractLauncherUiTest.checkDetectedLeaks();
return true;
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index ecfdb55..28ed588 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -81,6 +81,11 @@
@Test
public void testAllAppsFromOverview() throws Exception {
+ // When actions are enabled, all apps isn't present in overview
+ if (mLauncher.overviewActionsEnabled()) {
+ return;
+ }
+
// Test opening all apps from Overview.
assertNotNull("switchToAllApps() returned null",
mLauncher.getWorkspace().switchToOverview().switchToAllApps());
@@ -141,8 +146,8 @@
launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview",
numTasks - 1, getTaskCount(launcher)));
- if (!TestHelpers.isInLauncherProcess() ||
- getFromLauncher(launcher -> !launcher.getDeviceProfile().isLandscape)) {
+ if (!mLauncher.overviewActionsEnabled() && (!TestHelpers.isInLauncherProcess()
+ || getFromLauncher(launcher -> !launcher.getDeviceProfile().isLandscape))) {
// Test switching to all apps and back.
final AllAppsFromOverview allApps = overview.switchToAllApps();
assertNotNull("overview.switchToAllApps() returned null (1)", allApps);
@@ -185,6 +190,11 @@
@Test
public void testAppIconLaunchFromAllAppsFromOverview() throws Exception {
+ // All apps doesn't exist in Overview when actions are enabled
+ if (mLauncher.overviewActionsEnabled()) {
+ return;
+ }
+
final AllApps allApps =
mLauncher.getWorkspace().switchToOverview().switchToAllApps();
assertTrue("Launcher internal state is not All Apps",
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 1dbe195..114c491 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -56,6 +56,7 @@
private final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);
private final Alarm mCacheExpireAlarm;
+ private boolean mHadPendingAlarm;
protected int mCurrentAccessibilityAction = -1;
public SecondaryDropTarget(Context context, AttributeSet attrs) {
@@ -70,6 +71,24 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mHadPendingAlarm) {
+ mCacheExpireAlarm.setAlarm(CACHE_EXPIRE_TIMEOUT);
+ mHadPendingAlarm = false;
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mCacheExpireAlarm.alarmPending()) {
+ mCacheExpireAlarm.cancelAlarm();
+ mHadPendingAlarm = true;
+ }
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
setupUi(UNINSTALL);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 3d8a9d7..d7498a5 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -124,7 +124,7 @@
"Show launcher preview in grid picker");
public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
- "ENABLE_OVERVIEW_ACTIONS", false, "Show app actions instead of the shelf in Overview."
+ "ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview."
+ " As part of this decoupling, also distinguish swipe up from nav bar vs above it.");
public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 05d365b..4e60d13 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -90,6 +90,8 @@
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
+ public static final String REQUEST_OVERVIEW_ACTIONS_ENABLED = "overview-actions-enabled";
+
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824";
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 5e98184..e93df96 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -37,6 +37,7 @@
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
+import android.os.StrictMode;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
@@ -95,6 +96,9 @@
public static final long DEFAULT_UI_TIMEOUT = 10000;
private static final String TAG = "AbstractLauncherUiTest";
+ private static String sDetectedActivityLeak;
+ private static boolean sActivityLeakReported;
+
protected LooperExecutor mMainThreadExecutor = MAIN_EXECUTOR;
protected final UiDevice mDevice = UiDevice.getInstance(getInstrumentation());
protected final LauncherInstrumentation mLauncher = new LauncherInstrumentation();
@@ -102,6 +106,41 @@
protected String mTargetPackage;
private int mLauncherPid;
+ static {
+ if (TestHelpers.isInLauncherProcess()) {
+ StrictMode.VmPolicy.Builder builder =
+ new StrictMode.VmPolicy.Builder()
+ .detectActivityLeaks()
+ .penaltyLog()
+ .penaltyListener(Runnable::run, violation -> {
+ // Runs in the main thread. We can't dumpheap in the main thread,
+ // so let's just mark the fact that the leak has happened.
+ if (sDetectedActivityLeak == null) {
+ sDetectedActivityLeak = violation.toString();
+ }
+ });
+ StrictMode.setVmPolicy(builder.build());
+ }
+ }
+
+ public static void checkDetectedLeaks() {
+ if (sDetectedActivityLeak != null && !sActivityLeakReported) {
+ sActivityLeakReported = true;
+
+ final UiDevice device = UiDevice.getInstance(getInstrumentation());
+ try {
+ device.executeShellCommand(
+ "am dumpheap "
+ + device.getLauncherPackageName()
+ + " "
+ + getInstrumentation().getTargetContext().getFilesDir().getPath()
+ + "/ActivityLeakHeapDump.hprof");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
protected AbstractLauncherUiTest() {
mLauncher.enableCheckEventsForSuccessfulGestures();
try {
@@ -120,6 +159,8 @@
checkLauncherIntegrity(launcher, containerType)));
}
mLauncher.enableDebugTracing();
+ // Avoid double-reporting of Launcher crashes.
+ mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
}
protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -190,6 +231,7 @@
if (mLauncherPid != 0) {
assertEquals("Launcher crashed, pid mismatch:", mLauncherPid, mLauncher.getPid());
}
+ checkDetectedLeaks();
}
protected void clearLauncherData() throws IOException, InterruptedException {
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index 1a68122..38f50c1 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -56,6 +56,7 @@
private void evaluateInPortrait() throws Throwable {
mTest.mDevice.setOrientationNatural();
mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
+ AbstractLauncherUiTest.checkDetectedLeaks();
base.evaluate();
mTest.getDevice().pressHome();
}
@@ -63,6 +64,7 @@
private void evaluateInLandscape() throws Throwable {
mTest.mDevice.setOrientationLeft();
mTest.mLauncher.setExpectedRotation(Surface.ROTATION_90);
+ AbstractLauncherUiTest.checkDetectedLeaks();
base.evaluate();
mTest.getDevice().pressHome();
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 2ecac75..f8bbf21 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -64,6 +64,7 @@
test.waitForResumed("Launcher internal state is still Background");
// Check that we switched to home.
test.mLauncher.getWorkspace();
+ AbstractLauncherUiTest.checkDetectedLeaks();
}
// Please don't add negative test cases for methods that fail only after a long wait.
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 4b1a067..de9757f 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -41,7 +41,6 @@
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,14 +70,12 @@
@Test
@PortraitLandscape
- @Ignore // b/148867106
public void testWidgetConfig() throws Throwable {
runTest(true);
}
@Test
@PortraitLandscape
- @Ignore // b/148867106
public void testConfigCancelled() throws Throwable {
runTest(false);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 1ec5b68..47a60cf 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -169,6 +169,8 @@
private static boolean sCheckingEvents;
private boolean mCheckEventsForSuccessfulGestures = false;
+ private int mExpectedPid;
+ private Runnable mOnLauncherCrashed;
private static Pattern getTouchEventPattern(String prefix, String action) {
// The pattern includes sanity checks that we don't get a multi-touch events or other
@@ -251,6 +253,10 @@
mCheckEventsForSuccessfulGestures = true;
}
+ public void setOnLauncherCrashed(Runnable onLauncherCrashed) {
+ mOnLauncherCrashed = onLauncherCrashed;
+ }
+
Context getContext() {
return mInstrumentation.getContext();
}
@@ -326,7 +332,7 @@
}
}
- private String getAnomalyMessage() {
+ private String getSystemAnomalyMessage() {
UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
if (object != null) {
return "System alert popup is visible: " + object.getText();
@@ -345,15 +351,33 @@
return null;
}
+ private String getAnomalyMessage() {
+ if (mExpectedPid != 0 && mExpectedPid != getPid()) {
+ mExpectedPid = 0;
+ if (mOnLauncherCrashed != null) mOnLauncherCrashed.run();
+ return "Launcher crashed";
+ }
+
+ final String systemAnomalyMessage = getSystemAnomalyMessage();
+ if (systemAnomalyMessage != null) {
+ return "http://go/tapl : Tests are broken by a non-Launcher system error: "
+ + systemAnomalyMessage;
+ }
+
+ return null;
+ }
+
public void checkForAnomaly() {
final String anomalyMessage = getAnomalyMessage();
if (anomalyMessage != null) {
- String message = "http://go/tapl : Tests are broken by a non-Launcher system error: "
- + anomalyMessage;
- log("Hierarchy dump for: " + message);
+ if (sCheckingEvents) {
+ sCheckingEvents = false;
+ sEventChecker.finishNoWait();
+ }
+ log("Hierarchy dump for: " + anomalyMessage);
dumpViewHierarchy();
- Assert.fail(formatSystemHealthMessage(message));
+ Assert.fail(formatSystemHealthMessage(anomalyMessage));
}
}
@@ -543,7 +567,7 @@
return waitForLauncherObject(APPS_RES_ID);
}
case OVERVIEW: {
- if (mDevice.isNaturalOrientation()) {
+ if (mDevice.isNaturalOrientation() && !overviewActionsEnabled()) {
waitForLauncherObject(APPS_RES_ID);
} else {
waitUntilGone(APPS_RES_ID);
@@ -1203,6 +1227,11 @@
getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
}
+ public boolean overviewActionsEnabled() {
+ return getTestInfo(TestProtocol.REQUEST_OVERVIEW_ACTIONS_ENABLED).getBoolean(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
public void disableDebugTracing() {
getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
@@ -1246,10 +1275,13 @@
};
}
sCheckingEvents = true;
+ mExpectedPid = getPid();
if (sEventChecker == null) sEventChecker = new LogEventChecker();
sEventChecker.start();
return () -> {
+ checkForAnomaly();
+
if (sCheckingEvents) {
sCheckingEvents = false;
if (mCheckEventsForSuccessfulGestures) {