blob: f2530f5b337f732c04e510d24695dcddc66756e1 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.vr.util;
import android.content.Intent;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import org.junit.Assert;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.chrome.browser.vr.TestVrShellDelegate;
import org.chromium.chrome.browser.vr.VrFeedbackStatus;
import org.chromium.chrome.browser.vr.VrIntentDelegate;
import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule;
import org.chromium.chrome.browser.vr.rules.CustomTabActivityVrTestRule;
import org.chromium.chrome.browser.vr.rules.VrActivityRestrictionRule;
import org.chromium.chrome.browser.vr.rules.VrTestRule;
import org.chromium.chrome.browser.vr.rules.WebappActivityVrTestRule;
import java.util.ArrayList;
import java.util.concurrent.Callable;
/**
* Utility class for interacting with VR-specific Rules, i.e. ChromeActivityTestRules that implement
* the VrTestRule interface.
*/
public class VrTestRuleUtils extends XrTestRuleUtils {
// VrCore waits this amount of time after exiting VR before actually unregistering a registered
// Daydream intent, meaning that it still thinks VR is active until this amount of time has
// passed.
private static final int VRCORE_UNREGISTER_DELAY_MS = 500;
/**
* Essentially a Runnable that can throw exceptions.
*/
public interface ChromeLaunchMethod { public void launch() throws Throwable; }
/**
* Helper method to apply a VrTestRule/ChromeActivityTestRule combination. The only difference
* between various classes that implement VrTestRule is how they start their activity, so the
* common boilerplate code can be kept here so each VrTestRule only has to provide a way to
* launch Chrome.
*
* @param base The Statement passed to the calling ChromeActivityTestRule's apply() method.
* @param desc The Description passed to the calling ChromeActivityTestRule's apply() method.
* @param rule The calling VrTestRule.
* @param launcher A ChromeLaunchMethod whose launch() contains the code snippet to start Chrome
* in the calling ChromeActivityTestRule's activity type.
*/
public static void evaluateVrTestRuleImpl(final Statement base, final Description desc,
final VrTestRule rule, final ChromeLaunchMethod launcher) throws Throwable {
VrTestRuleUtils.ensureNoVrActivitiesDisplayed();
HeadTrackingUtils.checkForAndApplyHeadTrackingModeAnnotation(rule, desc);
launcher.launch();
// Must be called after Chrome is started, as otherwise startService fails with an
// IllegalStateException for being used from a backgrounded app.
VrSettingsServiceUtils.checkForAndApplyVrSettingsFileAnnotation(desc, rule);
// Reset the VR feedback shared preferences if they're not currently the default because
// otherwise we can run into issues with VrFeedbackInfoBarTest#* erroneously failing due to
// tests being non-hermetic. Only set if not the default instead of unconditionally in order
// to avoid unnecessary disk writes.
if (VrFeedbackStatus.getFeedbackOptOut()) {
VrFeedbackStatus.setFeedbackOptOut(false);
}
if (VrFeedbackStatus.getUserExitedAndEntered2DCount() != 0) {
VrFeedbackStatus.setUserExitedAndEntered2DCount(0);
}
try {
base.evaluate();
} finally {
if (rule.isTrackerDirty()) HeadTrackingUtils.revertTracker();
}
}
/**
* Creates the list of VrTestRules that are currently supported for use in test
* parameterization.
*
* @return An ArrayList of ParameterSets, with each ParameterSet containing a callable to create
* a VrTestRule for a supported ChromeActivity.
*/
public static ArrayList<ParameterSet> generateDefaultTestRuleParameters() {
ArrayList<ParameterSet> parameters = new ArrayList<ParameterSet>();
parameters.add(new ParameterSet()
.value(new Callable<ChromeTabbedActivityVrTestRule>() {
@Override
public ChromeTabbedActivityVrTestRule call() {
return new ChromeTabbedActivityVrTestRule();
}
})
.name("ChromeTabbedActivity"));
parameters.add(new ParameterSet()
.value(new Callable<CustomTabActivityVrTestRule>() {
@Override
public CustomTabActivityVrTestRule call() {
return new CustomTabActivityVrTestRule();
}
})
.name("CustomTabActivity"));
parameters.add(new ParameterSet()
.value(new Callable<WebappActivityVrTestRule>() {
@Override
public WebappActivityVrTestRule call() {
return new WebappActivityVrTestRule();
}
})
.name("WebappActivity"));
return parameters;
}
/**
* Creates a RuleChain that applies the XrActivityRestrictionRule and VrActivityRestrictionRule
* before the given VrTestRule.
*
* @param rule The TestRule to wrap in an XrActivityRestrictionRule and
* VrActivityRestrictionRule.
* @return A RuleChain that ensures an XrActivityRestrictionRule and VrActivityRestrictionRule
* is applied before the provided TestRule.
*/
public static RuleChain wrapRuleInActivityRestrictionRule(TestRule rule) {
Assert.assertTrue("Given rule is not an VrTestRule", rule instanceof VrTestRule);
return RuleChain
.outerRule(new VrActivityRestrictionRule(((VrTestRule) rule).getRestriction()))
.around(XrTestRuleUtils.wrapRuleInActivityRestrictionRule(rule));
}
/**
* Ensures that no VR-related activity is currently being displayed. This is meant to be used
* by TestRules before starting any activities. Having a VR activity in the foreground (e.g.
* Daydream Home) has the potential to affect test results, as it often means that we are in VR
* at the beginning of the test, which we don't want. This is most commonly caused by VrCore
* automatically launching Daydream Home when Chrome gets closed after a test, but can happen
* for other reasons as well.
*/
public static void ensureNoVrActivitiesDisplayed() {
// This will always be hit on standalones, but we're expected to be in VR in that case.
if (TestVrShellDelegate.isOnStandalone()) return;
UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
String currentPackageName = uiDevice.getCurrentPackageName();
if (currentPackageName != null && currentPackageName.contains("vr")) {
uiDevice.pressHome();
// Chrome startup would likely be slow enough that this sleep is unnecessary, but sleep
// to be sure since this will be hit relatively infrequently.
SystemClock.sleep(VRCORE_UNREGISTER_DELAY_MS);
}
}
/**
* Helper method to add additional data to a Chrome startup intent that makes it usable on a
* standalone VR device.
*/
public static Intent maybeAddStandaloneIntentData(Intent intent) {
if (TestVrShellDelegate.isOnStandalone()) {
// Tell VrShellDelegate that it should create a TestVrShellDelegate on startup
TestVrShellDelegate.enableTestVrShellDelegateOnStartupForTesting();
intent.addCategory(VrIntentDelegate.DAYDREAM_CATEGORY);
intent.putExtra("android.intent.extra.VR_LAUNCH", true);
}
return intent;
}
}