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 0000000000..6854aa8dd5 --- /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 0000000000..6a149b74ba --- /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 9cbab5e183..fc8e1c51e1 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.RemoteException; 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 com.android.launcher3.util.rule.LauncherActivityRule; 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 @@ public abstract class AbstractLauncherUiTest { 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 @@ public abstract class AbstractLauncherUiTest { } } - protected Instrumentation getInstrumentation() { - return InstrumentationRegistry.getInstrumentation(); - } - /** * Opens all apps and returns the recycler view */ @@ -231,7 +278,7 @@ public abstract class AbstractLauncherUiTest { 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 @@ public abstract class AbstractLauncherUiTest { } protected T getFromLauncher(Function f) { - if (!mIsInLauncherProcess) return null; + if (!TestHelpers.isInLauncherProcess()) return null; return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity())); } @@ -298,7 +345,7 @@ public abstract class AbstractLauncherUiTest { // flakiness. protected boolean waitForLauncherCondition( Function condition, long timeout) { - if (!mIsInLauncherProcess) return true; + if (!TestHelpers.isInLauncherProcess()) return true; return Wait.atMost(() -> getFromLauncher(condition), timeout); } @@ -311,7 +358,7 @@ public abstract class AbstractLauncherUiTest { getOnUiThread(new Callable() { @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 0000000000..da21a5dfcc --- /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 183e3908ee..aaea3d51f9 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.LauncherAppWidgetProviderInfo; 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 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { private void setResult(boolean success) { - getInstrumentation().getTargetContext().sendBroadcast( + TestHelpers.getInstrumentation().getTargetContext().sendBroadcast( WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class, success ? "clickOK" : "clickCancel")); }