Merge "Adding tests that would reliably reproduce shifted search." into ub-launcher3-master

This commit is contained in:
Vadim Tryshev 2018-12-17 23:21:55 +00:00 committed by Android (Google) Code Review
commit 57e98b8006
7 changed files with 142 additions and 25 deletions

View File

@ -22,6 +22,8 @@ import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper
.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
@ -47,6 +49,7 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@ -70,6 +73,7 @@ import java.util.concurrent.TimeUnit;
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
public static final String DOWN_EVT = "OtherActivityTouchConsumer.DOWN";
private final SparseArray<RecentsAnimationState> mAnimationStates = new SparseArray<>();
private final RunningTaskInfo mRunningTask;
@ -135,6 +139,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
mTouchInteractionLog.addMotionEvent(ev);
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
RaceConditionTracker.onEvent(DOWN_EVT, ENTER);
TraceHelper.beginSection("TouchInt");
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
@ -151,6 +156,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
Display display = getSystemService(WindowManager.class).getDefaultDisplay();
mDisplayRotation = display.getRotation();
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
RaceConditionTracker.onEvent(DOWN_EVT, EXIT);
break;
}
case ACTION_POINTER_UP: {

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 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.quickstep;
import static com.android.launcher3.util.RaceConditionTracker.enterEvt;
import static com.android.launcher3.util.RaceConditionTracker.exitEvt;
import android.content.Intent;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
import com.android.launcher3.util.RaceConditionReproducer;
import com.android.quickstep.QuickStepOnOffRule.Mode;
import com.android.quickstep.QuickStepOnOffRule.QuickstepOnOff;
import org.junit.Test;
import org.junit.runner.RunWith;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class RaceConditionsTests extends AbstractQuickStepTest {
private void runTest(String... eventSequence) {
final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(eventSequence);
// Destroy Launcher activity.
executeOnLauncher(launcher -> {
if (launcher != null) {
launcher.finish();
}
});
waitForLauncherCondition(
"Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT);
// Start an activity where we'll press home.
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
// The test action.
eventProcessor.startIteration();
mLauncher.pressHome();
eventProcessor.finishIteration();
}
@Test
@QuickstepOnOff(mode = Mode.ON)
public void testPressHomeToStartLauncher() {
runTest(enterEvt(Launcher.ON_CREATE_EVT),
exitEvt(Launcher.ON_CREATE_EVT),
enterEvt(OtherActivityTouchConsumer.DOWN_EVT),
exitEvt(OtherActivityTouchConsumer.DOWN_EVT));
runTest(enterEvt(OtherActivityTouchConsumer.DOWN_EVT),
exitEvt(OtherActivityTouchConsumer.DOWN_EVT),
enterEvt(Launcher.ON_CREATE_EVT),
exitEvt(Launcher.ON_CREATE_EVT));
}
}

View File

@ -24,9 +24,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.app.Instrumentation;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.util.Log;
@ -66,7 +64,6 @@ import java.io.IOException;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTests extends AbstractQuickStepTest {
private static final int WAIT_TIME_MS = 60000;
private static final String TAG = "TaplTests";
private static int sScreenshotCount = 0;
@ -112,13 +109,6 @@ public class TaplTests extends AbstractQuickStepTest {
waitForResumed("Launcher internal state is still Background");
}
private String resolveSystemApp(String category) {
return getInstrumentation().getContext().getPackageManager().resolveActivity(
new Intent(Intent.ACTION_MAIN).addCategory(category),
PackageManager.MATCH_SYSTEM_ONLY).
activityInfo.packageName;
}
private boolean isInState(LauncherState state) {
if (!TestHelpers.isInLauncherProcess()) return true;
return getFromLauncher(launcher -> launcher.getStateManager().getState() == state);
@ -143,17 +133,6 @@ public class TaplTests extends AbstractQuickStepTest {
return !launcher.hasBeenResumed();
}
private void startAppFast(String packageName) {
final Instrumentation instrumentation = getInstrumentation();
final Intent intent = instrumentation.getContext().getPackageManager().
getLaunchIntentForPackage(packageName);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instrumentation.getTargetContext().startActivity(intent);
assertTrue(packageName + " didn't start",
mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), WAIT_TIME_MS));
}
private void startTestApps() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_MESSAGING));
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@ -338,7 +317,8 @@ public class TaplTests extends AbstractQuickStepTest {
assertNotNull("overview.getCurrentTask() returned null (1)", task);
assertNotNull("OverviewTask.open returned null", task.open());
assertTrue("Contacts app didn't open from Overview", mDevice.wait(Until.hasObject(
By.pkg(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS)).depth(0)), WAIT_TIME_MS));
By.pkg(resolveSystemApp(Intent.CATEGORY_APP_CONTACTS)).depth(0)),
LONG_WAIT_TIME_MS));
executeOnLauncher(launcher -> assertTrue(
"Launcher activity is the top activity; expecting another activity to be the top "
+ "one",

View File

@ -19,6 +19,7 @@ package com.android.launcher3;
import static android.content.pm.ActivityInfo.CONFIG_LOCALE;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
@ -26,6 +27,8 @@ import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.logging.LoggerUtils.newTarget;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@ -71,16 +74,18 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
@ -116,6 +121,7 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
@ -143,8 +149,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import androidx.annotation.Nullable;
/**
* Default launcher application.
*/
@ -184,6 +188,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
private static final String RUNTIME_STATE_PENDING_ACTIVITY_RESULT = "launcher.activity_result";
// Type: SparseArray<Parcelable>
private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
public static final String ON_CREATE_EVT = "Launcher.onCreate";
private LauncherStateManager mStateManager;
@ -255,6 +260,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onCreate(Bundle savedInstanceState) {
RaceConditionTracker.onEvent(ON_CREATE_EVT, ENTER);
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
@ -349,6 +355,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mRotationHelper.initialize();
TraceHelper.endSection("Launcher-onCreate");
RaceConditionTracker.onEvent(ON_CREATE_EVT, EXIT);
}
@Override

View File

@ -22,6 +22,9 @@ package com.android.launcher3.util;
* orders.
*/
public class RaceConditionTracker {
public final static boolean ENTER = true;
public final static boolean EXIT = false;
public interface EventProcessor {
void onEvent(String eventName);
}
@ -35,4 +38,22 @@ public class RaceConditionTracker {
public static void onEvent(String eventName) {
if (sEventProcessor != null) sEventProcessor.onEvent(eventName);
}
public static void onEvent(String eventName, boolean isEnter) {
if (sEventProcessor != null) {
sEventProcessor.onEvent(enterExitEvt(eventName, isEnter));
}
}
public static String enterExitEvt(String eventName, boolean isEnter) {
return eventName + ":" + (isEnter ? "enter" : "exit");
}
public static String enterEvt(String eventName) {
return enterExitEvt(eventName, ENTER);
}
public static String exitEvt(String eventName) {
return enterExitEvt(eventName, EXIT);
}
}

View File

@ -17,6 +17,7 @@ package com.android.launcher3.ui;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.Instrumentation;
@ -25,11 +26,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageManager;
import android.os.Process;
import android.os.RemoteException;
import android.view.Surface;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
@ -77,6 +80,7 @@ public abstract class AbstractLauncherUiTest {
public static final long SHORT_UI_TIMEOUT= 300;
public static final long DEFAULT_UI_TIMEOUT = 10000;
protected static final int LONG_WAIT_TIME_MS = 60000;
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
protected final UiDevice mDevice;
@ -325,4 +329,22 @@ public abstract class AbstractLauncherUiTest {
return intent == null ? null : (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
}
}
protected void startAppFast(String packageName) {
final Instrumentation instrumentation = getInstrumentation();
final Intent intent = instrumentation.getContext().getPackageManager().
getLaunchIntentForPackage(packageName);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
instrumentation.getTargetContext().startActivity(intent);
assertTrue(packageName + " didn't start",
mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), LONG_WAIT_TIME_MS));
}
protected String resolveSystemApp(String category) {
return getInstrumentation().getContext().getPackageManager().resolveActivity(
new Intent(Intent.ACTION_MAIN).addCategory(category),
PackageManager.MATCH_SYSTEM_ONLY).
activityInfo.packageName;
}
}

View File

@ -43,6 +43,11 @@ import java.util.concurrent.TimeUnit;
* executing events in previously unseen order. It does it by postponing execution of threads that
* would lead to an already seen sequence.
*
* If an event A occurs before event B in the sequence, this is how execution order looks like:
* Events: ... A ... B ...
* Events and instructions, guaranteed order:
* (instructions executed prior to A) A ... B (instructions executed after B)
*
* Each iteration has 3 parts (phases).
* Phase 1. Picking a previously seen event subsequence that we believe can have previously unseen
* continuations. Reproducing this sequence by pausing threads that would lead to other sequences.
@ -178,6 +183,10 @@ public class RaceConditionReproducer implements RaceConditionTracker.EventProces
mReproString = reproString;
}
public RaceConditionReproducer(String... reproSequence) {
this(String.join("|", reproSequence));
}
public synchronized String getCurrentSequenceString() {
return mCurrentSequence.toString();
}