Commit 958b96f3 authored by Christopher Grant's avatar Christopher Grant Committed by Commit Bot

VR: Prevent keyboard from showing with exit-VR prompt

If the exit-VR prompt shows while content is editing text, we should
hide the keyboard.  A side effect of this change is that, when the
keyboard disappears, it notifies content that this has happened, and
content loses focus.

In the case of autofill settings, this means that if the user chooses
autofill settings but dismisses the exit-VR prompt to return to their
page, that the input field will no longer be focused for edit (and the
keyboard won't be showing).  In the 2D case, the keyboard is also
hidden, but the cursor is still blinking in the field.  Therefore, VR is
not at parity with 2D, but this feels better than having the keyboard
persist through VR modal dialogs.

BUG=835483
R=asimjour

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_vr
Change-Id: I753ec31273e2473a21ea5cd2c2dddf70c962f71a
Reviewed-on: https://chromium-review.googlesource.com/1030873Reviewed-by: default avatarAmirhossein Simjour <asimjour@chromium.org>
Commit-Queue: Christopher Grant <cjgrant@chromium.org>
Cr-Commit-Position: refs/heads/master@{#554786}
parent a1a9942e
...@@ -1509,8 +1509,6 @@ void VrShellGl::DrawFrame(int16_t frame_index, base::TimeTicks current_time) { ...@@ -1509,8 +1509,6 @@ void VrShellGl::DrawFrame(int16_t frame_index, base::TimeTicks current_time) {
ui_controller_update_time_.AddSample(controller_time); ui_controller_update_time_.AddSample(controller_time);
} }
ui_->scene()->CallPerFrameCallbacks();
bool textures_changed = ui_->scene()->UpdateTextures(); bool textures_changed = ui_->scene()->UpdateTextures();
// TODO(mthiesse): Determine if a visible controller is actually drawn in the // TODO(mthiesse): Determine if a visible controller is actually drawn in the
......
...@@ -110,7 +110,7 @@ class ContentElementSceneTest : public UiTest { ...@@ -110,7 +110,7 @@ class ContentElementSceneTest : public UiTest {
protected: protected:
std::unique_ptr<StrictMock<MockTextInputDelegate>> text_input_delegate_; std::unique_ptr<StrictMock<MockTextInputDelegate>> text_input_delegate_;
std::unique_ptr<TestContentInputForwarder> input_forwarder_; std::unique_ptr<TestContentInputForwarder> input_forwarder_;
testing::Sequence in_sequence_; testing::InSequence in_sequence_;
}; };
TEST_F(ContentElementSceneTest, WebInputFocus) { TEST_F(ContentElementSceneTest, WebInputFocus) {
...@@ -119,21 +119,21 @@ TEST_F(ContentElementSceneTest, WebInputFocus) { ...@@ -119,21 +119,21 @@ TEST_F(ContentElementSceneTest, WebInputFocus) {
// Set mock keyboard delegate. // Set mock keyboard delegate.
auto* kb = static_cast<Keyboard*>(scene_->GetUiElementByName(kKeyboard)); auto* kb = static_cast<Keyboard*>(scene_->GetUiElementByName(kKeyboard));
auto kb_delegate = std::make_unique<StrictMock<MockKeyboardDelegate>>(); auto kb_delegate = std::make_unique<StrictMock<MockKeyboardDelegate>>();
EXPECT_CALL(*kb_delegate, HideKeyboard()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, HideKeyboard());
kb->SetKeyboardDelegate(kb_delegate.get()); kb->SetKeyboardDelegate(kb_delegate.get());
// Editing web input. // Editing web input.
EXPECT_CALL(*text_input_delegate_, RequestFocus(_)).InSequence(in_sequence_); EXPECT_CALL(*text_input_delegate_, RequestFocus(_));
EXPECT_CALL(*kb_delegate, ShowKeyboard()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, ShowKeyboard());
EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, OnBeginFrame());
EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, SetTransform(_));
ui_->ShowSoftInput(true); ui_->ShowSoftInput(true);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
// Giving content focus should tell the delegate the focued field's content. // Giving content focus should tell the delegate the focued field's content.
EXPECT_CALL(*text_input_delegate_, UpdateInput(_)).InSequence(in_sequence_); EXPECT_CALL(*text_input_delegate_, UpdateInput(_));
EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, OnBeginFrame());
EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, SetTransform(_));
content->OnFocusChanged(true); content->OnFocusChanged(true);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
...@@ -145,17 +145,16 @@ TEST_F(ContentElementSceneTest, WebInputFocus) { ...@@ -145,17 +145,16 @@ TEST_F(ContentElementSceneTest, WebInputFocus) {
info.selection_end = 1; info.selection_end = 1;
info.composition_start = 0; info.composition_start = 0;
info.composition_end = 1; info.composition_end = 1;
EXPECT_CALL(*text_input_delegate_, UpdateInput(info)) EXPECT_CALL(*text_input_delegate_, UpdateInput(info));
.InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, OnBeginFrame());
EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, SetTransform(_));
EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_);
ui_->UpdateWebInputIndices(1, 1, 0, 1); ui_->UpdateWebInputIndices(1, 1, 0, 1);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
// End editing. // End editing.
EXPECT_CALL(*kb_delegate, HideKeyboard()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, HideKeyboard());
EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, OnBeginFrame());
EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_); EXPECT_CALL(*kb_delegate, SetTransform(_));
ui_->ShowSoftInput(false); ui_->ShowSoftInput(false);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
...@@ -163,9 +162,11 @@ TEST_F(ContentElementSceneTest, WebInputFocus) { ...@@ -163,9 +162,11 @@ TEST_F(ContentElementSceneTest, WebInputFocus) {
EXPECT_FALSE(input_forwarder_->clear_focus_called()); EXPECT_FALSE(input_forwarder_->clear_focus_called());
content->OnFocusChanged(false); content->OnFocusChanged(false);
EXPECT_TRUE(input_forwarder_->clear_focus_called()); EXPECT_TRUE(input_forwarder_->clear_focus_called());
// OnBeginFrame on the keyboard delegate should be called despite of // OnBeginFrame on the keyboard delegate should be called despite of
// visibility. // visibility.
scene_->CallPerFrameCallbacks(); EXPECT_CALL(*kb_delegate, OnBeginFrame());
OnBeginFrame();
} }
// Verify that we clear the model for the web input field when it loses focus to // Verify that we clear the model for the web input field when it loses focus to
...@@ -179,8 +180,7 @@ TEST_F(ContentElementSceneTest, ClearWebInputInfoModel) { ...@@ -179,8 +180,7 @@ TEST_F(ContentElementSceneTest, ClearWebInputInfoModel) {
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
// Initial state gets pushed when the content element is focused. // Initial state gets pushed when the content element is focused.
EXPECT_CALL(*text_input_delegate_, UpdateInput(info)) EXPECT_CALL(*text_input_delegate_, UpdateInput(info));
.InSequence(in_sequence_);
content->OnFocusChanged(true); content->OnFocusChanged(true);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
...@@ -191,8 +191,7 @@ TEST_F(ContentElementSceneTest, ClearWebInputInfoModel) { ...@@ -191,8 +191,7 @@ TEST_F(ContentElementSceneTest, ClearWebInputInfoModel) {
// A cleared state gets pushed when the content element is focused. This is // A cleared state gets pushed when the content element is focused. This is
// needed because the user may have clicked another text field in the content, // needed because the user may have clicked another text field in the content,
// so we shouldn't be pushing the stale state. // so we shouldn't be pushing the stale state.
EXPECT_CALL(*text_input_delegate_, UpdateInput(TextInputInfo())) EXPECT_CALL(*text_input_delegate_, UpdateInput(TextInputInfo()));
.InSequence(in_sequence_);
content->OnFocusChanged(true); content->OnFocusChanged(true);
EXPECT_TRUE(OnBeginFrame()); EXPECT_TRUE(OnBeginFrame());
} }
......
...@@ -99,20 +99,15 @@ void Keyboard::OnButtonUp(const gfx::PointF& position) { ...@@ -99,20 +99,15 @@ void Keyboard::OnButtonUp(const gfx::PointF& position) {
} }
void Keyboard::AdvanceKeyboardFrameIfNeeded() { void Keyboard::AdvanceKeyboardFrameIfNeeded() {
// If the update phase is not dirty, the frame will be advanced in // This is the keyboard's equivalent to OnBeginFrame(), but is separate
// OnBeginFrame. That is, we only call OnBeginFrame below when the element is // because it must run on every frame - not just if the keyboard is visible.
// not visible (i.e UiElement::kDirty is true). if (!delegate_)
if (!delegate_ || update_phase() != kDirty)
return; return;
delegate_->OnBeginFrame(); delegate_->OnBeginFrame();
} }
bool Keyboard::OnBeginFrame(const gfx::Transform& head_pose) { bool Keyboard::OnBeginFrame(const gfx::Transform& head_pose) {
if (!delegate_)
return false;
delegate_->OnBeginFrame();
// We return false here because any visible changes to the keyboard, such as // We return false here because any visible changes to the keyboard, such as
// hover effects and showing/hiding of the keyboard will be drawn by the // hover effects and showing/hiding of the keyboard will be drawn by the
// controller's dirtyness, so it's safe to assume no visual changes here. // controller's dirtyness, so it's safe to assume no visual changes here.
......
...@@ -128,6 +128,12 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time, ...@@ -128,6 +128,12 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
FrameLifecycle::set_phase(kUpdatedBindings); FrameLifecycle::set_phase(kUpdatedBindings);
} }
// Per-frame callbacks run every frame, always, as opposed to bindings, which
// run selectively based on element visibility.
for (auto callback : per_frame_callback_) {
callback.Run();
}
{ {
TRACE_EVENT0("gpu", "UiScene::OnBeginFrame.UpdateAnimationsAndOpacity"); TRACE_EVENT0("gpu", "UiScene::OnBeginFrame.UpdateAnimationsAndOpacity");
...@@ -167,12 +173,6 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time, ...@@ -167,12 +173,6 @@ bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
return scene_dirty; return scene_dirty;
} }
void UiScene::CallPerFrameCallbacks() {
for (auto callback : per_frame_callback_) {
callback.Run();
}
}
bool UiScene::UpdateTextures() { bool UiScene::UpdateTextures() {
TRACE_EVENT0("gpu", "UiScene::UpdateTextures"); TRACE_EVENT0("gpu", "UiScene::UpdateTextures");
bool needs_redraw = false; bool needs_redraw = false;
......
...@@ -47,8 +47,6 @@ class UiScene { ...@@ -47,8 +47,6 @@ class UiScene {
bool OnBeginFrame(const base::TimeTicks& current_time, bool OnBeginFrame(const base::TimeTicks& current_time,
const gfx::Transform& head_pose); const gfx::Transform& head_pose);
void CallPerFrameCallbacks();
// Returns true if any textures were redrawn. // Returns true if any textures were redrawn.
bool UpdateTextures(); bool UpdateTextures();
......
...@@ -1883,9 +1883,9 @@ void UiSceneCreator::CreateKeyboard() { ...@@ -1883,9 +1883,9 @@ void UiSceneCreator::CreateKeyboard() {
} }
}, },
base::Unretained(keyboard.get())))); base::Unretained(keyboard.get()))));
VR_BIND_VISIBILITY(
VR_BIND_VISIBILITY(keyboard, keyboard, (model->editing_input || model->editing_web_input) &&
model->editing_input || model->editing_web_input); model->active_modal_prompt_type == kModalPromptTypeNone);
scene_->AddPerFrameCallback(base::BindRepeating( scene_->AddPerFrameCallback(base::BindRepeating(
[](Keyboard* keyboard) { keyboard->AdvanceKeyboardFrameIfNeeded(); }, [](Keyboard* keyboard) { keyboard->AdvanceKeyboardFrameIfNeeded(); },
base::Unretained(keyboard.get()))); base::Unretained(keyboard.get())));
......
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