Merge "Update RecentsActivityRotation when device rotate"
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 2d9d092..470a442 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -258,6 +258,18 @@
@NonNull RemoteAnimationTargetCompat[] appTargets,
@NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing);
+ private boolean areAllTargetsTranslucent(@NonNull RemoteAnimationTargetCompat[] targets) {
+ boolean isAllOpeningTargetTrs = true;
+ for (int i = 0; i < targets.length; i++) {
+ RemoteAnimationTargetCompat target = targets[i];
+ if (target.mode == MODE_OPENING) {
+ isAllOpeningTargetTrs &= target.isTranslucent;
+ }
+ if (!isAllOpeningTargetTrs) break;
+ }
+ return isAllOpeningTargetTrs;
+ }
+
/**
* Compose the animations for a launch from the app icon.
*
@@ -275,16 +287,8 @@
mLauncher.getStateManager().setCurrentAnimation(anim);
Rect windowTargetBounds = getWindowTargetBounds(appTargets);
- boolean isAllOpeningTargetTrs = true;
- for (int i = 0; i < appTargets.length; i++) {
- RemoteAnimationTargetCompat target = appTargets[i];
- if (target.mode == MODE_OPENING) {
- isAllOpeningTargetTrs &= target.isTranslucent;
- }
- if (!isAllOpeningTargetTrs) break;
- }
anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds,
- !isAllOpeningTargetTrs));
+ areAllTargetsTranslucent(appTargets)));
if (launcherClosing) {
Pair<AnimatorSet, Runnable> launcherContentAnimator =
getLauncherContentAnimator(true /* isAppOpening */,
@@ -450,10 +454,10 @@
private Animator getOpeningWindowAnimators(View v,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
- Rect windowTargetBounds, boolean toggleVisibility) {
+ Rect windowTargetBounds, boolean appTargetsAreTranslucent) {
RectF launcherIconBounds = new RectF();
FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
- toggleVisibility, launcherIconBounds, true /* isOpening */);
+ !appTargetsAreTranslucent, launcherIconBounds, true /* isOpening */);
Rect crop = new Rect();
Matrix matrix = new Matrix();
@@ -500,6 +504,7 @@
: 0f;
final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
? 0 : getWindowCornerRadius(mLauncher.getResources());
+ final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
@@ -512,7 +517,7 @@
FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
RADIUS_DURATION, EXAGGERATED_EASE);
- FloatProp mShadowRadius = new FloatProp(0, mMaxShadowRadius, 0,
+ FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
APP_LAUNCH_DURATION, EXAGGERATED_EASE);
FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
@@ -765,12 +770,13 @@
int duration = CLOSING_TRANSITION_DURATION_MS;
float windowCornerRadius = mDeviceProfile.isMultiWindowMode
? 0 : getWindowCornerRadius(mLauncher.getResources());
+ float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius;
closingAnimator.setDuration(duration);
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DEACCEL_1_7);
FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR);
- FloatProp mShadowRadius = new FloatProp(mMaxShadowRadius, 0, 0, duration,
+ FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, 0, duration,
DEACCEL_1_7);
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 4f62d2f..a00ce56 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -64,7 +64,7 @@
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
-import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarToOverviewTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -285,7 +285,7 @@
list.add(new NoButtonNavbarToOverviewTouchController(this));
break;
case TWO_BUTTONS:
- list.add(new TwoButtonNavbarToOverviewTouchController(this));
+ list.add(new TwoButtonNavbarTouchController(this));
list.add(getDeviceProfile().isVerticalBarLayout()
? new TransposedQuickSwitchTouchController(this)
: new QuickSwitchTouchController(this));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java
deleted file mode 100644
index ff4bfe6..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2020 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 static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.touch.AbstractStateChangeTouchController;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.quickstep.SystemUiProxy;
-
-/**
- * Touch controller for handling edge swipes in 2-button mode
- */
-public class TwoButtonNavbarToOverviewTouchController extends AbstractStateChangeTouchController {
-
- private static final String TAG = "2BtnNavbarTouchCtrl";
-
- public TwoButtonNavbarToOverviewTouchController(Launcher l) {
- super(l, l.getDeviceProfile().isVerticalBarLayout()
- ? SingleAxisSwipeDetector.HORIZONTAL : SingleAxisSwipeDetector.VERTICAL);
- }
-
- @Override
- protected boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
- }
-
- @Override
- protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- boolean draggingFromNav =
- mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
- return draggingFromNav ? OVERVIEW : NORMAL;
- } else {
- return isDragTowardPositive ? OVERVIEW : NORMAL;
- }
- }
-
- @Override
- protected float getShiftRange() {
- return mLauncher.getDeviceProfile().isVerticalBarLayout()
- ? mLauncher.getDragLayer().getWidth() : super.getShiftRange();
- }
-
- @Override
- protected float initCurrentAnimation(@AnimationFlags int animComponent) {
- float range = getShiftRange();
- long maxAccuracy = (long) (2 * range);
- mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
- maxAccuracy, animComponent);
- return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
- }
-
- @Override
- protected void onSwipeInteractionCompleted(LauncherState targetState) {
- super.onSwipeInteractionCompleted(targetState);
- if (mStartState == NORMAL && targetState == OVERVIEW) {
- SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
new file mode 100644
index 0000000..6271a44
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 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 static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.AbstractFloatingView.getOpenView;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+
+import android.animation.ValueAnimator;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.views.AllAppsEduView;
+
+/**
+ * Touch controller for handling edge swipes in 2-button mode
+ */
+public class TwoButtonNavbarTouchController extends AbstractStateChangeTouchController {
+
+ private static final int MAX_NUM_SWIPES_TO_TRIGGER_EDU = 3;
+
+ private static final String TAG = "2BtnNavbarTouchCtrl";
+
+ private final boolean mIsTransposed;
+
+ // If true, we will finish the current animation instantly on second touch.
+ private boolean mFinishFastOnSecondTouch;
+
+ private int mContinuousTouchCount = 0;
+
+ public TwoButtonNavbarTouchController(Launcher l) {
+ super(l, l.getDeviceProfile().isVerticalBarLayout()
+ ? SingleAxisSwipeDetector.HORIZONTAL : SingleAxisSwipeDetector.VERTICAL);
+ mIsTransposed = l.getDeviceProfile().isVerticalBarLayout();
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ boolean canIntercept = canInterceptTouchInternal(ev);
+ if (!canIntercept) {
+ mContinuousTouchCount = 0;
+ }
+ return canIntercept;
+ }
+
+ private boolean canInterceptTouchInternal(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ if (mFinishFastOnSecondTouch) {
+ mCurrentAnimation.getAnimationPlayer().end();
+ }
+
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ if ((ev.getEdgeFlags() & EDGE_NAV_BAR) == 0) {
+ return false;
+ }
+ if (!mIsTransposed && mLauncher.isInState(OVERVIEW)) {
+ return true;
+ }
+ return mLauncher.isInState(NORMAL);
+ }
+
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (mIsTransposed) {
+ boolean draggingFromNav =
+ mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
+ return draggingFromNav ? OVERVIEW : NORMAL;
+ } else {
+ return isDragTowardPositive ^ (fromState == OVERVIEW) ? OVERVIEW : NORMAL;
+ }
+ }
+
+ @Override
+ protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
+ LauncherState targetState, float velocity, boolean isFling) {
+ super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
+ velocity, isFling);
+ mFinishFastOnSecondTouch = !mIsTransposed && mFromState == NORMAL;
+ }
+
+ @Override
+ protected float getShiftRange() {
+ return mLauncher.getDeviceProfile().isVerticalBarLayout()
+ ? mLauncher.getDragLayer().getWidth() : super.getShiftRange();
+ }
+
+ @Override
+ protected float initCurrentAnimation(@AnimationFlags int animComponent) {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
+ maxAccuracy, animComponent);
+ return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState) {
+ super.onSwipeInteractionCompleted(targetState);
+ if (!mIsTransposed) {
+ mContinuousTouchCount++;
+ }
+ if (mStartState == NORMAL && targetState == OVERVIEW) {
+ SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
+ } else if (targetState == NORMAL
+ && mContinuousTouchCount >= MAX_NUM_SWIPES_TO_TRIGGER_EDU) {
+ mContinuousTouchCount = 0;
+ if (getOpenView(mLauncher, TYPE_ALL_APPS_EDU) == null) {
+ AllAppsEduView.show(mLauncher);
+ }
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3d5b1c6..d648dd6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1395,6 +1395,7 @@
// Update the screenshot of the task
if (mTaskSnapshot == null) {
UI_HELPER_EXECUTOR.execute(() -> {
+ if (mRecentsAnimationController == null) return;
final ThumbnailData taskSnapshot =
mRecentsAnimationController.screenshotTask(runningTaskId);
MAIN_EXECUTOR.execute(() -> {
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index c0087b0..ca73041 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -293,7 +293,7 @@
builder.withMatrix(mMatrix)
.withWindowCrop(mCropRect)
.withCornerRadius(params.getCornerRadius())
- .withShadowRadius(params.getShadowRadius());
+ .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 5a7f541..65bcf26 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -325,7 +325,7 @@
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius())
- .withShadowRadius(params.getShadowRadius());
+ .withShadowRadius(app.isTranslucent ? 0 : params.getShadowRadius());
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
// When relativeLayer = 0, it reverts the surfaces back to the original order.
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 475953b..2e7e6e0 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -56,7 +56,6 @@
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.FailureRewriterRule;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.quickstep.views.RecentsView;
@@ -103,8 +102,7 @@
}
mOrderSensitiveRules = RuleChain
- .outerRule(new FailureRewriterRule())
- .around(new NavigationModeSwitchRule(mLauncher))
+ .outerRule(new NavigationModeSwitchRule(mLauncher))
.around(new FailureWatcher(mDevice));
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
@@ -221,7 +219,7 @@
OverviewTask task = overview.getCurrentTask();
assertNotNull("overview.getCurrentTask() returned null (1)", task);
assertNotNull("OverviewTask.open returned null", task.open());
- assertTrue("Test activity didn't open from Overview", mDevice.wait(Until.hasObject(
+ assertTrue("Test activity didn't open from Overview", TestHelpers.wait(Until.hasObject(
By.pkg(getAppPackageName()).text("TestActivity2")),
DEFAULT_UI_TIMEOUT));
@@ -238,7 +236,7 @@
// Test dismissing all tasks.
pressHomeAndGoToOverview().dismissAllTasks();
- assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
+ assertTrue("Fallback Launcher not visible", TestHelpers.wait(Until.hasObject(By.pkg(
mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
}
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index ba28e82..2da06e9 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -76,7 +76,8 @@
private boolean mInitialized;
private boolean mDestroyed;
- private int mLastActivityFlags = -1;
+ // Initialize mLastActivityFlags to a value not used by SCREEN_ORIENTATION flags
+ private int mLastActivityFlags = -999;
public RotationHelper(Activity activity) {
mActivity = activity;
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 539768e..14df0f3 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -34,7 +34,6 @@
public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
- public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 37dd4d2..b3c1240 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -63,7 +63,6 @@
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Wait;
-import com.android.launcher3.util.rule.FailureRewriterRule;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.ShellCommandRule;
@@ -100,6 +99,7 @@
private static final String TAG = "AbstractLauncherUiTest";
private static String sStrictmodeDetectedActivityLeak;
+ private static boolean sDumpWasGenerated = false;
private static boolean sActivityLeakReported;
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
protected static final ActivityLeakTracker ACTIVITY_LEAK_TRACKER = new ActivityLeakTracker();
@@ -151,10 +151,18 @@
}
public static String dumpHprofData() {
+ if (sDumpWasGenerated) return "dump has already been generated by another test";
try {
final String fileName = getInstrumentation().getTargetContext().getFilesDir().getPath()
+ "/ActivityLeakHeapDump.hprof";
- Debug.dumpHprofData(fileName);
+ if (TestHelpers.isInLauncherProcess()) {
+ Debug.dumpHprofData(fileName);
+ } else {
+ final UiDevice device = UiDevice.getInstance(getInstrumentation());
+ device.executeShellCommand(
+ "am dumpheap " + device.getLauncherPackageName() + " " + fileName);
+ }
+ sDumpWasGenerated = true;
return "memory dump filename: " + fileName;
} catch (Throwable e) {
Log.e(TAG, "dumpHprofData failed", e);
@@ -224,9 +232,8 @@
}
@Rule
- public TestRule mOrderSensitiveRules = RuleChain.
- outerRule(new FailureRewriterRule())
- .around(new TestStabilityRule())
+ public TestRule mOrderSensitiveRules = RuleChain
+ .outerRule(new TestStabilityRule())
.around(mActivityMonitor)
.around(getRulesInsideActivityMonitor());
@@ -237,7 +244,7 @@
@Before
public void setUp() throws Exception {
Assert.assertTrue("Keyguard is visible",
- mDevice.wait(
+ TestHelpers.wait(
Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
final String launcherPackageName = mDevice.getLauncherPackageName();
@@ -470,8 +477,7 @@
}
getInstrumentation().getTargetContext().startActivity(intent);
assertTrue("App didn't start: " + selector,
- UiDevice.getInstance(getInstrumentation())
- .wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT));
+ TestHelpers.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT));
}
public static ActivityInfo resolveSystemAppInfo(String category) {
diff --git a/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java b/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
deleted file mode 100644
index 77546de..0000000
--- a/tests/src/com/android/launcher3/util/rule/FailureInvestigator.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2020 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.util.rule;
-
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import android.os.SystemClock;
-
-import androidx.test.uiautomator.UiDevice;
-
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.regex.Pattern;
-
-class FailureInvestigator {
- private static boolean matches(String regex, CharSequence string) {
- return Pattern.compile(regex).matcher(string).find();
- }
-
- static class LogcatMatch {
- String logcatPattern;
- int bug;
-
- LogcatMatch(String logcatPattern, int bug) {
- this.logcatPattern = logcatPattern;
- this.bug = bug;
- }
- }
-
- static class ExceptionMatch {
- String exceptionPattern;
- LogcatMatch[] logcatMatches;
-
- ExceptionMatch(String exceptionPattern, LogcatMatch[] logcatMatches) {
- this.exceptionPattern = exceptionPattern;
- this.logcatMatches = logcatMatches;
- }
- }
-
- private static final ExceptionMatch[] EXCEPTION_MATCHES = {
- new ExceptionMatch(
- "java.lang.AssertionError: http://go/tapl : Tests are broken by a "
- + "non-Launcher system error: (Phone is locked|Screen is empty)",
- new LogcatMatch[]{
- new LogcatMatch(
- "BroadcastQueue: Can't deliver broadcast to com.android"
- + ".systemui.*Crashing it",
- 147845913),
- new LogcatMatch(
- "Attempt to invoke virtual method 'boolean android\\"
- + ".graphics\\.Bitmap\\.isRecycled\\(\\)' on a null "
- + "object reference",
- 148424291),
- new LogcatMatch(
- "java\\.lang\\.IllegalArgumentException\\: Ranking map "
- + "doesn't contain key",
- 148570537),
- }),
- new ExceptionMatch("Launcher didn't initialize",
- new LogcatMatch[]{
- new LogcatMatch(
- "ActivityManager: Reason: executing service com.google"
- + ".android.apps.nexuslauncher/com.android.launcher3"
- + ".notification.NotificationListener",
- 148238677),
- }),
- };
-
- static int getBugForFailure(CharSequence exception) {
- if ("com.google.android.setupwizard".equals(
- UiDevice.getInstance(getInstrumentation()).getLauncherPackageName())) {
- return 145935261;
- }
-
- final String logSinceBoot;
- try {
- final String systemBootTime =
- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(
- new Date(System.currentTimeMillis() - SystemClock.elapsedRealtime()));
-
- logSinceBoot =
- UiDevice.getInstance(getInstrumentation())
- .executeShellCommand("logcat -d -t " + systemBootTime.replace(" ", ""));
- } catch (IOException | OutOfMemoryError e) {
- return 0;
- }
-
- if (matches("android\\:\\:uirenderer\\:\\:renderthread\\:\\:EglManager\\:\\:swapBuffers",
- logSinceBoot)) {
- return 148529608;
- }
-
- for (ExceptionMatch exceptionMatch : EXCEPTION_MATCHES) {
- if (matches(exceptionMatch.exceptionPattern, exception)) {
- for (LogcatMatch logcatMatch : exceptionMatch.logcatMatches) {
- if (matches(logcatMatch.logcatPattern, logSinceBoot)) {
- return logcatMatch.bug;
- }
- }
- break;
- }
- }
-
- return 0;
- }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureRewriterRule.java b/tests/src/com/android/launcher3/util/rule/FailureRewriterRule.java
deleted file mode 100644
index 99ddee4..0000000
--- a/tests/src/com/android/launcher3/util/rule/FailureRewriterRule.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2020 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.util.rule;
-
-import android.util.Log;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-public class FailureRewriterRule implements TestRule {
- private static final String TAG = "FailureRewriter";
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new Statement() {
- @Override
- public void evaluate() throws Throwable {
- try {
- base.evaluate();
- } catch (Throwable e) {
- final int bug = FailureInvestigator.getBugForFailure(e.toString());
- if (bug == 0) throw e;
-
- Log.e(TAG, "Known bug found for the original failure "
- + android.util.Log.getStackTraceString(e));
- throw new AssertionError(
- "Detected a failure that matches a known bug b/" + bug);
- }
- }
- };
- }
-}
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 093c024..3fc83ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -68,8 +68,7 @@
mLauncher.assertTrue(
"App didn't start: " + label,
- mLauncher.getDevice().wait(Until.hasObject(selector),
- LauncherInstrumentation.WAIT_TIME_MS));
+ TestHelpers.wait(Until.hasObject(selector), LauncherInstrumentation.WAIT_TIME_MS));
return new Background(mLauncher);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index e2a442d..0c8f610 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -933,7 +933,7 @@
@NonNull
UiObject2 waitForAndroidObject(String resId) {
- final UiObject2 object = mDevice.wait(
+ final UiObject2 object = TestHelpers.wait(
Until.findObject(By.res(ANDROID_PACKAGE, resId)), WAIT_TIME_MS);
assertNotNull("Can't find a android object with id: " + resId, object);
return object;
diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
index b8791e8..7f6062f 100644
--- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
+++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java
@@ -27,6 +27,11 @@
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.DropBoxManager;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.uiautomator.SearchCondition;
+import androidx.test.uiautomator.UiDevice;
import org.junit.Assert;
@@ -35,6 +40,7 @@
public class TestHelpers {
+ private static final String TAG = "Tapl";
private static Boolean sIsInLauncherProcess;
public static boolean isInLauncherProcess() {
@@ -154,4 +160,12 @@
return null;
}
}
+
+ public static <R> R wait(SearchCondition<R> condition, long timeout) {
+ Log.d(TAG,
+ "TestHelpers.wait, condition=" + timeout + ", time=" + SystemClock.uptimeMillis());
+ final R result = UiDevice.getInstance(getInstrumentation()).wait(condition, timeout);
+ Log.d(TAG, "TestHelpers.wait, result=" + result + ", time=" + SystemClock.uptimeMillis());
+ return result;
+ }
}