update:2021.03.19
fix:重新提交 add:
This commit is contained in:
1
quickstep/tests/OWNERS
Normal file
1
quickstep/tests/OWNERS
Normal file
@@ -0,0 +1 @@
|
||||
vadimt@google.com
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.uiuios.ui.AbstractLauncherUiTest;
|
||||
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestRule;
|
||||
|
||||
/**
|
||||
* Base class for all instrumentation tests that deal with Quickstep.
|
||||
*/
|
||||
public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
|
||||
@Override
|
||||
protected TestRule getRulesInsideActivityMonitor() {
|
||||
return RuleChain.
|
||||
outerRule(new NavigationModeSwitchRule(mLauncher)).
|
||||
around(super.getRulesInsideActivityMonitor());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright (C) 2019 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 org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import android.app.prediction.AppPredictor;
|
||||
import android.app.prediction.AppTarget;
|
||||
import android.app.prediction.AppTargetId;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.os.Process;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.uiuios.BubbleTextView;
|
||||
import com.android.uiuios.Launcher;
|
||||
import com.android.uiuios.appprediction.PredictionRowView;
|
||||
import com.android.uiuios.appprediction.PredictionUiStateManager;
|
||||
import com.android.uiuios.appprediction.PredictionUiStateManager.Client;
|
||||
import com.android.uiuios.compat.LauncherAppsCompat;
|
||||
import com.android.uiuios.model.AppLaunchTracker;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AppPredictionsUITests extends AbstractQuickStepTest {
|
||||
|
||||
private LauncherActivityInfo mSampleApp1;
|
||||
private LauncherActivityInfo mSampleApp2;
|
||||
private LauncherActivityInfo mSampleApp3;
|
||||
|
||||
private AppPredictor.Callback mCallback;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(mTargetContext)
|
||||
.getActivityList(null, Process.myUserHandle());
|
||||
mSampleApp1 = activities.get(0);
|
||||
mSampleApp2 = activities.get(1);
|
||||
mSampleApp3 = activities.get(2);
|
||||
|
||||
// Disable app tracker
|
||||
AppLaunchTracker.INSTANCE.initializeForTesting(new AppLaunchTracker());
|
||||
PredictionUiStateManager.INSTANCE.initializeForTesting(null);
|
||||
|
||||
mCallback = PredictionUiStateManager.INSTANCE.get(mTargetContext).appPredictorCallback(
|
||||
Client.HOME);
|
||||
|
||||
mDevice.setOrientationNatural();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Throwable {
|
||||
AppLaunchTracker.INSTANCE.initializeForTesting(null);
|
||||
PredictionUiStateManager.INSTANCE.initializeForTesting(null);
|
||||
mDevice.unfreezeRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that prediction UI is updated as soon as we get predictions from the system
|
||||
*/
|
||||
@Test
|
||||
public void testPredictionExistsInAllApps() {
|
||||
mActivityMonitor.startLauncher();
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
|
||||
// Dispatch an update
|
||||
sendPredictionUpdate(mSampleApp1, mSampleApp2);
|
||||
// The first update should apply immediately.
|
||||
waitForLauncherCondition("Predictions were not updated in loading state",
|
||||
launcher -> getPredictedApp(launcher).size() == 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that prediction update is deferred if it is already visible
|
||||
*/
|
||||
@Test
|
||||
public void testPredictionsDeferredUntilHome() {
|
||||
mActivityMonitor.startLauncher();
|
||||
sendPredictionUpdate(mSampleApp1, mSampleApp2);
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
waitForLauncherCondition("Predictions were not updated in loading state",
|
||||
launcher -> getPredictedApp(launcher).size() == 2);
|
||||
|
||||
// Update predictions while all-apps is visible
|
||||
sendPredictionUpdate(mSampleApp1, mSampleApp2, mSampleApp3);
|
||||
assertEquals(2, getFromLauncher(this::getPredictedApp).size());
|
||||
|
||||
// Go home and go back to all-apps
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
assertEquals(3, getFromLauncher(this::getPredictedApp).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPredictionsDisabled() {
|
||||
mActivityMonitor.startLauncher();
|
||||
sendPredictionUpdate();
|
||||
mLauncher.pressHome().switchToAllApps();
|
||||
|
||||
waitForLauncherCondition("Predictions were not updated in loading state",
|
||||
launcher -> launcher.getAppsView().getFloatingHeaderView()
|
||||
.findFixedRowByType(PredictionRowView.class).getVisibility() == View.GONE);
|
||||
assertFalse(PredictionUiStateManager.INSTANCE.get(mTargetContext)
|
||||
.getCurrentState().isEnabled);
|
||||
}
|
||||
|
||||
public ArrayList<BubbleTextView> getPredictedApp(Launcher launcher) {
|
||||
PredictionRowView container = launcher.getAppsView().getFloatingHeaderView()
|
||||
.findFixedRowByType(PredictionRowView.class);
|
||||
|
||||
ArrayList<BubbleTextView> predictedAppViews = new ArrayList<>();
|
||||
for (int i = 0; i < container.getChildCount(); i++) {
|
||||
View view = container.getChildAt(i);
|
||||
if (view instanceof BubbleTextView && view.getVisibility() == View.VISIBLE) {
|
||||
predictedAppViews.add((BubbleTextView) view);
|
||||
}
|
||||
}
|
||||
return predictedAppViews;
|
||||
}
|
||||
|
||||
private void sendPredictionUpdate(LauncherActivityInfo... activities) {
|
||||
getOnUiThread(() -> {
|
||||
List<AppTarget> targets = new ArrayList<>(activities.length);
|
||||
for (LauncherActivityInfo info : activities) {
|
||||
ComponentName cn = info.getComponentName();
|
||||
AppTarget target =
|
||||
new AppTarget.Builder(new AppTargetId("app:" + cn), cn.getPackageName(), info.getUser())
|
||||
.setClassName(cn.getClassName())
|
||||
.build();
|
||||
targets.add(target);
|
||||
}
|
||||
mCallback.onTargetsAvailable(targets);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.android.quickstep;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.uiuios.LauncherState.OVERVIEW;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.uiuios.Launcher;
|
||||
import com.android.quickstep.views.DigitalWellBeingToast;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
|
||||
private static final String CALCULATOR_PACKAGE =
|
||||
resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
|
||||
|
||||
@Test
|
||||
public void testToast() throws Exception {
|
||||
startAppFast(CALCULATOR_PACKAGE);
|
||||
|
||||
final UsageStatsManager usageStatsManager =
|
||||
mTargetContext.getSystemService(UsageStatsManager.class);
|
||||
final int observerId = 0;
|
||||
|
||||
try {
|
||||
final String[] packages = new String[]{CALCULATOR_PACKAGE};
|
||||
|
||||
// Set time limit for app.
|
||||
runWithShellPermission(() ->
|
||||
usageStatsManager.registerAppUsageLimitObserver(observerId, packages,
|
||||
Duration.ofSeconds(600), Duration.ofSeconds(300),
|
||||
PendingIntent.getActivity(mTargetContext, -1, new Intent(), 0)));
|
||||
|
||||
mLauncher.pressHome();
|
||||
final DigitalWellBeingToast toast = getToast();
|
||||
|
||||
assertTrue("Toast is not visible", toast.hasLimit());
|
||||
assertEquals("Toast text: ", "5 minutes left today", toast.getText());
|
||||
|
||||
// Unset time limit for app.
|
||||
runWithShellPermission(
|
||||
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
|
||||
|
||||
mLauncher.pressHome();
|
||||
assertFalse("Toast is visible", getToast().hasLimit());
|
||||
} finally {
|
||||
runWithShellPermission(
|
||||
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
|
||||
}
|
||||
}
|
||||
|
||||
private DigitalWellBeingToast getToast() {
|
||||
executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW));
|
||||
waitForState("Launcher internal state didn't switch to Overview", OVERVIEW);
|
||||
waitForLauncherCondition("No latest task", launcher -> getLatestTask(launcher) != null);
|
||||
|
||||
return getFromLauncher(launcher -> {
|
||||
final TaskView task = getLatestTask(launcher);
|
||||
assertTrue("Latest task is not Calculator",
|
||||
CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName()));
|
||||
return task.getDigitalWellBeingToast();
|
||||
});
|
||||
}
|
||||
|
||||
private TaskView getLatestTask(Launcher launcher) {
|
||||
return launcher.<RecentsView>getOverviewPanel().getTaskViewAt(0);
|
||||
}
|
||||
|
||||
private void runWithShellPermission(Runnable action) {
|
||||
getInstrumentation().getUiAutomation().adoptShellPermissionIdentity();
|
||||
try {
|
||||
action.run();
|
||||
} finally {
|
||||
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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 android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.uiuios.tapl.LauncherInstrumentation.WAIT_TIME_MS;
|
||||
import static com.android.uiuios.tapl.TestHelpers.getHomeIntentInPackage;
|
||||
import static com.android.uiuios.tapl.TestHelpers.getLauncherInMyProcess;
|
||||
import static com.android.uiuios.ui.AbstractLauncherUiTest.resolveSystemApp;
|
||||
import static com.android.uiuios.util.rule.ShellCommandRule.disableHeadsUpNotification;
|
||||
import static com.android.uiuios.util.rule.ShellCommandRule.getLauncherCommand;
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.THREE_BUTTON;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.uiuios.tapl.LauncherInstrumentation;
|
||||
import com.android.uiuios.testcomponent.TestCommandReceiver;
|
||||
import com.android.uiuios.util.rule.FailureWatcher;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
/**
|
||||
* TODO: Fix fallback when quickstep is enabled
|
||||
*/
|
||||
public class FallbackRecentsTest {
|
||||
|
||||
private final UiDevice mDevice;
|
||||
private final LauncherInstrumentation mLauncher;
|
||||
private final ActivityInfo mOtherLauncherActivity;
|
||||
|
||||
@Rule
|
||||
public final TestRule mDisableHeadsUpNotification = disableHeadsUpNotification();
|
||||
|
||||
@Rule
|
||||
public final TestRule mSetLauncherCommand;
|
||||
|
||||
@Rule
|
||||
public final TestRule mOrderSensitiveRules;
|
||||
|
||||
public FallbackRecentsTest() throws RemoteException {
|
||||
Instrumentation instrumentation = getInstrumentation();
|
||||
Context context = instrumentation.getContext();
|
||||
mDevice = UiDevice.getInstance(instrumentation);
|
||||
mDevice.setOrientationNatural();
|
||||
mLauncher = new LauncherInstrumentation(instrumentation);
|
||||
|
||||
mOrderSensitiveRules = RuleChain.
|
||||
outerRule(new NavigationModeSwitchRule(mLauncher)).
|
||||
around(new FailureWatcher(mDevice));
|
||||
|
||||
mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
|
||||
getHomeIntentInPackage(context),
|
||||
MATCH_DISABLED_COMPONENTS).get(0).activityInfo;
|
||||
|
||||
mSetLauncherCommand = (base, desc) -> new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
TestCommandReceiver.callCommand(TestCommandReceiver.ENABLE_TEST_LAUNCHER);
|
||||
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
|
||||
getLauncherCommand(mOtherLauncherActivity));
|
||||
try {
|
||||
base.evaluate();
|
||||
} finally {
|
||||
TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
|
||||
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
|
||||
getLauncherCommand(getLauncherInMyProcess()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NavigationModeSwitch(mode = THREE_BUTTON)
|
||||
@Test
|
||||
public void goToOverviewFromHome() {
|
||||
mDevice.pressHome();
|
||||
assertTrue("Fallback Launcher not visible", mDevice.wait(Until.hasObject(By.pkg(
|
||||
mOtherLauncherActivity.packageName)), WAIT_TIME_MS));
|
||||
|
||||
mLauncher.getBackground().switchToOverview();
|
||||
}
|
||||
|
||||
@NavigationModeSwitch(mode = THREE_BUTTON)
|
||||
@Test
|
||||
public void goToOverviewFromApp() {
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
|
||||
mLauncher.getBackground().switchToOverview();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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 androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ALL;
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.THREE_BUTTON;
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.TWO_BUTTON;
|
||||
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_2BUTTON_OVERLAY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_3BUTTON_OVERLAY;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.NAV_BAR_MODE_GESTURAL_OVERLAY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.uiuios.tapl.LauncherInstrumentation;
|
||||
import com.android.uiuios.tapl.TestHelpers;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import org.junit.Assert;
|
||||
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.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Test rule that allows executing a test with Quickstep on and then Quickstep off.
|
||||
* The test should be annotated with @QuickstepOnOff.
|
||||
*/
|
||||
public class NavigationModeSwitchRule implements TestRule {
|
||||
|
||||
static final String TAG = "QuickStepOnOffRule";
|
||||
|
||||
public enum Mode {
|
||||
THREE_BUTTON, TWO_BUTTON, ZERO_BUTTON, ALL
|
||||
}
|
||||
|
||||
// Annotation for tests that need to be run with quickstep enabled and disabled.
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface NavigationModeSwitch {
|
||||
Mode mode() default ALL;
|
||||
}
|
||||
|
||||
private final LauncherInstrumentation mLauncher;
|
||||
|
||||
public NavigationModeSwitchRule(LauncherInstrumentation launcher) {
|
||||
mLauncher = launcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
if (TestHelpers.isInLauncherProcess() &&
|
||||
description.getAnnotation(NavigationModeSwitch.class) != null) {
|
||||
Mode mode = description.getAnnotation(NavigationModeSwitch.class).mode();
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
final Context context = getInstrumentation().getContext();
|
||||
final int currentInteractionMode =
|
||||
LauncherInstrumentation.getCurrentInteractionMode(context);
|
||||
final String prevOverlayPkg =
|
||||
QuickStepContract.isGesturalMode(currentInteractionMode)
|
||||
? NAV_BAR_MODE_GESTURAL_OVERLAY
|
||||
: QuickStepContract.isSwipeUpMode(currentInteractionMode)
|
||||
? NAV_BAR_MODE_2BUTTON_OVERLAY
|
||||
: NAV_BAR_MODE_3BUTTON_OVERLAY;
|
||||
final LauncherInstrumentation.NavigationModel originalMode =
|
||||
mLauncher.getNavigationModel();
|
||||
try {
|
||||
if (mode == ZERO_BUTTON || mode == ALL) {
|
||||
evaluateWithZeroButtons();
|
||||
}
|
||||
if (mode == TWO_BUTTON || mode == ALL) {
|
||||
evaluateWithTwoButtons();
|
||||
}
|
||||
if (mode == THREE_BUTTON || mode == ALL) {
|
||||
evaluateWithThreeButtons();
|
||||
}
|
||||
} finally {
|
||||
setActiveOverlay(prevOverlayPkg, originalMode);
|
||||
}
|
||||
}
|
||||
|
||||
public void evaluateWithoutChangingSetting(Statement base) throws Throwable {
|
||||
base.evaluate();
|
||||
}
|
||||
|
||||
private void evaluateWithThreeButtons() throws Throwable {
|
||||
setActiveOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.THREE_BUTTON);
|
||||
evaluateWithoutChangingSetting(base);
|
||||
}
|
||||
|
||||
private void evaluateWithTwoButtons() throws Throwable {
|
||||
setActiveOverlay(NAV_BAR_MODE_2BUTTON_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.TWO_BUTTON);
|
||||
base.evaluate();
|
||||
}
|
||||
|
||||
private void evaluateWithZeroButtons() throws Throwable {
|
||||
setActiveOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY,
|
||||
LauncherInstrumentation.NavigationModel.ZERO_BUTTON);
|
||||
base.evaluate();
|
||||
}
|
||||
|
||||
private void setActiveOverlay(String overlayPackage,
|
||||
LauncherInstrumentation.NavigationModel expectedMode) throws Exception {
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_3BUTTON_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY);
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_2BUTTON_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_2BUTTON_OVERLAY);
|
||||
setOverlayPackageEnabled(NAV_BAR_MODE_GESTURAL_OVERLAY,
|
||||
overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY);
|
||||
|
||||
if (currentSysUiNavigationMode() != expectedMode) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final Context targetContext = getInstrumentation().getTargetContext();
|
||||
final SysUINavigationMode.NavigationModeChangeListener listener =
|
||||
newMode -> {
|
||||
if (LauncherInstrumentation.getNavigationModel(newMode.resValue)
|
||||
== expectedMode) {
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
final SysUINavigationMode sysUINavigationMode =
|
||||
SysUINavigationMode.INSTANCE.get(targetContext);
|
||||
targetContext.getMainExecutor().execute(() ->
|
||||
sysUINavigationMode.addModeChangeListener(listener));
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
targetContext.getMainExecutor().execute(() ->
|
||||
sysUINavigationMode.removeModeChangeListener(listener));
|
||||
Assert.assertTrue("Navigation mode didn't change to " + expectedMode,
|
||||
currentSysUiNavigationMode() == expectedMode);
|
||||
}
|
||||
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
if (mLauncher.getNavigationModel() == expectedMode) break;
|
||||
Thread.sleep(100);
|
||||
}
|
||||
Assert.assertTrue("Couldn't switch to " + overlayPackage,
|
||||
mLauncher.getNavigationModel() == expectedMode);
|
||||
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
if (mLauncher.getNavigationModeMismatchError() == null) break;
|
||||
Thread.sleep(100);
|
||||
}
|
||||
final String error = mLauncher.getNavigationModeMismatchError();
|
||||
Assert.assertTrue("Switching nav mode: " + error, error == null);
|
||||
|
||||
Thread.sleep(5000);
|
||||
}
|
||||
|
||||
private void setOverlayPackageEnabled(String overlayPackage, boolean enable)
|
||||
throws Exception {
|
||||
Log.d(TAG, "setOverlayPackageEnabled: " + overlayPackage + " " + enable);
|
||||
final String action = enable ? "enable" : "disable";
|
||||
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
|
||||
"cmd overlay " + action + " " + overlayPackage);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
private static LauncherInstrumentation.NavigationModel currentSysUiNavigationMode() {
|
||||
return LauncherInstrumentation.getNavigationModel(
|
||||
SysUINavigationMode.getMode(
|
||||
getInstrumentation().
|
||||
getTargetContext()).
|
||||
resValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.uiuios.util.RaceConditionTracker.enterEvt;
|
||||
import static com.android.uiuios.util.RaceConditionTracker.exitEvt;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.uiuios.Launcher;
|
||||
import com.android.uiuios.util.RaceConditionReproducer;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.Mode;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
import com.android.quickstep.inputconsumers.OtherActivityInputConsumer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
|
||||
|
||||
static final int STRESS_REPEAT_COUNT = 10;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// Start an activity where the gestures start.
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
}
|
||||
|
||||
private void runTest(String... eventSequence) {
|
||||
final RaceConditionReproducer eventProcessor = new RaceConditionReproducer(eventSequence);
|
||||
|
||||
// Destroy Launcher activity.
|
||||
closeLauncherActivity();
|
||||
|
||||
// The test action.
|
||||
eventProcessor.startIteration();
|
||||
mLauncher.pressHome();
|
||||
eventProcessor.finishIteration();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // Ignoring until race condition repro framework is changes for multi-process case.
|
||||
@NavigationModeSwitch(mode = Mode.TWO_BUTTON)
|
||||
public void testPressHome() {
|
||||
runTest(enterEvt(Launcher.ON_CREATE_EVT),
|
||||
exitEvt(Launcher.ON_CREATE_EVT),
|
||||
enterEvt(OtherActivityInputConsumer.DOWN_EVT),
|
||||
exitEvt(OtherActivityInputConsumer.DOWN_EVT));
|
||||
|
||||
runTest(enterEvt(OtherActivityInputConsumer.DOWN_EVT),
|
||||
exitEvt(OtherActivityInputConsumer.DOWN_EVT),
|
||||
enterEvt(Launcher.ON_CREATE_EVT),
|
||||
exitEvt(Launcher.ON_CREATE_EVT));
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
public void testStressPressHome() {
|
||||
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
|
||||
// Destroy Launcher activity.
|
||||
closeLauncherActivity();
|
||||
|
||||
// The test action.
|
||||
mLauncher.pressHome();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
public void testStressSwipeToOverview() {
|
||||
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
|
||||
// Destroy Launcher activity.
|
||||
closeLauncherActivity();
|
||||
|
||||
// The test action.
|
||||
mLauncher.getBackground().switchToOverview();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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.uiuios.ui.TaplTestsLauncher3.getAppPackageName;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.Until;
|
||||
|
||||
import com.android.uiuios.Launcher;
|
||||
import com.android.uiuios.LauncherState;
|
||||
import com.android.uiuios.tapl.AllApps;
|
||||
import com.android.uiuios.tapl.AllAppsFromOverview;
|
||||
import com.android.uiuios.tapl.Background;
|
||||
import com.android.uiuios.tapl.Overview;
|
||||
import com.android.uiuios.tapl.OverviewTask;
|
||||
import com.android.uiuios.tapl.TestHelpers;
|
||||
import com.android.uiuios.ui.TaplTestsLauncher3;
|
||||
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
TaplTestsLauncher3.initialize(this);
|
||||
}
|
||||
|
||||
private void startTestApps() throws Exception {
|
||||
startAppFast(getAppPackageName());
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
startTestActivity(2);
|
||||
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
@Ignore // Enable after b/131115533
|
||||
public void testPressRecentAppsLauncherAndGetOverview() throws RemoteException {
|
||||
mDevice.pressRecentApps();
|
||||
waitForState("Launcher internal state didn't switch to Overview", LauncherState.OVERVIEW);
|
||||
|
||||
assertNotNull("getOverview() returned null", mLauncher.getOverview());
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
public void testWorkspaceSwitchToAllApps() {
|
||||
assertNotNull("switchToAllApps() returned null",
|
||||
mLauncher.getWorkspace().switchToAllApps());
|
||||
assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllAppsFromOverview() throws Exception {
|
||||
// Test opening all apps from Overview.
|
||||
assertNotNull("switchToAllApps() returned null",
|
||||
mLauncher.getWorkspace().switchToOverview().switchToAllApps());
|
||||
|
||||
TaplTestsLauncher3.runAllAppsTest(this, mLauncher.getAllAppsFromOverview());
|
||||
}
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testOverview() throws Exception {
|
||||
startTestApps();
|
||||
Overview overview = mLauncher.pressHome().switchToOverview();
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
executeOnLauncher(
|
||||
launcher -> assertTrue("Don't have at least 3 tasks", getTaskCount(launcher) >= 3));
|
||||
|
||||
// Test flinging forward and backward.
|
||||
executeOnLauncher(launcher -> assertEquals("Current task in Overview is not 0",
|
||||
0, getCurrentOverviewPage(launcher)));
|
||||
|
||||
overview.flingForward();
|
||||
assertTrue("Launcher internal state is not Overview", isInState(LauncherState.OVERVIEW));
|
||||
final Integer currentTaskAfterFlingForward = getFromLauncher(
|
||||
launcher -> getCurrentOverviewPage(launcher));
|
||||
executeOnLauncher(launcher -> assertTrue("Current task in Overview is still 0",
|
||||
currentTaskAfterFlingForward > 0));
|
||||
|
||||
overview.flingBackward();
|
||||
assertTrue("Launcher internal state is not Overview", isInState(LauncherState.OVERVIEW));
|
||||
executeOnLauncher(launcher -> assertTrue("Flinging back in Overview did nothing",
|
||||
getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
|
||||
|
||||
// Test opening a task.
|
||||
OverviewTask task = mLauncher.pressHome().switchToOverview().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(
|
||||
By.pkg(getAppPackageName()).text("TestActivity2")),
|
||||
DEFAULT_UI_TIMEOUT));
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
|
||||
// Test dismissing a task.
|
||||
overview = mLauncher.pressHome().switchToOverview();
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
final Integer numTasks = getFromLauncher(launcher -> getTaskCount(launcher));
|
||||
task = overview.getCurrentTask();
|
||||
assertNotNull("overview.getCurrentTask() returned null (2)", task);
|
||||
task.dismiss();
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview",
|
||||
numTasks - 1, getTaskCount(launcher)));
|
||||
|
||||
if (!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);
|
||||
assertTrue("Launcher internal state is not All Apps (1)",
|
||||
isInState(LauncherState.ALL_APPS));
|
||||
|
||||
overview = allApps.switchBackToOverview();
|
||||
assertNotNull("allApps.switchBackToOverview() returned null", overview);
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
|
||||
// Test UIDevice.pressBack()
|
||||
overview.switchToAllApps();
|
||||
assertNotNull("overview.switchToAllApps() returned null (2)", allApps);
|
||||
assertTrue("Launcher internal state is not All Apps (2)",
|
||||
isInState(LauncherState.ALL_APPS));
|
||||
mDevice.pressBack();
|
||||
mLauncher.getOverview();
|
||||
}
|
||||
|
||||
// Test UIDevice.pressHome, once we are in AllApps.
|
||||
mDevice.pressHome();
|
||||
waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
|
||||
|
||||
// Test dismissing all tasks.
|
||||
mLauncher.getWorkspace().switchToOverview().dismissAllTasks();
|
||||
waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL);
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Still have tasks after dismissing all",
|
||||
0, getTaskCount(launcher)));
|
||||
}
|
||||
|
||||
private int getCurrentOverviewPage(Launcher launcher) {
|
||||
return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
|
||||
}
|
||||
|
||||
private int getTaskCount(Launcher launcher) {
|
||||
return launcher.<RecentsView>getOverviewPanel().getTaskViewCount();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppIconLaunchFromAllAppsFromOverview() throws Exception {
|
||||
final AllApps allApps =
|
||||
mLauncher.getWorkspace().switchToOverview().switchToAllApps();
|
||||
assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
|
||||
|
||||
TaplTestsLauncher3.runIconLaunchFromAllAppsTest(this, allApps);
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
@PortraitLandscape
|
||||
public void testSwitchToOverview() throws Exception {
|
||||
assertNotNull("Workspace.switchToOverview() returned null",
|
||||
mLauncher.pressHome().switchToOverview());
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
}
|
||||
|
||||
@Test
|
||||
@NavigationModeSwitch
|
||||
// @PortraitLandscape
|
||||
public void testBackground() throws Exception {
|
||||
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
|
||||
final Background background = mLauncher.getBackground();
|
||||
assertNotNull("Launcher.getBackground() returned null", background);
|
||||
executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the top "
|
||||
+ "one",
|
||||
isInBackground(launcher)));
|
||||
|
||||
assertNotNull("Background.switchToOverview() returned null", background.switchToOverview());
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
isInState(LauncherState.OVERVIEW));
|
||||
}
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testAllAppsFromHome() throws Exception {
|
||||
// Test opening all apps
|
||||
assertNotNull("switchToAllApps() returned null",
|
||||
mLauncher.getWorkspace().switchToAllApps());
|
||||
|
||||
TaplTestsLauncher3.runAllAppsTest(this, mLauncher.getAllApps());
|
||||
|
||||
// Testing pressHome.
|
||||
assertTrue("Launcher internal state is not All Apps", isInState(LauncherState.ALL_APPS));
|
||||
assertNotNull("pressHome returned null", mLauncher.pressHome());
|
||||
assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL));
|
||||
assertNotNull("getHome returned null", mLauncher.getWorkspace());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user