Commit dd789ac6 authored by bsheedy's avatar bsheedy Committed by Commit Bot

Add TestVrShellDelegate

This adds TestVrShellDelegate, which extends VrShellDelegate and does
two things:
1. Removes the need for @VisibleForTesting annotations in
  VrShellDelegate.
2. Allows us to have test-only code for VrShellDelegate without
  affecting production code if necessary.

Bug: 775259
Change-Id: I1bb4beed2d88ba774a3fe28fa6799e0b8bee1113
Reviewed-on: https://chromium-review.googlesource.com/723769Reviewed-by: default avataragrieve <agrieve@chromium.org>
Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#510121}
parent 8e6d7b60
......@@ -594,6 +594,7 @@ if (enable_vr) {
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrShellDelegateUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTestRuleUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/TestVrShellDelegate.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrFeedbackInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellCompositorViewHolderTest.java",
......
......@@ -22,7 +22,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.support.annotation.IntDef;
import android.support.annotation.VisibleForTesting;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
......@@ -135,9 +134,9 @@ public class VrShellDelegate
private VrCoreVersionChecker mVrCoreVersionChecker;
private TabModelSelector mTabModelSelector;
private boolean mProbablyInDon;
private boolean mInVr;
private final Handler mExpectPauseOrDonSucceeded;
private boolean mProbablyInDon;
private boolean mNeedsAnimationCancel;
private boolean mCancellingEntryAnimation;
......@@ -275,13 +274,7 @@ public class VrShellDelegate
if (sInstance != null) sInstance.cancelStartupAnimationIfNeeded();
}
@VisibleForTesting
public static VrShellDelegate getInstanceForTesting() {
return getInstance();
}
@VisibleForTesting
public static boolean isDisplayingUrlForTesting() {
protected static boolean isDisplayingUrl() {
if (sInstance == null) return false;
return sInstance.mVrShell.isDisplayingUrlForTesting();
}
......@@ -485,7 +478,7 @@ public class VrShellDelegate
* @return A helper class for creating VR-specific classes that may not be available at compile
* time.
*/
private static VrClassesWrapper getVrClassesWrapper() {
protected static VrClassesWrapper getVrClassesWrapper() {
if (sInstance != null) return sInstance.mVrClassesWrapper;
return createVrClassesWrapper();
}
......@@ -606,7 +599,7 @@ public class VrShellDelegate
sVrBroadcastReceiver = null;
}
private VrShellDelegate(ChromeActivity activity, VrClassesWrapper wrapper) {
protected VrShellDelegate(ChromeActivity activity, VrClassesWrapper wrapper) {
mActivity = activity;
mVrClassesWrapper = wrapper;
// If an activity isn't resumed at the point, it must have been paused.
......@@ -619,6 +612,7 @@ public class VrShellDelegate
mExpectPauseOrDonSucceeded = new Handler();
ApplicationStatus.registerStateListenerForAllActivities(this);
if (!mPaused) onResume();
sInstance = this;
}
@Override
......@@ -1067,7 +1061,7 @@ public class VrShellDelegate
return true;
}
private void onResume() {
protected void onResume() {
if (cancelStartupAnimationIfNeeded()) return;
mPaused = false;
......@@ -1098,6 +1092,7 @@ public class VrShellDelegate
} else if (mProbablyInDon) {
// This means the user backed out of the DON flow, and we won't be entering VR.
maybeSetPresentResult(false, mDonSucceeded);
shutdownVr(true, false);
mWaitingForVrTimeout = true;
new Handler().postDelayed(new Runnable() {
......@@ -1149,7 +1144,7 @@ public class VrShellDelegate
shutdownVr(true /* disableVrMode */, false /* stayingInChrome */);
}
private void onPause() {
protected void onPause() {
mPaused = true;
if (mCancellingEntryAnimation) return;
mExpectPauseOrDonSucceeded.removeCallbacksAndMessages(null);
......@@ -1272,8 +1267,7 @@ public class VrShellDelegate
/**
* Exits VR Shell, performing all necessary cleanup.
*/
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
protected void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
cancelPendingVrEntry();
// Ensure shutdownVr runs if we're stopping.
if (handleFinishAutopresentation() && !mStopped) return;
......@@ -1560,24 +1554,21 @@ public class VrShellDelegate
/**
* @param api The VrDaydreamApi object this delegate will use instead of the default one
*/
@VisibleForTesting
public void overrideDaydreamApiForTesting(VrDaydreamApi api) {
protected void overrideDaydreamApi(VrDaydreamApi api) {
mVrDaydreamApi = api;
}
/**
* @return The VrShell for the VrShellDelegate instance
*/
@VisibleForTesting
public static VrShell getVrShellForTesting() {
protected static VrShell getVrShell() {
return sInstance == null ? null : sInstance.mVrShell;
}
/**
* @param versionChecker The VrCoreVersionChecker object this delegate will use
*/
@VisibleForTesting
public void overrideVrCoreVersionCheckerForTesting(VrCoreVersionChecker versionChecker) {
protected void overrideVrCoreVersionChecker(VrCoreVersionChecker versionChecker) {
mVrCoreVersionChecker = versionChecker;
updateVrSupportLevel(null);
}
......@@ -1585,27 +1576,31 @@ public class VrShellDelegate
/**
* @param frequency Sets how often to show the feedback prompt.
*/
@VisibleForTesting
public void setFeedbackFrequencyForTesting(int frequency) {
protected void setFeedbackFrequency(int frequency) {
mFeedbackFrequency = frequency;
}
@VisibleForTesting
public boolean isListeningForWebVrActivate() {
protected boolean isListeningForWebVrActivate() {
return mListeningForWebVrActivate;
}
@VisibleForTesting
public boolean isClearActivatePending() {
protected boolean isClearActivatePending() {
assert mNativeVrShellDelegate != 0;
return nativeIsClearActivatePending(mNativeVrShellDelegate);
}
@VisibleForTesting
public boolean isVrEntryComplete() {
protected boolean isVrEntryComplete() {
return mInVr && !mProbablyInDon;
}
protected boolean getProbablyInDon() {
return mProbablyInDon;
}
protected boolean getDonSucceeded() {
return mDonSucceeded;
}
/**
* @return Pointer to the native VrShellDelegate object.
*/
......
// Copyright 2017 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_shell;
import android.os.Handler;
import org.junit.Assert;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.ChromeActivity;
/**
* Class for accessing VrShellDelegate internals for testing purposes.
* This does two things:
* - Prevents us from needing @VisibleForTesting annotations everywhere in production code
* - Allows us to have test-specific behavior if necessary without changing production code
*/
public class TestVrShellDelegate extends VrShellDelegate {
// Arbitrary but valid delay to make sure that we actually did cancel the DON flow instead of
// running into crbug.com/762724
private static final int DON_CANCEL_DELAY_MS = 200;
private boolean mOnResumeCalled;
private static TestVrShellDelegate sInstance;
protected TestVrShellDelegate(ChromeActivity activity) {
super(activity, VrShellDelegate.getVrClassesWrapper());
}
public static void createTestVrShellDelegate(final ChromeActivity activity) {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
sInstance = new TestVrShellDelegate(activity);
}
});
}
public static TestVrShellDelegate getInstance() {
return sInstance;
}
public static boolean isDisplayingUrlForTesting() {
return VrShellDelegate.isDisplayingUrl();
}
public static VrShell getVrShellForTesting() {
return VrShellDelegate.getVrShell();
}
public void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
super.shutdownVr(disableVrMode, stayingInChrome);
}
public void overrideDaydreamApiForTesting(VrDaydreamApi api) {
super.overrideDaydreamApi(api);
}
public void overrideVrCoreVersionCheckerForTesting(VrCoreVersionChecker versionChecker) {
super.overrideVrCoreVersionChecker(versionChecker);
}
public void setFeedbackFrequencyForTesting(int frequency) {
super.setFeedbackFrequency(frequency);
}
public boolean isListeningForWebVrActivate() {
return super.isListeningForWebVrActivate();
}
public boolean isClearActivatePending() {
return super.isClearActivatePending();
}
public boolean isVrEntryComplete() {
return super.isVrEntryComplete();
}
/**
* Wait a short period of time before running if we think the DON flow was cancelled.
*
* The same as the production onResume, except that in the case of mProbablyInDon still being
* set, the decision that the DON flow was cancelled is delayed until later to see if the
* broadcast is just late. This is caused by crbug.com/762724.
* TODO(bsheedy): Remove this when the root cause is fixed.
*/
@Override
protected void onResume() {
if (!getDonSucceeded() && getProbablyInDon()) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
TestVrShellDelegate.super.onResume();
mOnResumeCalled = true;
}
}, DON_CANCEL_DELAY_MS);
} else {
super.onResume();
mOnResumeCalled = true;
}
}
/**
* Make sure that onResume is called before onPause.
*
* This is necessary since we don't want weird problems to show up caused by the delayed
* onResume being called after onPause.
*/
@Override
protected void onPause() {
Assert.assertTrue(mOnResumeCalled);
mOnResumeCalled = false;
super.onPause();
}
}
\ No newline at end of file
......@@ -135,7 +135,7 @@ public class VrFeedbackInfoBarTest {
VrTransitionUtils.enterPresentationAndWait(
mVrTestFramework.getFirstTabCvc(), mVrTestFramework.getFirstTabWebContents());
assertState(true /* isInVr */, false /* isInfobarVisible */);
Assert.assertTrue(VrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
// Exiting VR should not prompt for feedback since the no VR browsing was performed.
VrTransitionUtils.forceExitVr();
......@@ -156,7 +156,7 @@ public class VrFeedbackInfoBarTest {
VrTransitionUtils.enterPresentationAndWait(
mVrTestFramework.getFirstTabCvc(), mVrTestFramework.getFirstTabWebContents());
assertState(true /* isInVr */, false /* isInfobarVisible */);
Assert.assertTrue(VrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
// Exit presentation mode by navigating to a different url.
ChromeTabUtils.waitForTabPageLoaded(
......
......@@ -65,25 +65,25 @@ public class VrShellNativeUiTest {
throws IllegalArgumentException, InterruptedException, TimeoutException {
mVrTestRule.loadUrl(BOOKMARKS_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(BOOKMARKS_FOLDER_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(BOOKMARKS_UNCATEGORIZED_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(DOWNLOADS_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(NTP_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(NATIVE_HISTORY_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
mVrTestRule.loadUrl(RECENT_TABS_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertFalse(
"Should not be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
"Should not be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
}
/**
......@@ -94,6 +94,6 @@ public class VrShellNativeUiTest {
public void testUrlOnNonNativeUi()
throws IllegalArgumentException, InterruptedException, TimeoutException {
mVrTestRule.loadUrl(TEST_PAGE_2D_URL, PAGE_LOAD_TIMEOUT_S);
Assert.assertTrue("Should be showing URL", VrShellDelegate.isDisplayingUrlForTesting());
Assert.assertTrue("Should be showing URL", TestVrShellDelegate.isDisplayingUrlForTesting());
}
}
......@@ -113,7 +113,7 @@ public class VrShellNavigationTest {
Assert.assertEquals("Browser is on correct web site", getUrl(page), wc.getVisibleUrl());
Assert.assertEquals("Browser is in VR Presentation Mode",
presentationMode == PresentationMode.PRESENTING,
VrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
Assert.assertEquals("Browser is in fullscreen",
fullscreenMode == FullscreenMode.FULLSCREENED, DOMUtils.isFullscreen(wc));
// Feedback infobar should never show up during navigations.
......
......@@ -181,7 +181,7 @@ public class VrShellTransitionTest {
VrTransitionUtils.waitForVrEntry(POLL_TIMEOUT_LONG_MS);
mVrTestFramework.loadUrlAndAwaitInitialization(
VrTestFramework.getHtmlTestFile("test_navigation_webvr_page"), PAGE_LOAD_TIMEOUT_S);
VrShellImpl vrShellImpl = (VrShellImpl) VrShellDelegate.getVrShellForTesting();
VrShellImpl vrShellImpl = (VrShellImpl) TestVrShellDelegate.getVrShellForTesting();
float expectedWidth = vrShellImpl.getContentWidthForTesting();
float expectedHeight = vrShellImpl.getContentHeightForTesting();
VrTransitionUtils.enterPresentationOrFail(mVrTestFramework.getFirstTabCvc());
......
......@@ -37,6 +37,7 @@ import org.chromium.base.test.util.Restriction;
import org.chromium.base.test.util.RetryOnFailure;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.vr_shell.util.VrShellDelegateUtils;
import org.chromium.chrome.browser.vr_shell.util.VrTestRuleUtils;
import org.chromium.chrome.browser.vr_shell.util.VrTransitionUtils;
import org.chromium.chrome.test.ChromeActivityTestRule;
......@@ -97,7 +98,7 @@ public class WebVrInputTest {
// Wait on VrShellImpl to say that its parent consumed the touch event
// Set to 2 because there's an ACTION_DOWN followed by ACTION_UP
final CountDownLatch touchRegisteredLatch = new CountDownLatch(2);
((VrShellImpl) VrShellDelegate.getVrShellForTesting())
((VrShellImpl) TestVrShellDelegate.getVrShellForTesting())
.setOnDispatchTouchEventForTesting(new OnDispatchTouchEventCallback() {
@Override
public void onDispatchTouchEvent(boolean parentConsumed) {
......@@ -156,7 +157,7 @@ public class WebVrInputTest {
// TODO(mthiesse, crbug.com/758374): Injecting touch events into the root GvrLayout
// (VrShellImpl) is flaky. Sometimes the events just don't get routed to the presentation
// view for no apparent reason. We should figure out why this is and see if it's fixable.
final View presentationView = ((VrShellImpl) VrShellDelegate.getVrShellForTesting())
final View presentationView = ((VrShellImpl) TestVrShellDelegate.getVrShellForTesting())
.getPresentationViewForTesting();
long downTime = SystemClock.uptimeMillis();
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
......@@ -245,14 +246,15 @@ public class WebVrInputTest {
CriteriaHelper.pollUiThread(new Criteria("DisplayActivate was never registered.") {
@Override
public boolean isSatisfied() {
return VrShellDelegate.getInstanceForTesting().isListeningForWebVrActivate();
return VrShellDelegateUtils.getDelegateInstance().isListeningForWebVrActivate();
}
}, POLL_TIMEOUT_LONG_MS, POLL_CHECK_INTERVAL_SHORT_MS);
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
mVrTestRule.getActivity().getCurrentContentViewCore().onPause();
Assert.assertTrue(VrShellDelegate.getInstanceForTesting().isClearActivatePending());
Assert.assertTrue(
VrShellDelegateUtils.getDelegateInstance().isClearActivatePending());
}
});
}
......
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.vr_shell.rules;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction.SupportedActivity;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
......@@ -22,6 +23,7 @@ public class ChromeTabbedActivityVrTestRule
@Override
public void evaluate() throws Throwable {
startMainActivityOnBlankPage();
TestVrShellDelegate.createTestVrShellDelegate(getActivity());
base.evaluate();
}
}, desc);
......
......@@ -11,6 +11,7 @@ import org.junit.runners.model.Statement;
import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction.SupportedActivity;
/**
......@@ -25,6 +26,7 @@ public class CustomTabActivityVrTestRule extends CustomTabActivityTestRule imple
public void evaluate() throws Throwable {
startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
InstrumentationRegistry.getTargetContext(), "about:blank"));
TestVrShellDelegate.createTestVrShellDelegate(getActivity());
base.evaluate();
}
}, desc);
......
......@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.vr_shell.rules;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction.SupportedActivity;
import org.chromium.chrome.browser.webapps.WebappActivityTestRule;
......@@ -21,6 +22,7 @@ public class WebappActivityVrTestRule extends WebappActivityTestRule implements
@Override
public void evaluate() throws Throwable {
startWebappActivity();
TestVrShellDelegate.createTestVrShellDelegate(getActivity());
base.evaluate();
}
}, desc);
......
......@@ -5,7 +5,7 @@
package org.chromium.chrome.browser.vr_shell.util;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.vr_shell.VrShellDelegate;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import java.util.concurrent.atomic.AtomicReference;
......@@ -19,12 +19,13 @@ public class VrShellDelegateUtils {
* This is necessary in case acquiring the instance causes the delegate
* to be constructed, which must happen on the UI thread.
*/
public static VrShellDelegate getDelegateInstance() {
final AtomicReference<VrShellDelegate> delegate = new AtomicReference<VrShellDelegate>();
public static TestVrShellDelegate getDelegateInstance() {
final AtomicReference<TestVrShellDelegate> delegate =
new AtomicReference<TestVrShellDelegate>();
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
delegate.set(VrShellDelegate.getInstanceForTesting());
delegate.set(TestVrShellDelegate.getInstance());
}
});
return delegate.get();
......
......@@ -18,6 +18,7 @@ import org.junit.Assert;
import org.chromium.base.ContextUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import org.chromium.chrome.browser.vr_shell.VrClassesWrapperImpl;
import org.chromium.chrome.browser.vr_shell.VrIntentUtils;
import org.chromium.chrome.browser.vr_shell.VrShellDelegate;
......@@ -77,7 +78,7 @@ public class VrTransitionUtils {
CriteriaHelper.pollUiThread(Criteria.equals(true, new Callable<Boolean>() {
@Override
public Boolean call() {
return VrShellDelegate.getInstanceForTesting().isVrEntryComplete();
return VrShellDelegateUtils.getDelegateInstance().isVrEntryComplete();
}
}), timeout, POLL_CHECK_INTERVAL_SHORT_MS);
}
......@@ -123,7 +124,7 @@ public class VrTransitionUtils {
enterPresentation(cvc);
Assert.assertTrue(VrTestFramework.pollJavaScriptBoolean(
"vrDisplay.isPresenting", POLL_TIMEOUT_LONG_MS, cvc.getWebContents()));
Assert.assertTrue(VrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
}
/**
......@@ -135,7 +136,7 @@ public class VrTransitionUtils {
@Override
public void run() {
isBackButtonEnabled.set(
VrShellDelegate.getVrShellForTesting().isBackButtonEnabled());
TestVrShellDelegate.getVrShellForTesting().isBackButtonEnabled());
}
});
return isBackButtonEnabled.get();
......@@ -150,7 +151,7 @@ public class VrTransitionUtils {
@Override
public void run() {
isForwardButtonEnabled.set(
VrShellDelegate.getVrShellForTesting().isForwardButtonEnabled());
TestVrShellDelegate.getVrShellForTesting().isForwardButtonEnabled());
}
});
return isForwardButtonEnabled.get();
......@@ -163,7 +164,7 @@ public class VrTransitionUtils {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
VrShellDelegate.getVrShellForTesting().navigateBack();
TestVrShellDelegate.getVrShellForTesting().navigateBack();
}
});
}
......@@ -175,7 +176,7 @@ public class VrTransitionUtils {
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
VrShellDelegate.getVrShellForTesting().navigateForward();
TestVrShellDelegate.getVrShellForTesting().navigateForward();
}
});
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment