Make @QuickstepOnOff and @PortraitLandscape available to all UI tests.

Also, fix rotation as Portrait as starting poin for all tests, to avoid
tests running in unexpected configuration.

Bug: 115645301
Test: run all Nexus tests
Change-Id: I3ab0e91db111eeefda77af2960c43962a119de0c
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
new file mode 100644
index 0000000..6854aa8
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -0,0 +1,31 @@
+/*
+ * 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 com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+
+/**
+ * Base class for all instrumentation tests that deal with Quickstep.
+ */
+public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
+    @Rule
+    public TestRule mQuickstepOnOffExecutor =
+            new QuickStepOnOffRule(mMainThreadExecutor, mLauncher);
+}
diff --git a/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
new file mode 100644
index 0000000..6a149b7
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/QuickStepOnOffRule.java
@@ -0,0 +1,89 @@
+/*
+ * 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 androidx.test.InstrumentationRegistry;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.ui.TestHelpers;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+
+/**
+ * Test rule that allows executing a test with Quickstep on and then Quickstep off.
+ * The test should be annotated with @QuickstepOnOff.
+ */
+public class QuickStepOnOffRule implements TestRule {
+    // Annotation for tests that need to be run with quickstep enabled and disabled.
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface QuickstepOnOff {
+    }
+
+    private final Executor mMainThreadExecutor;
+    private final LauncherInstrumentation mLauncher;
+
+    public QuickStepOnOffRule(Executor mainThreadExecutor, LauncherInstrumentation launcher) {
+        mLauncher = launcher;
+        this.mMainThreadExecutor = mainThreadExecutor;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        if (TestHelpers.isInLauncherProcess() &&
+                description.getAnnotation(QuickstepOnOff.class) != null) {
+            return new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    try {
+                        evaluateWithQuickstepOn();
+                        evaluateWithQuickstepOff();
+                    } finally {
+                        overrideSwipeUpEnabled(null);
+                    }
+                }
+
+                private void evaluateWithQuickstepOff() throws Throwable {
+                    overrideSwipeUpEnabled(false);
+                    base.evaluate();
+                }
+
+                private void evaluateWithQuickstepOn() throws Throwable {
+                    overrideSwipeUpEnabled(true);
+                    base.evaluate();
+                }
+
+                private void overrideSwipeUpEnabled(Boolean swipeUpEnabledOverride) {
+                    mLauncher.overrideSwipeUpEnabled(swipeUpEnabledOverride);
+                    mMainThreadExecutor.execute(() -> OverviewInteractionState.INSTANCE.get(
+                            InstrumentationRegistry.getInstrumentation().getTargetContext()).
+                            notifySwipeUpSettingChanged(mLauncher.isSwipeUpEnabled()));
+                }
+            };
+        } else {
+            return base;
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 9cbab5e..fc8e1c5 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -32,6 +32,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.Surface;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.By;
@@ -59,7 +60,13 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -83,22 +90,66 @@
     protected final LauncherInstrumentation mLauncher;
     protected Context mTargetContext;
     protected String mTargetPackage;
-    protected final boolean mIsInLauncherProcess;
 
     private static final String TAG = "AbstractLauncherUiTest";
 
     protected AbstractLauncherUiTest() {
-        final Instrumentation instrumentation = getInstrumentation();
+        final Instrumentation instrumentation =TestHelpers.getInstrumentation();
         mDevice = UiDevice.getInstance(instrumentation);
+        try {
+            mDevice.setOrientationNatural();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
         mLauncher = new LauncherInstrumentation(instrumentation);
-
-        mIsInLauncherProcess = instrumentation.getTargetContext().getPackageName().equals(
-                mDevice.getLauncherPackageName());
     }
 
     @Rule
     public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
 
+    // Annotation for tests that need to be run in portrait and landscape modes.
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    protected @interface PortraitLandscape {
+    }
+
+    @Rule
+    public TestRule mPortraitLandscapeExecutor =
+            (base, description) -> false && description.getAnnotation(PortraitLandscape.class)
+                    != null ? new Statement() {
+                @Override
+                public void evaluate() throws Throwable {
+                    try {
+                        // Create launcher activity if necessary and bring it to the front.
+                        mDevice.pressHome();
+                        waitForLauncherCondition(launcher -> launcher != null);
+
+                        executeOnLauncher(launcher ->
+                                launcher.getRotationHelper().forceAllowRotationForTesting(true));
+
+                        evaluateInPortrait();
+                        evaluateInLandscape();
+                    } finally {
+                        mDevice.setOrientationNatural();
+                        executeOnLauncher(launcher ->
+                                launcher.getRotationHelper().forceAllowRotationForTesting(false));
+                        mLauncher.setExpectedRotation(Surface.ROTATION_0);
+                    }
+                }
+
+                private void evaluateInPortrait() throws Throwable {
+                    mDevice.setOrientationNatural();
+                    mLauncher.setExpectedRotation(Surface.ROTATION_0);
+                    base.evaluate();
+                }
+
+                private void evaluateInLandscape() throws Throwable {
+                    mDevice.setOrientationLeft();
+                    mLauncher.setExpectedRotation(Surface.ROTATION_90);
+                    base.evaluate();
+                }
+            } : base;
+
     @Before
     public void setUp() throws Exception {
         mTargetContext = InstrumentationRegistry.getTargetContext();
@@ -119,10 +170,6 @@
         }
     }
 
-    protected Instrumentation getInstrumentation() {
-        return InstrumentationRegistry.getInstrumentation();
-    }
-
     /**
      * Opens all apps and returns the recycler view
      */
@@ -231,7 +278,7 @@
     protected void sendPointer(int action, Point point) {
         MotionEvent event = MotionEvent.obtain(SystemClock.uptimeMillis(),
                 SystemClock.uptimeMillis(), action, point.x, point.y, 0);
-        getInstrumentation().sendPointerSync(event);
+        TestHelpers.getInstrumentation().sendPointerSync(event);
         event.recycle();
     }
 
@@ -271,7 +318,7 @@
     }
 
     protected <T> T getFromLauncher(Function<Launcher, T> f) {
-        if (!mIsInLauncherProcess) return null;
+        if (!TestHelpers.isInLauncherProcess()) return null;
         return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
     }
 
