1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.vr.util; 6 7 import android.content.Intent; 8 import android.os.SystemClock; 9 import android.support.test.InstrumentationRegistry; 10 import android.support.test.uiautomator.UiDevice; 11 12 import org.junit.Assert; 13 import org.junit.rules.RuleChain; 14 import org.junit.rules.TestRule; 15 import org.junit.runner.Description; 16 import org.junit.runners.model.Statement; 17 18 import org.chromium.base.BundleUtils; 19 import org.chromium.base.test.BundleTestRule; 20 import org.chromium.base.test.params.ParameterSet; 21 import org.chromium.chrome.browser.vr.TestVrShellDelegate; 22 import org.chromium.chrome.browser.vr.VrFeedbackStatus; 23 import org.chromium.chrome.browser.vr.VrIntentDelegate; 24 import org.chromium.chrome.browser.vr.rules.ChromeTabbedActivityVrTestRule; 25 import org.chromium.chrome.browser.vr.rules.CustomTabActivityVrTestRule; 26 import org.chromium.chrome.browser.vr.rules.VrActivityRestrictionRule; 27 import org.chromium.chrome.browser.vr.rules.VrTestRule; 28 import org.chromium.chrome.browser.vr.rules.WebappActivityVrTestRule; 29 30 import java.util.ArrayList; 31 import java.util.concurrent.Callable; 32 33 /** 34 * Utility class for interacting with VR-specific Rules, i.e. ChromeActivityTestRules that implement 35 * the VrTestRule interface. 36 */ 37 public class VrTestRuleUtils extends XrTestRuleUtils { 38 // VrCore waits this amount of time after exiting VR before actually unregistering a registered 39 // Daydream intent, meaning that it still thinks VR is active until this amount of time has 40 // passed. 41 private static final int VRCORE_UNREGISTER_DELAY_MS = 500; 42 43 /** 44 * Helper method to apply a VrTestRule/ChromeActivityTestRule combination. The only difference 45 * between various classes that implement VrTestRule is how they start their activity, so the 46 * common boilerplate code can be kept here so each VrTestRule only has to provide a way to 47 * launch Chrome. 48 * 49 * @param base The Statement passed to the calling ChromeActivityTestRule's apply() method. 50 * @param desc The Description passed to the calling ChromeActivityTestRule's apply() method. 51 * @param rule The calling VrTestRule. 52 * @param launcher A ChromeLaunchMethod whose launch() contains the code snippet to start Chrome 53 * in the calling ChromeActivityTestRule's activity type. 54 */ evaluateVrTestRuleImpl(final Statement base, final Description desc, final VrTestRule rule, final ChromeLaunchMethod launcher)55 public static void evaluateVrTestRuleImpl(final Statement base, final Description desc, 56 final VrTestRule rule, final ChromeLaunchMethod launcher) throws Throwable { 57 TestVrShellDelegate.setDescription(desc); 58 59 VrTestRuleUtils.ensureNoVrActivitiesDisplayed(); 60 launcher.launch(); 61 62 // Reset the VR feedback shared preferences if they're not currently the default because 63 // otherwise we can run into issues with VrFeedbackInfoBarTest#* erroneously failing due to 64 // tests being non-hermetic. Only set if not the default instead of unconditionally in order 65 // to avoid unnecessary disk writes. 66 if (VrFeedbackStatus.getFeedbackOptOut()) { 67 VrFeedbackStatus.setFeedbackOptOut(false); 68 } 69 if (VrFeedbackStatus.getUserExitedAndEntered2DCount() != 0) { 70 VrFeedbackStatus.setUserExitedAndEntered2DCount(0); 71 } 72 73 base.evaluate(); 74 } 75 76 /** 77 * Creates the list of VrTestRules that are currently supported for use in test 78 * parameterization. 79 * 80 * @return An ArrayList of ParameterSets, with each ParameterSet containing a callable to create 81 * a VrTestRule for a supported ChromeActivity. 82 */ generateDefaultTestRuleParameters()83 public static ArrayList<ParameterSet> generateDefaultTestRuleParameters() { 84 ArrayList<ParameterSet> parameters = new ArrayList<ParameterSet>(); 85 parameters.add(new ParameterSet() 86 .value(new Callable<ChromeTabbedActivityVrTestRule>() { 87 @Override 88 public ChromeTabbedActivityVrTestRule call() { 89 return new ChromeTabbedActivityVrTestRule(); 90 } 91 }) 92 .name("ChromeTabbedActivity")); 93 94 parameters.add(new ParameterSet() 95 .value(new Callable<CustomTabActivityVrTestRule>() { 96 @Override 97 public CustomTabActivityVrTestRule call() { 98 return new CustomTabActivityVrTestRule(); 99 } 100 }) 101 .name("CustomTabActivity")); 102 103 parameters.add(new ParameterSet() 104 .value(new Callable<WebappActivityVrTestRule>() { 105 @Override 106 public WebappActivityVrTestRule call() { 107 return new WebappActivityVrTestRule(); 108 } 109 }) 110 .name("WebappActivity")); 111 112 return parameters; 113 } 114 115 /** 116 * Creates a RuleChain that applies the XrActivityRestrictionRule and VrActivityRestrictionRule 117 * before the given VrTestRule. 118 * 119 * Also enforces that {@link BundleUtils#isBundle()} returns true for vr to be initialized. 120 * 121 * @param rule The TestRule to wrap in an XrActivityRestrictionRule and 122 * VrActivityRestrictionRule. 123 * @return A RuleChain that ensures an XrActivityRestrictionRule and VrActivityRestrictionRule 124 * is applied before the provided TestRule. 125 */ wrapRuleInActivityRestrictionRule(TestRule rule)126 public static RuleChain wrapRuleInActivityRestrictionRule(TestRule rule) { 127 Assert.assertTrue("Given rule is not an VrTestRule", rule instanceof VrTestRule); 128 return RuleChain 129 .outerRule(new VrActivityRestrictionRule(((VrTestRule) rule).getRestriction())) 130 .around(new BundleTestRule()) 131 .around(XrTestRuleUtils.wrapRuleInActivityRestrictionRule(rule)); 132 } 133 134 /** 135 * Ensures that no VR-related activity is currently being displayed. This is meant to be used 136 * by TestRules before starting any activities. Having a VR activity in the foreground (e.g. 137 * Daydream Home) has the potential to affect test results, as it often means that we are in VR 138 * at the beginning of the test, which we don't want. This is most commonly caused by VrCore 139 * automatically launching Daydream Home when Chrome gets closed after a test, but can happen 140 * for other reasons as well. 141 */ ensureNoVrActivitiesDisplayed()142 public static void ensureNoVrActivitiesDisplayed() { 143 // This will always be hit on standalones, but we're expected to be in VR in that case. 144 if (TestVrShellDelegate.isOnStandalone()) return; 145 UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 146 String currentPackageName = uiDevice.getCurrentPackageName(); 147 if (currentPackageName != null && currentPackageName.contains("vr")) { 148 uiDevice.pressHome(); 149 // Chrome startup would likely be slow enough that this sleep is unnecessary, but sleep 150 // to be sure since this will be hit relatively infrequently. 151 SystemClock.sleep(VRCORE_UNREGISTER_DELAY_MS); 152 } 153 } 154 155 /** 156 * Helper method to add additional data to a Chrome startup intent that makes it usable on a 157 * standalone VR device. 158 */ maybeAddStandaloneIntentData(Intent intent)159 public static Intent maybeAddStandaloneIntentData(Intent intent) { 160 if (TestVrShellDelegate.isOnStandalone()) { 161 // Tell VrShellDelegate that it should create a TestVrShellDelegate on startup 162 TestVrShellDelegate.enableTestVrShellDelegateOnStartupForTesting(); 163 intent.addCategory(VrIntentDelegate.DAYDREAM_CATEGORY); 164 intent.putExtra("android.intent.extra.VR_LAUNCH", true); 165 } 166 return intent; 167 } 168 } 169