Skip to content

Commit

Permalink
[Passwords] Suppress Soft Keyboard for Touch To Fill
Browse files Browse the repository at this point in the history
This change implements the necessary change to the renderer to suppress
the soft keyboard in case the Touch To Fill UI should be shown. It does
so by adding an always_hide_ime field to RenderWidget and TextInputState
and modifying ImeAdapterImpl.java to always hide the IME if this flag is
set.

Bug: 957532
Change-Id: I835f89991aeca931c8c963ce6e8e165187188ed5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1619788
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Changwan Ryu <changwan@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#683581}
  • Loading branch information
jdoerrie authored and Commit Bot committed Aug 2, 2019
1 parent 000f92a commit 3d4843c
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 76 deletions.
7 changes: 4 additions & 3 deletions content/browser/android/ime_adapter_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,10 @@ void ImeAdapterAndroid::UpdateState(const TextInputState& state) {
ConvertUTF16ToJavaString(env, state.value);
Java_ImeAdapterImpl_updateState(
env, obj, static_cast<int>(state.type), state.flags, state.mode,
static_cast<int>(state.action), state.show_ime_if_needed, jstring_text,
state.selection_start, state.selection_end, state.composition_start,
state.composition_end, state.reply_to_request);
static_cast<int>(state.action), state.show_ime_if_needed,
state.always_hide_ime, jstring_text, state.selection_start,
state.selection_end, state.composition_start, state.composition_end,
state.reply_to_request);
}

