Automated VR keyboard update prompt tests
Automates the two manual tests for ensuring that attempting to use
keyboard input while in the VR browser without the keyboard APK
installed triggers a DOFF prompt to install or updated the APK.
As a side effect, also adds the ability to wait for an element
in the native UI to change visibility.
Bug: 887588
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:linux_vr;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Ie4e08317c82fc2f4cc5379a5d18a82994f34a804
Reviewed-on: https://chromium-review.googlesource.com/c/1246279
Commit-Queue: Brian Sheedy <[email protected]>
Reviewed-by: Aldo Culquicondor <[email protected]>
Reviewed-by: Michael Thiessen <[email protected]>
Cr-Commit-Position: refs/heads/master@{#595916}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
index ea181134..b8d08db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -1252,7 +1252,7 @@
}
public void registerUiOperationCallbackForTesting(
- int actionType, Runnable resultCallback, int quiescenceTimeoutMs) {
+ int actionType, Runnable resultCallback, int timeoutMs, int elementName) {
assert actionType < UiTestOperationType.NUM_UI_TEST_OPERATION_TYPES;
// Fill the ArrayLists if this is the first time the method has been called.
if (mUiOperationResults == null) {
@@ -1265,16 +1265,15 @@
mUiOperationResultCallbacks.add(null);
}
}
- // We currently have two callback types, and only one of them actually cares about the
- // value given to the callback, so we can blindly set the default here. If more are added,
- // their defaults will have to be properly set here.
- mUiOperationResults.set(actionType, VrUiTestActivityResult.UNREPORTED);
+ mUiOperationResults.set(actionType, UiTestOperationResult.UNREPORTED);
mUiOperationResultCallbacks.set(actionType, resultCallback);
// In the case of the UI activity quiescence callback type, we need to let the native UI
// know how long to wait before timing out.
if (actionType == UiTestOperationType.UI_ACTIVITY_RESULT) {
- nativeSetUiExpectingActivityForTesting(mNativeVrShell, quiescenceTimeoutMs);
+ nativeSetUiExpectingActivityForTesting(mNativeVrShell, timeoutMs);
+ } else if (actionType == UiTestOperationType.ELEMENT_VISIBILITY_CHANGE) {
+ nativeWatchElementForVisibilityChangeForTesting(mNativeVrShell, elementName, timeoutMs);
}
}
@@ -1344,6 +1343,8 @@
long nativeVrShell, int quiescenceTimeoutMs);
private native void nativeSaveNextFrameBufferToDiskForTesting(
long nativeVrShell, String filepathBase);
+ private native void nativeWatchElementForVisibilityChangeForTesting(
+ long nativeVrShell, int elementName, int timeoutMs);
private native void nativeResumeContentRendering(long nativeVrShell);
private native void nativeOnOverlayTextureEmptyChanged(long nativeVrShell, boolean empty);
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java
index 347c2be..39dfa74 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/keyboard/GvrKeyboardLoaderClient.java
@@ -17,6 +17,7 @@
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
@@ -31,6 +32,7 @@
private static IGvrKeyboardLoader sLoader;
private static ClassLoader sRemoteClassLoader;
+ private static boolean sFailLoadForTesting;
// GVR doesn't support setting the context twice in the application's lifetime and crashes if we
// do so. Setting the same context wrapper is a no-op, so we keep a reference to the one we
// create and use it across re-initialization of the keyboard api.
@@ -67,7 +69,13 @@
}
}
+ @VisibleForTesting
+ public static void setFailLoadForTesting(boolean shouldFail) {
+ sFailLoadForTesting = shouldFail;
+ }
+
private static IGvrKeyboardLoader getLoader() {
+ if (sFailLoadForTesting) return null;
if (sLoader == null) {
ClassLoader remoteClassLoader = (ClassLoader) getRemoteClassLoader();
if (remoteClassLoader != null) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
index c8e4fee8..9302b9e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -95,9 +95,9 @@
}
public void registerUiOperationCallbackForTesting(
- int actionType, Runnable resultCallback, int quiescenceTimeoutMs) {
+ int actionType, Runnable resultCallback, int timeoutMs, int elementName) {
getVrShell().registerUiOperationCallbackForTesting(
- actionType, resultCallback, quiescenceTimeoutMs);
+ actionType, resultCallback, timeoutMs, elementName);
}
public void saveNextFrameBufferToDiskForTesting(String filepathBase) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
index e1539b1..3cd7df9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrInstallUpdateInfoBarTest.java
@@ -4,8 +4,12 @@
package org.chromium.chrome.browser.vr;
+import static org.chromium.chrome.browser.vr.XrTestFramework.PAGE_LOAD_TIMEOUT_S;
+import static org.chromium.chrome.browser.vr.XrTestFramework.POLL_TIMEOUT_LONG_MS;
import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_SVR;
+import static org.chromium.chrome.test.util.ChromeRestriction.RESTRICTION_TYPE_VIEWER_DAYDREAM;
+import android.graphics.PointF;
import android.os.Build;
import android.support.test.filters.MediumTest;
import android.view.View;
@@ -26,7 +30,10 @@
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.vr.keyboard.GvrKeyboardLoaderClient;
import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
+import org.chromium.chrome.browser.vr.util.NativeUiUtils;
+import org.chromium.chrome.browser.vr.util.VrBrowserTransitionUtils;
import org.chromium.chrome.browser.vr.util.VrInfoBarUtils;
import org.chromium.chrome.browser.vr.util.VrShellDelegateUtils;
import org.chromium.chrome.browser.vr.util.VrTestRuleUtils;
@@ -39,7 +46,7 @@
/**
* End-to-end tests for the InfoBar that prompts the user to update or install
* VrCore (VR Services) when attempting to use a VR feature with an outdated
- * or entirely missing version.
+ * or entirely missing version or other VR-related update prompts.
*/
@RunWith(ParameterizedRunner.class)
@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
@@ -143,4 +150,49 @@
public void testInfoBarNotPresentWhenVrServicesNotSupported() throws InterruptedException {
infoBarTestHelper(VrCoreCompatibility.VR_NOT_SUPPORTED);
}
+
+ /**
+ * Tests that the install/upgrade prompt for the keyboard appears when clicking on the URL
+ * bar without the keyboard installed.
+ */
+ @Test
+ @MediumTest
+ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+ public void testKeyboardInstallUpgradePromptUrlBar() throws InterruptedException {
+ testKeyboardInstallUpgradeImpl(UserFriendlyElementName.URL);
+ }
+
+ /**
+ * Tests that the install/upgrade prompt for the keyboard appears when interacting with a web
+ * text input field without the keyboard installed.
+ */
+ @Test
+ @MediumTest
+ @Restriction(RESTRICTION_TYPE_VIEWER_DAYDREAM)
+ public void testKeyboardInstallUpgradePromptWebInput() throws InterruptedException {
+ testKeyboardInstallUpgradeImpl(UserFriendlyElementName.CONTENT_QUAD);
+ }
+
+ private void testKeyboardInstallUpgradeImpl(final int uiElementToClick)
+ throws InterruptedException {
+ mVrTestRule.loadUrl(
+ VrBrowserTestFramework.getFileUrlForHtmlTestFile("test_web_input_editing"),
+ PAGE_LOAD_TIMEOUT_S);
+ GvrKeyboardLoaderClient.setFailLoadForTesting(true);
+ VrBrowserTransitionUtils.forceEnterVrBrowserOrFail(POLL_TIMEOUT_LONG_MS);
+ // The prompt takes significantly longer to show when clicking on the web content, so we
+ // can't just wait for quiescence since that gets reached before the prompt shows (not sure
+ // what's causing a UI change other than the prompt). Instead, explicitly wait for the
+ // prompt to become visible before waiting for quiescence.
+ NativeUiUtils.performActionAndWaitForUiQuiescence(() -> {
+ try {
+ NativeUiUtils.performActionAndWaitForVisibilityChange(
+ UserFriendlyElementName.EXIT_PROMPT,
+ () -> { NativeUiUtils.clickElement(uiElementToClick, new PointF()); });
+ } catch (InterruptedException e) {
+ Assert.fail("Interrupted while waiting for UI visibility change");
+ }
+
+ });
+ }
}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
index a882d22..fbeead5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/NativeUiUtils.java
@@ -15,12 +15,12 @@
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.vr.TestVrShellDelegate;
+import org.chromium.chrome.browser.vr.UiTestOperationResult;
import org.chromium.chrome.browser.vr.UiTestOperationType;
import org.chromium.chrome.browser.vr.UserFriendlyElementName;
import org.chromium.chrome.browser.vr.VrControllerTestAction;
import org.chromium.chrome.browser.vr.VrDialog;
import org.chromium.chrome.browser.vr.VrShell;
-import org.chromium.chrome.browser.vr.VrUiTestActivityResult;
import org.chromium.chrome.browser.vr.VrViewContainer;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
@@ -139,8 +139,10 @@
// Run on the UI thread to prevent issues with registering a new callback before
// ReportUiOperationResultForTesting has finished.
ThreadUtils.runOnUiThreadBlocking(() -> {
- instance.registerUiOperationCallbackForTesting(UiTestOperationType.UI_ACTIVITY_RESULT,
- () -> { resultLatch.countDown(); }, DEFAULT_UI_QUIESCENCE_TIMEOUT_MS);
+ instance.registerUiOperationCallbackForTesting(
+ UiTestOperationType.UI_ACTIVITY_RESULT, () -> {
+ resultLatch.countDown();
+ }, DEFAULT_UI_QUIESCENCE_TIMEOUT_MS, 0 /* unused */);
});
action.run();
@@ -149,8 +151,37 @@
int uiResult =
instance.getLastUiOperationResultForTesting(UiTestOperationType.UI_ACTIVITY_RESULT);
Assert.assertEquals("UI reported non-quiescent result '"
- + vrUiTestActivityResultToString(uiResult) + "'",
- VrUiTestActivityResult.QUIESCENT, uiResult);
+ + uiTestOperationResultToString(uiResult) + "'",
+ UiTestOperationResult.QUIESCENT, uiResult);
+ }
+
+ /**
+ * Runs the given Runnable and waits until the specified element changes its visibility.
+ *
+ * @param elementName The UserFriendlyElementName to wait on to change visibility.
+ * @param action A Runnable containing the action to perform.
+ */
+ public static void performActionAndWaitForVisibilityChange(
+ final int elementName, Runnable action) throws InterruptedException {
+ final TestVrShellDelegate instance = TestVrShellDelegate.getInstance();
+ final CountDownLatch resultLatch = new CountDownLatch(1);
+ // Run on the UI thread to prevent issues with registering a new callback before
+ // ReportUiOperationResultForTesting has finished.
+ ThreadUtils.runOnUiThreadBlocking(() -> {
+ instance.registerUiOperationCallbackForTesting(
+ UiTestOperationType.ELEMENT_VISIBILITY_CHANGE, () -> {
+ resultLatch.countDown();
+ }, DEFAULT_UI_QUIESCENCE_TIMEOUT_MS, elementName);
+ });
+ action.run();
+
+ // Wait for the result to be reported.
+ resultLatch.await();
+ int result = instance.getLastUiOperationResultForTesting(
+ UiTestOperationType.ELEMENT_VISIBILITY_CHANGE);
+ Assert.assertEquals("UI reported non-visibility-changed result '"
+ + uiTestOperationResultToString(result) + "'",
+ UiTestOperationResult.VISIBILITY_CHANGE, result);
}
/**
@@ -197,7 +228,7 @@
// ReportUiOperationResultForTesting has finished.
ThreadUtils.runOnUiThreadBlocking(() -> {
instance.registerUiOperationCallbackForTesting(UiTestOperationType.FRAME_BUFFER_DUMPED,
- () -> { resultLatch.countDown(); }, 0 /* unused */);
+ () -> { resultLatch.countDown(); }, 0 /* unused */, 0 /* unused */);
});
instance.saveNextFrameBufferToDiskForTesting(filepathBase);
resultLatch.await();
@@ -244,16 +275,20 @@
clickElementAndWaitForUiQuiescence(UserFriendlyElementName.BROWSING_DIALOG, buttonCenter);
}
- private static String vrUiTestActivityResultToString(int result) {
+ private static String uiTestOperationResultToString(int result) {
switch (result) {
- case VrUiTestActivityResult.UNREPORTED:
+ case UiTestOperationResult.UNREPORTED:
return "Unreported";
- case VrUiTestActivityResult.QUIESCENT:
+ case UiTestOperationResult.QUIESCENT:
return "Quiescent";
- case VrUiTestActivityResult.TIMEOUT_NO_START:
+ case UiTestOperationResult.TIMEOUT_NO_START:
return "Timeout (UI activity not started)";
- case VrUiTestActivityResult.TIMEOUT_NO_END:
+ case UiTestOperationResult.TIMEOUT_NO_END:
return "Timeout (UI activity not stopped)";
+ case UiTestOperationResult.VISIBILITY_CHANGE:
+ return "Visibility change";
+ case UiTestOperationResult.TIMEOUT_NO_CHANGE:
+ return "Timeout (Element visibility did not change)";
default:
return "Unknown result";
}
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc
index 623ba72..abb2294 100644
--- a/chrome/browser/android/vr/vr_gl_thread.cc
+++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -518,7 +518,7 @@
void VrGLThread::ReportUiOperationResultForTesting(
const UiTestOperationType& action_type,
- const VrUiTestActivityResult& result) {
+ const UiTestOperationResult& result) {
DCHECK(OnGlThread());
main_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&VrShell::ReportUiOperationResultForTesting,
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index 120bee4..a1f4b211 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -78,7 +78,7 @@
void ForceExitVr() override;
void ReportUiOperationResultForTesting(
const UiTestOperationType& action_type,
- const VrUiTestActivityResult& result) override;
+ const UiTestOperationResult& result) override;
// PlatformInputHandler
void ForwardEventToPlatformUi(std::unique_ptr<InputEvent> event) override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 79b864c..181b8765 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -1280,8 +1280,24 @@
base::android::ConvertJavaStringToUTF8(env, filepath_base)));
}
+void VrShell::WatchElementForVisibilityChangeForTesting(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jint element_name,
+ jint timeout_ms) {
+ VisibilityChangeExpectation visibility_expectation;
+ visibility_expectation.element_name =
+ static_cast<UserFriendlyElementName>(element_name);
+ visibility_expectation.timeout_ms = timeout_ms;
+ PostToGlThread(
+ FROM_HERE,
+ base::BindOnce(
+ &BrowserRenderer::WatchElementForVisibilityChangeForTesting,
+ gl_thread_->GetBrowserRenderer(), visibility_expectation));
+}
+
void VrShell::ReportUiOperationResultForTesting(UiTestOperationType action_type,
- VrUiTestActivityResult result) {
+ UiTestOperationResult result) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_VrShell_reportUiOperationResultForTesting(env, j_vr_shell_,
static_cast<int>(action_type),
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h
index 043cbe3..973f634 100644
--- a/chrome/browser/android/vr/vr_shell.h
+++ b/chrome/browser/android/vr/vr_shell.h
@@ -57,7 +57,7 @@
class VrShellDelegate;
class VrWebContentsObserver;
enum class UiTestOperationType;
-enum class VrUiTestActivityResult;
+enum class UiTestOperationResult;
struct Assets;
struct AutocompleteRequest;
@@ -286,8 +286,14 @@
const base::android::JavaParamRef<jobject>& obj,
jstring filepath_base);
+ void WatchElementForVisibilityChangeForTesting(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ jint element_name,
+ jint timeout_ms);
+
void ReportUiOperationResultForTesting(UiTestOperationType action_type,
- VrUiTestActivityResult result);
+ UiTestOperationResult result);
void PerformControllerActionForTesting(
JNIEnv* env,
diff --git a/chrome/browser/vr/browser_renderer.cc b/chrome/browser/vr/browser_renderer.cc
index e81b8c6..cd9fcc76 100644
--- a/chrome/browser/vr/browser_renderer.cc
+++ b/chrome/browser/vr/browser_renderer.cc
@@ -256,6 +256,19 @@
frame_buffer_dump_filepath_base_ = filepath_base;
}
+void BrowserRenderer::WatchElementForVisibilityChangeForTesting(
+ VisibilityChangeExpectation visibility_expectation) {
+ DCHECK(ui_visibility_state_ == nullptr) << "Attempted to watch a UI element "
+ "for visibility changes with one "
+ "in progress";
+ ui_visibility_state_ = std::make_unique<UiVisibilityState>();
+ ui_visibility_state_->timeout_ms =
+ base::TimeDelta::FromMilliseconds(visibility_expectation.timeout_ms);
+ ui_visibility_state_->element_to_watch = visibility_expectation.element_name;
+ ui_visibility_state_->initially_visible = ui_->GetElementVisibilityForTesting(
+ ui_visibility_state_->element_to_watch);
+}
+
void BrowserRenderer::AcceptDoffPromptForTesting() {
ui_->AcceptDoffPromptForTesting();
}
@@ -283,6 +296,7 @@
ui_updated = true;
}
ReportUiStatusForTesting(timing_start, ui_updated);
+ ReportElementVisibilityStatusForTesting(timing_start);
base::TimeDelta scene_time = base::TimeTicks::Now() - timing_start;
// Don't double-count the controller time that was part of the scene time.
@@ -374,16 +388,16 @@
if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
// The UI is being updated, but hasn't reached a stable state in the
// given time -> report timeout.
- ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoEnd);
+ ReportUiActivityResultForTesting(UiTestOperationResult::kTimeoutNoEnd);
}
} else {
if (ui_test_state_->activity_started) {
// The UI has been updated since the test requested notification of
// quiescence, but wasn't this frame -> report that the UI is quiescent.
- ReportUiActivityResultForTesting(VrUiTestActivityResult::kQuiescent);
+ ReportUiActivityResultForTesting(UiTestOperationResult::kQuiescent);
} else if (time_since_start > ui_test_state_->quiescence_timeout_ms) {
// The UI has never been updated and we've reached the timeout.
- ReportUiActivityResultForTesting(VrUiTestActivityResult::kTimeoutNoStart);
+ ReportUiActivityResultForTesting(UiTestOperationResult::kTimeoutNoStart);
}
}
}
@@ -393,7 +407,7 @@
}
void BrowserRenderer::ReportUiActivityResultForTesting(
- VrUiTestActivityResult result) {
+ UiTestOperationResult result) {
ui_test_state_ = nullptr;
browser_->ReportUiOperationResultForTesting(
UiTestOperationType::kUiActivityResult, result);
@@ -406,7 +420,31 @@
frame_buffer_dump_filepath_base_.clear();
browser_->ReportUiOperationResultForTesting(
UiTestOperationType::kFrameBufferDumped,
- VrUiTestActivityResult::kQuiescent /* unused */);
+ UiTestOperationResult::kQuiescent /* unused */);
+}
+
+void BrowserRenderer::ReportElementVisibilityStatusForTesting(
+ const base::TimeTicks& current_time) {
+ if (ui_visibility_state_ == nullptr)
+ return;
+ base::TimeDelta time_since_start =
+ current_time - ui_visibility_state_->start_time;
+ if (ui_->GetElementVisibilityForTesting(
+ ui_visibility_state_->element_to_watch) !=
+ ui_visibility_state_->initially_visible) {
+ ReportElementVisibilityResultForTesting(
+ UiTestOperationResult::kVisibilityChange);
+ } else if (time_since_start > ui_visibility_state_->timeout_ms) {
+ ReportElementVisibilityResultForTesting(
+ UiTestOperationResult::kTimeoutNoChange);
+ }
+}
+
+void BrowserRenderer::ReportElementVisibilityResultForTesting(
+ UiTestOperationResult result) {
+ ui_visibility_state_ = nullptr;
+ browser_->ReportUiOperationResultForTesting(
+ UiTestOperationType::kElementVisibilityChange, result);
}
} // namespace vr
diff --git a/chrome/browser/vr/browser_renderer.h b/chrome/browser/vr/browser_renderer.h
index a53539d..ab3bafc 100644
--- a/chrome/browser/vr/browser_renderer.h
+++ b/chrome/browser/vr/browser_renderer.h
@@ -24,7 +24,7 @@
namespace vr {
-enum class VrUiTestActivityResult;
+enum class UiTestOperationResult;
class BrowserUiInterface;
class InputDelegate;
class PlatformInputHandler;
@@ -35,7 +35,9 @@
struct ControllerTestInput;
struct RenderInfo;
struct UiTestActivityExpectation;
+struct VisibilityChangeExpectation;
struct UiTestState;
+struct UiVisibilityState;
// The BrowserRenderer handles all input/output activities during a frame.
// This includes head movement, controller movement and input, audio output and
@@ -78,6 +80,8 @@
void SetUiExpectingActivityForTesting(
UiTestActivityExpectation ui_expectation);
void SaveNextFrameBufferToDiskForTesting(std::string filepath_base);
+ void WatchElementForVisibilityChangeForTesting(
+ VisibilityChangeExpectation visibility_expectation);
void AcceptDoffPromptForTesting();
void ConnectPresentingService(
device::mojom::VRDisplayInfoPtr display_info,
@@ -108,8 +112,11 @@
void ReportUiStatusForTesting(const base::TimeTicks& current_time,
bool ui_updated);
- void ReportUiActivityResultForTesting(VrUiTestActivityResult result);
+ void ReportUiActivityResultForTesting(UiTestOperationResult result);
void ReportFrameBufferDumpForTesting();
+ void ReportElementVisibilityStatusForTesting(
+ const base::TimeTicks& current_time);
+ void ReportElementVisibilityResultForTesting(UiTestOperationResult result);
std::unique_ptr<UiInterface> ui_;
std::unique_ptr<SchedulerDelegate> scheduler_delegate_;
@@ -124,6 +131,7 @@
BrowserRendererBrowserInterface* browser_;
std::unique_ptr<UiTestState> ui_test_state_;
+ std::unique_ptr<UiVisibilityState> ui_visibility_state_;
SlidingTimeDeltaAverage ui_processing_time_;
SlidingTimeDeltaAverage ui_controller_update_time_;
diff --git a/chrome/browser/vr/browser_renderer_browser_interface.h b/chrome/browser/vr/browser_renderer_browser_interface.h
index 8ce4826..f2103bf 100644
--- a/chrome/browser/vr/browser_renderer_browser_interface.h
+++ b/chrome/browser/vr/browser_renderer_browser_interface.h
@@ -17,7 +17,7 @@
virtual void ForceExitVr() = 0;
virtual void ReportUiOperationResultForTesting(
const UiTestOperationType& action_type,
- const VrUiTestActivityResult& result) = 0;
+ const UiTestOperationResult& result) = 0;
};
} // namespace vr
diff --git a/chrome/browser/vr/browser_renderer_unittest.cc b/chrome/browser/vr/browser_renderer_unittest.cc
index 47bc5de..797df89 100644
--- a/chrome/browser/vr/browser_renderer_unittest.cc
+++ b/chrome/browser/vr/browser_renderer_unittest.cc
@@ -52,6 +52,7 @@
MOCK_METHOD2(GetTargetPointForTesting,
gfx::Point3F(UserFriendlyElementName,
const gfx::PointF& position));
+ MOCK_METHOD1(GetElementVisibilityForTesting, bool(UserFriendlyElementName));
MOCK_METHOD0(IsContentVisibleAndOpaque, bool());
MOCK_METHOD1(SetContentUsesQuadLayer, void(bool));
gfx::Transform GetContentWorldSpaceTransform() override { return {}; }
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index ce47c6b..8f66e5db 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -67,6 +67,8 @@
return kOverflowMenuNewIncognitoTabItem;
case UserFriendlyElementName::kCloseIncognitoTabs:
return kOverflowMenuCloseAllIncognitoTabsItem;
+ case UserFriendlyElementName::kExitPrompt:
+ return kExitPrompt;
default:
NOTREACHED();
return kNone;
@@ -547,6 +549,13 @@
InitializeModel(ui_initial_state);
}
+bool Ui::GetElementVisibilityForTesting(UserFriendlyElementName element_name) {
+ auto* target_element = scene()->GetUiElementByName(
+ UserFriendlyElementNameToUiElementName(element_name));
+ DCHECK(target_element) << "Unsupported test element";
+ return target_element->IsVisible();
+}
+
void Ui::InitializeModel(const UiInitialState& ui_initial_state) {
model_->speech.has_or_can_request_audio_permission =
ui_initial_state.has_or_can_request_audio_permission;
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index 9694c41d..8627fa22 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -74,6 +74,8 @@
ContentInputDelegate* GetContentInputDelegateForTest() {
return content_input_delegate_.get();
}
+ bool GetElementVisibilityForTesting(
+ UserFriendlyElementName element_name) override;
void Dump(bool include_bindings);
// TODO(crbug.com/767957): Refactor to hide these behind the UI interface.
diff --git a/chrome/browser/vr/ui_interface.h b/chrome/browser/vr/ui_interface.h
index a5d8551..e30e57f5 100644
--- a/chrome/browser/vr/ui_interface.h
+++ b/chrome/browser/vr/ui_interface.h
@@ -79,6 +79,8 @@
virtual gfx::Point3F GetTargetPointForTesting(
UserFriendlyElementName element_name,
const gfx::PointF& position) = 0;
+ virtual bool GetElementVisibilityForTesting(
+ UserFriendlyElementName element_name) = 0;
virtual bool IsContentVisibleAndOpaque() = 0;
virtual void SetContentUsesQuadLayer(bool uses_quad_buffers) = 0;
virtual gfx::Transform GetContentWorldSpaceTransform() = 0;
diff --git a/chrome/browser/vr/ui_test_input.h b/chrome/browser/vr/ui_test_input.h
index 05171cec9..8de91465f 100644
--- a/chrome/browser/vr/ui_test_input.h
+++ b/chrome/browser/vr/ui_test_input.h
@@ -25,6 +25,7 @@
kNewIncognitoTab, // Button to open a new Incognito tab in the overflow menu
kCloseIncognitoTabs, // Button to close all Incognito tabs in the overflow
// menu
+ kExitPrompt, // DOFF prompt/request to exit VR
};
// These are the types of actions that Java can request callbacks for once
@@ -33,17 +34,21 @@
enum class UiTestOperationType : int {
kUiActivityResult = 0, // Result after being told to wait for quiescence
kFrameBufferDumped, // Signal that the frame buffer was dumped to disk
+ kElementVisibilityChange, // Signal that a watched element changed visibility
kNumUiTestOperationTypes, // Must be last
};
-// These are used to report the current state of the UI after performing an
-// action
+// These are used to report the result of a UI test operation.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.vr
-enum class VrUiTestActivityResult : int {
- kUnreported,
- kQuiescent,
- kTimeoutNoStart,
- kTimeoutNoEnd,
+enum class UiTestOperationResult : int {
+ kUnreported, // The result has not yet been reported
+ kQuiescent, // The UI reached quiescence (kUiActivityResult)
+ kTimeoutNoStart, // Timed out, UI activity never started (kUiActivityResult)
+ kTimeoutNoEnd, // Timed out, UI activity never finished (kUiActivityResult)
+ kVisibilityChange, // The watched element's visibility changed
+ // (kElementVisibilityChange)
+ kTimeoutNoChange, // Timed out, visibility never changed
+ // (kElementVisibilityChange)
};
// These are used to specify what type of action should be performed on a UI
@@ -71,6 +76,11 @@
int quiescence_timeout_ms;
};
+struct VisibilityChangeExpectation {
+ UserFriendlyElementName element_name;
+ int timeout_ms;
+};
+
// Holds all the information necessary to keep track of and report whether the
// UI reacted to test input.
struct UiTestState {
@@ -83,6 +93,19 @@
base::TimeTicks start_time = base::TimeTicks::Now();
};
+// Holds all the information necessary to keep track of and report whether a
+// UI element changed visibility in the allotted time.
+struct UiVisibilityState {
+ // The UI element being watched.
+ UserFriendlyElementName element_to_watch = UserFriendlyElementName::kUrl;
+ // The initial visibility state of the element.
+ bool initially_visible = false;
+ // How long to wait for a visibility change before timing out.
+ base::TimeDelta timeout_ms = base::TimeDelta::Min();
+ // The point in time that we started watching for visibility changes.
+ base::TimeTicks start_time = base::TimeTicks::Now();
+};
+
} // namespace vr
#endif // CHROME_BROWSER_VR_UI_TEST_INPUT_H_