@@ -298,7 +345,7 @@
     // flakiness.
     protected boolean waitForLauncherCondition(
             Function<Launcher, Boolean> condition, long timeout) {
-        if (!mIsInLauncherProcess) return true;
+        if (!TestHelpers.isInLauncherProcess()) return true;
         return Wait.atMost(() -> getFromLauncher(condition), timeout);
     }
 
@@ -311,7 +358,7 @@
                 getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
             @Override
             public LauncherAppWidgetProviderInfo call() throws Exception {
-                ComponentName cn = new ComponentName(getInstrumentation().getContext(),
+                ComponentName cn = new ComponentName(TestHelpers.getInstrumentation().getContext(),
                         hasConfigureScreen ? AppWidgetWithConfig.class : AppWidgetNoConfig.class);
                 Log.d(TAG, "findWidgetProvider componentName=" + cn.flattenToString());
                 return AppWidgetManagerCompat.getInstance(mTargetContext)
diff --git a/tests/src/com/android/launcher3/ui/TestHelpers.java b/tests/src/com/android/launcher3/ui/TestHelpers.java
new file mode 100644
index 0000000..da21a5d
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/TestHelpers.java
@@ -0,0 +1,36 @@
+/*
+ * 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.launcher3.ui;
+
+import android.app.Instrumentation;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.uiautomator.UiDevice;
+
+public class TestHelpers {
+    private static final boolean IS_IN_LAUNCHER_PROCESS =
+            getInstrumentation().getTargetContext().getPackageName().equals(
+                    UiDevice.getInstance(getInstrumentation()).getLauncherPackageName());
+
+    public static Instrumentation getInstrumentation() {
+        return InstrumentationRegistry.getInstrumentation();
+    }
+
+    public static boolean isInLauncherProcess() {
+        return IS_IN_LAUNCHER_PROCESS;
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 183e390..aaea3d5 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.testcomponent.WidgetConfigActivity;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TestHelpers;
 import com.android.launcher3.util.Condition;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ShellCommandRule;
@@ -131,7 +132,7 @@
 
     private void setResult(boolean success) {
 
-        getInstrumentation().getTargetContext().sendBroadcast(
+        TestHelpers.getInstrumentation().getTargetContext().sendBroadcast(
                 WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
                         success ? "clickOK" : "clickCancel"));
     }