void ImeAdapterAndroid::UpdateOnTouchDown() {
Expand Down
13 changes: 1 addition & 12 deletions content/common/text_input_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,7 @@

namespace content {

TextInputState::TextInputState()
: type(ui::TEXT_INPUT_TYPE_NONE),
mode(ui::TEXT_INPUT_MODE_DEFAULT),
action(ui::TextInputAction::kDefault),
flags(0),
selection_start(0),
selection_end(0),
composition_start(-1),
composition_end(-1),
can_compose_inline(true),
show_ime_if_needed(false),
reply_to_request(false) {}
TextInputState::TextInputState() = default;

TextInputState::TextInputState(const TextInputState& other) = default;

Expand Down
25 changes: 14 additions & 11 deletions content/common/text_input_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,44 +21,47 @@ struct CONTENT_EXPORT TextInputState {
TextInputState(const TextInputState& other);

// Type of the input field.
ui::TextInputType type;
ui::TextInputType type = ui::TEXT_INPUT_TYPE_NONE;

// The mode of input field.
ui::TextInputMode mode;
ui::TextInputMode mode = ui::TEXT_INPUT_MODE_DEFAULT;

// The action of the input field.
ui::TextInputAction action;
ui::TextInputAction action = ui::TextInputAction::kDefault;

// The flags of input field (autocorrect, autocomplete, etc.)
int flags;
int flags = 0;

// The value of input field.
base::string16 value;

// The cursor position of the current selection start, or the caret position
// if nothing is selected.
int selection_start;
int selection_start = 0;

// The cursor position of the current selection end, or the caret position if
// nothing is selected.
int selection_end;
int selection_end = 0;

// The start position of the current composition, or -1 if there is none.
int composition_start;
int composition_start = -1;

// The end position of the current composition, or -1 if there is none.
int composition_end;
int composition_end = -1;

// Whether or not inline composition can be performed for the current input.
bool can_compose_inline;
bool can_compose_inline = true;

// Whether or not the IME should be shown as a result of this update. Even if
// true, the IME will only be shown if the input is appropriate (e.g. not
// TEXT_INPUT_TYPE_NONE).
bool show_ime_if_needed;
bool show_ime_if_needed = false;

// Whether or not the IME should always be hidden as a result of this update.
bool always_hide_ime = false;

// Whether or not this is a reply to a request from IME.
bool reply_to_request;
bool reply_to_request = false;
};

} // namespace content
Expand Down
1 change: 1 addition & 0 deletions content/common/widget_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::TextInputState)
IPC_STRUCT_TRAITS_MEMBER(composition_end)
IPC_STRUCT_TRAITS_MEMBER(can_compose_inline)
IPC_STRUCT_TRAITS_MEMBER(show_ime_if_needed)
IPC_STRUCT_TRAITS_MEMBER(always_hide_ime)
IPC_STRUCT_TRAITS_MEMBER(reply_to_request)
IPC_STRUCT_TRAITS_END()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ private static int getModifiers(int metaState) {
* @param textInputMode Text input mode.
* @param textInputAction Text input mode action.
* @param showIfNeeded Whether the keyboard should be shown if it is currently hidden.
* @param alwaysHide Whether the keyboard should be unconditionally hidden.
* @param text The String contents of the field being edited.
* @param selectionStart The character offset of the selection start, or the caret position if
* there is no selection.
Expand All @@ -415,15 +416,16 @@ private static int getModifiers(int metaState) {
*/
@CalledByNative
private void updateState(int textInputType, int textInputFlags, int textInputMode,
int textInputAction, boolean showIfNeeded, String text, int selectionStart,
int selectionEnd, int compositionStart, int compositionEnd, boolean replyToRequest) {
int textInputAction, boolean showIfNeeded, boolean alwaysHide, String text,
int selectionStart, int selectionEnd, int compositionStart, int compositionEnd,
boolean replyToRequest) {
TraceEvent.begin("ImeAdapter.updateState");
try {
if (DEBUG_LOGS) {
Log.i(TAG,
"updateState: type [%d->%d], flags [%d], mode[%d], action[%d] show [%b], ",
"updateState: type [%d->%d], flags [%d], mode[%d], action[%d], show [%b], hide [%b]",
mTextInputType, textInputType, textInputFlags, textInputMode,
textInputAction, showIfNeeded);
textInputAction, showIfNeeded, alwaysHide);
}
boolean needsRestart = false;
boolean hide = false;
Expand Down Expand Up @@ -475,7 +477,7 @@ private void updateState(int textInputType, int textInputFlags, int textInputMod
mLastCompositionStart = compositionStart;
mLastCompositionEnd = compositionEnd;

if (hide) {
if (hide || alwaysHide) {
hideKeyboard();
} else {
if (needsRestart) restartInput();
Expand Down
54 changes: 54 additions & 0 deletions content/renderer/render_view_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_device_emulation_params.h"
#include "third_party/blink/public/web/web_document_loader.h"
#include "third_party/blink/public/web/web_frame_content_dumper.h"
Expand Down Expand Up @@ -1291,6 +1292,59 @@ TEST_F(RenderViewImplTest, OnImeTypeChanged) {
}
}

TEST_F(RenderViewImplTest, ShouldSuppressKeyboardIsPropagated) {
class TestAutofillClient : public blink::WebAutofillClient {
public:
TestAutofillClient() = default;
~TestAutofillClient() override = default;

bool ShouldSuppressKeyboard(const blink::WebFormControlElement&) override {
return should_suppress_keyboard_;
}

void SetShouldSuppressKeyboard(bool should_suppress_keyboard) {
should_suppress_keyboard_ = should_suppress_keyboard;
}

private:
bool should_suppress_keyboard_ = false;
};

// Set-up the fake autofill client.
TestAutofillClient client;
GetMainFrame()->SetAutofillClient(&client);

// Load an HTML page consisting of one input fields.
LoadHTML(
"<html>"
"<head>"
"</head>"
"<body>"
"<input id=\"test\" type=\"text\"></input>"
"</body>"
"</html>");

// Focus the text field, trigger a state update and check that the right IPC
// is sent.
ExecuteJavaScriptForTests("document.getElementById('test').focus();");
base::RunLoop().RunUntilIdle();
view()->GetWidget()->UpdateTextInputState();
auto params = ProcessAndReadIPC<WidgetHostMsg_TextInputStateChanged>();
EXPECT_FALSE(std::get<0>(params).always_hide_ime);
render_thread_->sink().ClearMessages();

// Tell the client to suppress the keyboard. Check whether always_hide_ime is
// set correctly.
client.SetShouldSuppressKeyboard(true);
view()->GetWidget()->UpdateTextInputState();
params = ProcessAndReadIPC<WidgetHostMsg_TextInputStateChanged>();
EXPECT_TRUE(std::get<0>(params).always_hide_ime);

// Explicitly clean-up the autofill client, as otherwise a use-after-free
// happens.
GetMainFrame()->SetAutofillClient(nullptr);
}

// Test that our IME backend can compose CJK words.
// Our IME front-end sends many platform-independent messages to the IME backend
// while it composes CJK words. This test sends the minimal messages captured
Expand Down
36 changes: 10 additions & 26 deletions content/renderer/render_widget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

#include <cmath>
#include <limits>
#include <memory>
#include <utility>

#include "base/auto_reset.h"
Expand Down Expand Up @@ -129,10 +128,6 @@
#include "third_party/skia/include/core/SkPixelRef.h"
#endif // defined(OS_POSIX)

#if defined(OS_MACOSX)
#include "content/renderer/text_input_client_observer.h"
#endif

using blink::WebImeTextSpan;
using blink::WebCursorInfo;
using blink::WebDeviceEmulationParams;
Expand Down Expand Up @@ -446,33 +441,13 @@ RenderWidget::RenderWidget(int32_t widget_routing_id,
mojom::WidgetRequest widget_request)
: routing_id_(widget_routing_id),
compositor_deps_(compositor_deps),
webwidget_internal_(nullptr),
auto_resize_mode_(false),
is_hidden_(hidden),
compositor_never_visible_(never_visible),
is_fullscreen_granted_(false),
display_mode_(display_mode),
ime_event_guard_(nullptr),
is_frozen_(is_frozen),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
text_input_flags_(0),
next_previous_flags_(kInvalidNextPreviousFlagsValue),
can_compose_inline_(true),
composition_range_(gfx::Range::InvalidRange()),
pending_window_rect_count_(0),
screen_info_(screen_info),
monitor_composition_info_(false),
popup_origin_scale_for_emulation_(0.f),
frame_swap_message_queue_(new FrameSwapMessageQueue(routing_id_)),
has_host_context_menu_location_(false),
has_focus_(false),
for_child_local_root_frame_(false),
#if defined(OS_MACOSX)
text_input_client_observer_(new TextInputClientObserver(this)),
#endif
first_update_visual_state_after_hidden_(false),
was_shown_time_(base::TimeTicks::Now()),
widget_binding_(this, std::move(widget_request)) {
DCHECK_NE(routing_id_, MSG_ROUTING_NONE);
DCHECK(RenderThread::IsMainThread());
Expand Down Expand Up @@ -1493,12 +1468,19 @@ void RenderWidget::UpdateTextInputStateInternal(bool show_virtual_keyboard,

bool new_can_compose_inline = CanComposeInline();

// Check whether the keyboard should always be hidden for the currently
// focused element.
auto* focused_frame = GetFocusedWebLocalFrameInWidget();
bool always_hide_ime =
focused_frame && focused_frame->ShouldSuppressKeyboardForFocusedElement();

// Only sends text input params if they are changed or if the ime should be
// shown.
if (show_virtual_keyboard || reply_to_request ||
text_input_type_ != new_type || text_input_mode_ != new_mode ||
text_input_info_ != new_info ||
can_compose_inline_ != new_can_compose_inline) {
can_compose_inline_ != new_can_compose_inline ||
always_hide_ime_ != always_hide_ime) {
TextInputState params;
params.type = new_type;
params.mode = new_mode;
Expand Down Expand Up @@ -1532,13 +1514,15 @@ void RenderWidget::UpdateTextInputStateInternal(bool show_virtual_keyboard,
// TODO(changwan): change instances of show_ime_if_needed to
// show_virtual_keyboard.
params.show_ime_if_needed = show_virtual_keyboard;
params.always_hide_ime = always_hide_ime;
params.reply_to_request = reply_to_request;
Send(new WidgetHostMsg_TextInputStateChanged(routing_id(), params));

text_input_info_ = new_info;
text_input_type_ = new_type;
text_input_mode_ = new_mode;
can_compose_inline_ = new_can_compose_inline;
always_hide_ime_ = always_hide_ime;
text_input_flags_ = new_info.flags;

#if defined(OS_ANDROID)
Expand Down
Loading

0 comments on commit 3d4843c

Please sign in to comment.