Commit adf1a9f6 authored by My Nguyen's avatar My Nguyen Committed by Commit Bot

Add ability to tap/click to accept suggestion

This is described in http://go/e14s-emoji-addition-mock for emoji and
http://go/personal-info-suggestion-mock for personal info suggestion.

Bug: 1098057
Change-Id: Idb66d47db2f60c9da7344fffc68ab771c981a80e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2257659Reviewed-by: default avatarKeith Lee <keithlee@chromium.org>
Reviewed-by: default avatarDarren Shen <shend@chromium.org>
Commit-Queue: My Nguyen <myy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782852}
parent b2da7772
...@@ -267,6 +267,13 @@ bool AssistiveSuggester::Suggest(const base::string16& text, ...@@ -267,6 +267,13 @@ bool AssistiveSuggester::Suggest(const base::string16& text,
return false; return false;
} }
void AssistiveSuggester::AcceptSuggestion(size_t index) {
if (current_suggester_ && current_suggester_->AcceptSuggestion(index)) {
RecordAssistiveSuccess(current_suggester_->GetProposeActionType());
current_suggester_ = nullptr;
}
}
void AssistiveSuggester::DismissSuggestion() { void AssistiveSuggester::DismissSuggestion() {
if (current_suggester_) if (current_suggester_)
current_suggester_->DismissSuggestion(); current_suggester_->DismissSuggestion();
......
...@@ -47,6 +47,9 @@ class AssistiveSuggester { ...@@ -47,6 +47,9 @@ class AssistiveSuggester {
// Returns true if suggester handles the event and it should stop propagate. // Returns true if suggester handles the event and it should stop propagate.
bool OnKeyEvent(const InputMethodEngineBase::KeyboardEvent& event); bool OnKeyEvent(const InputMethodEngineBase::KeyboardEvent& event);
// Accepts the suggestion at a given index if a suggester is currently active.
void AcceptSuggestion(size_t index);
private: private:
// Returns if any suggestion text should be displayed according to the // Returns if any suggestion text should be displayed according to the
// surrounding text information. // surrounding text information.
......
...@@ -124,12 +124,9 @@ SuggestionStatus EmojiSuggester::HandleKeyEvent( ...@@ -124,12 +124,9 @@ SuggestionStatus EmojiSuggester::HandleKeyEvent(
return SuggestionStatus::kNotHandled; return SuggestionStatus::kNotHandled;
SuggestionStatus status = SuggestionStatus::kNotHandled; SuggestionStatus status = SuggestionStatus::kNotHandled;
std::string error; std::string error;
if (event.key == "Enter" && candidate_id_ != -1) { if (event.key == "Enter") {
suggestion_shown_ = false; if (AcceptSuggestion(candidate_id_))
engine_->AcceptSuggestionCandidate(context_id_, candidates_[candidate_id_], status = SuggestionStatus::kAccept;
&error);
RecordAcceptanceIndex(candidate_id_);
status = SuggestionStatus::kAccept;
} else if (event.key == "Down") { } else if (event.key == "Down") {
candidate_id_ < static_cast<int>(candidates_.size()) - 1 candidate_id_ < static_cast<int>(candidates_.size()) - 1
? candidate_id_++ ? candidate_id_++
...@@ -182,6 +179,22 @@ void EmojiSuggester::ShowSuggestion(const std::string& text) { ...@@ -182,6 +179,22 @@ void EmojiSuggester::ShowSuggestion(const std::string& text) {
} }
} }
bool EmojiSuggester::AcceptSuggestion(size_t index) {
if (index < 0 || index >= candidates_.size())
return false;
std::string error;
engine_->AcceptSuggestionCandidate(context_id_, candidates_[index], &error);
if (!error.empty()) {
LOG(ERROR) << "Failed to accept suggestion. " << error;
}
suggestion_shown_ = false;
RecordAcceptanceIndex(index);
return true;
}
void EmojiSuggester::DismissSuggestion() { void EmojiSuggester::DismissSuggestion() {
std::string error; std::string error;
suggestion_shown_ = false; suggestion_shown_ = false;
......
...@@ -27,6 +27,7 @@ class EmojiSuggester : public Suggester { ...@@ -27,6 +27,7 @@ class EmojiSuggester : public Suggester {
SuggestionStatus HandleKeyEvent( SuggestionStatus HandleKeyEvent(
const InputMethodEngineBase::KeyboardEvent& event) override; const InputMethodEngineBase::KeyboardEvent& event) override;
bool Suggest(const base::string16& text) override; bool Suggest(const base::string16& text) override;
bool AcceptSuggestion(size_t index) override;
void DismissSuggestion() override; void DismissSuggestion() override;
AssistiveType GetProposeActionType() override; AssistiveType GetProposeActionType() override;
......
...@@ -227,7 +227,13 @@ void NativeInputMethodEngine::ImeObserver::OnCandidateClicked( ...@@ -227,7 +227,13 @@ void NativeInputMethodEngine::ImeObserver::OnCandidateClicked(
void NativeInputMethodEngine::ImeObserver::OnAssistiveWindowButtonClicked( void NativeInputMethodEngine::ImeObserver::OnAssistiveWindowButtonClicked(
const ui::ime::AssistiveWindowButton& button) { const ui::ime::AssistiveWindowButton& button) {
base_observer_->OnAssistiveWindowButtonClicked(button); if (button.id == ui::ime::ButtonId::kSuggestion) {
if (assistive_suggester_->IsAssistiveFeatureEnabled()) {
assistive_suggester_->AcceptSuggestion(button.index);
}
} else {
base_observer_->OnAssistiveWindowButtonClicked(button);
}
} }
void NativeInputMethodEngine::ImeObserver::OnMenuItemActivated( void NativeInputMethodEngine::ImeObserver::OnMenuItemActivated(
......
...@@ -133,10 +133,11 @@ SuggestionStatus PersonalInfoSuggester::HandleKeyEvent( ...@@ -133,10 +133,11 @@ SuggestionStatus PersonalInfoSuggester::HandleKeyEvent(
const InputMethodEngineBase::KeyboardEvent& event) { const InputMethodEngineBase::KeyboardEvent& event) {
if (suggestion_shown_) { if (suggestion_shown_) {
if (event.key == "Tab" || event.key == "Right") { if (event.key == "Tab" || event.key == "Right") {
AcceptSuggestion(); if (AcceptSuggestion()) {
IncrementPrefValueTilCapped(kPersonalInfoSuggesterTabAcceptanceCount, IncrementPrefValueTilCapped(kPersonalInfoSuggesterTabAcceptanceCount,
kMaxTabAcceptanceCount); kMaxTabAcceptanceCount);
return SuggestionStatus::kAccept; return SuggestionStatus::kAccept;
}
} else if (event.key == "Esc") { } else if (event.key == "Esc") {
DismissSuggestion(); DismissSuggestion();
return SuggestionStatus::kDismiss; return SuggestionStatus::kDismiss;
...@@ -290,15 +291,20 @@ AssistiveType PersonalInfoSuggester::GetProposeActionType() { ...@@ -290,15 +291,20 @@ AssistiveType PersonalInfoSuggester::GetProposeActionType() {
return proposed_action_type_; return proposed_action_type_;
} }
void PersonalInfoSuggester::AcceptSuggestion() { bool PersonalInfoSuggester::AcceptSuggestion(size_t index) {
std::string error; std::string error;
suggestion_shown_ = false;
suggestion_handler_->AcceptSuggestion(context_id_, &error); suggestion_handler_->AcceptSuggestion(context_id_, &error);
if (!error.empty()) { if (!error.empty()) {
LOG(ERROR) << "Failed to accept suggestion. " << error; LOG(ERROR) << "Failed to accept suggestion. " << error;
return false;
} }
suggestion_shown_ = false;
tts_handler_->Announce(base::StringPrintf( tts_handler_->Announce(base::StringPrintf(
"Inserted suggestion %s.", base::UTF16ToUTF8(suggestion_).c_str())); "Inserted suggestion %s.", base::UTF16ToUTF8(suggestion_).c_str()));
return true;
} }
void PersonalInfoSuggester::DismissSuggestion() { void PersonalInfoSuggester::DismissSuggestion() {
......
...@@ -77,6 +77,8 @@ class PersonalInfoSuggester : public Suggester { ...@@ -77,6 +77,8 @@ class PersonalInfoSuggester : public Suggester {
SuggestionStatus HandleKeyEvent( SuggestionStatus HandleKeyEvent(
const InputMethodEngineBase::KeyboardEvent& event) override; const InputMethodEngineBase::KeyboardEvent& event) override;
bool Suggest(const base::string16& text) override; bool Suggest(const base::string16& text) override;
// index defaults to 0 as not required for this suggester.
bool AcceptSuggestion(size_t index = 0) override;
void DismissSuggestion() override; void DismissSuggestion() override;
AssistiveType GetProposeActionType() override; AssistiveType GetProposeActionType() override;
...@@ -87,8 +89,6 @@ class PersonalInfoSuggester : public Suggester { ...@@ -87,8 +89,6 @@ class PersonalInfoSuggester : public Suggester {
void ShowSuggestion(const base::string16& text, void ShowSuggestion(const base::string16& text,
const size_t confirmed_length); const size_t confirmed_length);
void AcceptSuggestion();
int GetPrefValue(const std::string& pref_name); int GetPrefValue(const std::string& pref_name);
// Increment int value for the given pref_name by 1 every time the function is // Increment int value for the given pref_name by 1 every time the function is
......
...@@ -34,6 +34,10 @@ class Suggester { ...@@ -34,6 +34,10 @@ class Suggester {
// information. // information.
virtual bool Suggest(const base::string16& text) = 0; virtual bool Suggest(const base::string16& text) = 0;
// Accepts the suggestion at a given index, index can be made default if
// unnecessary. Returns true if suggestion is accepted successfully.
virtual bool AcceptSuggestion(size_t index) = 0;
virtual void DismissSuggestion() = 0; virtual void DismissSuggestion() = 0;
// Return the propose assistive action type. // Return the propose assistive action type.
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_UI_ASSISTIVE_DELEGATE_H_ #ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_UI_ASSISTIVE_DELEGATE_H_
#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_UI_ASSISTIVE_DELEGATE_H_ #define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_UI_ASSISTIVE_DELEGATE_H_
#include "base/strings/string16.h"
#include "ui/chromeos/ui_chromeos_export.h" #include "ui/chromeos/ui_chromeos_export.h"
namespace ui { namespace ui {
...@@ -15,6 +16,7 @@ enum class ButtonId { ...@@ -15,6 +16,7 @@ enum class ButtonId {
kUndo, kUndo,
kAddToDictionary, kAddToDictionary,
kSmartInputsSettingLink, kSmartInputsSettingLink,
kSuggestion,
}; };
enum class AssistiveWindowType { enum class AssistiveWindowType {
...@@ -26,6 +28,7 @@ enum class AssistiveWindowType { ...@@ -26,6 +28,7 @@ enum class AssistiveWindowType {
struct AssistiveWindowButton { struct AssistiveWindowButton {
ButtonId id = ButtonId::kNone; ButtonId id = ButtonId::kNone;
AssistiveWindowType window_type = AssistiveWindowType::kNone; AssistiveWindowType window_type = AssistiveWindowType::kNone;
size_t index = -1;
}; };
class UI_CHROMEOS_EXPORT AssistiveDelegate { class UI_CHROMEOS_EXPORT AssistiveDelegate {
......
...@@ -66,7 +66,8 @@ std::unique_ptr<views::Label> CreateAnnotationLabel() { ...@@ -66,7 +66,8 @@ std::unique_ptr<views::Label> CreateAnnotationLabel() {
} // namespace } // namespace
SuggestionView::SuggestionView() { SuggestionView::SuggestionView(views::ButtonListener* listener)
: views::Button(listener) {
index_label_ = AddChildView(CreateIndexLabel()); index_label_ = AddChildView(CreateIndexLabel());
index_label_->SetVisible(false); index_label_->SetVisible(false);
suggestion_label_ = AddChildView(CreateSuggestionLabel()); suggestion_label_ = AddChildView(CreateSuggestionLabel());
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/macros.h" #include "base/macros.h"
#include "ui/chromeos/ui_chromeos_export.h" #include "ui/chromeos/ui_chromeos_export.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/controls/styled_label.h" #include "ui/views/controls/styled_label.h"
#include "ui/views/view.h" #include "ui/views/view.h"
...@@ -34,9 +35,9 @@ constexpr SkColor kButtonHighlightColor = ...@@ -34,9 +35,9 @@ constexpr SkColor kButtonHighlightColor =
SkColorSetA(SK_ColorBLACK, 0x0F); // 6% Black. SkColorSetA(SK_ColorBLACK, 0x0F); // 6% Black.
// SuggestionView renders a suggestion. // SuggestionView renders a suggestion.
class UI_CHROMEOS_EXPORT SuggestionView : public views::View { class UI_CHROMEOS_EXPORT SuggestionView : public views::Button {
public: public:
SuggestionView(); explicit SuggestionView(views::ButtonListener* listener);
~SuggestionView() override; ~SuggestionView() override;
void SetView(const SuggestionDetails& details); void SetView(const SuggestionDetails& details);
......
...@@ -77,7 +77,8 @@ class SettingLinkView : public views::View { ...@@ -77,7 +77,8 @@ class SettingLinkView : public views::View {
}; };
SuggestionWindowView::SuggestionWindowView(gfx::NativeView parent, SuggestionWindowView::SuggestionWindowView(gfx::NativeView parent,
AssistiveDelegate* delegate) { AssistiveDelegate* delegate)
: delegate_(delegate) {
DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE); DialogDelegate::SetButtons(ui::DIALOG_BUTTON_NONE);
SetCanActivate(false); SetCanActivate(false);
DCHECK(parent); DCHECK(parent);
...@@ -146,7 +147,7 @@ void SuggestionWindowView::MaybeInitializeSuggestionViews( ...@@ -146,7 +147,7 @@ void SuggestionWindowView::MaybeInitializeSuggestionViews(
candidate_views_.resize(candidates_size); candidate_views_.resize(candidates_size);
while (candidate_views_.size() < candidates_size) { while (candidate_views_.size() < candidates_size) {
auto new_candidate = std::make_unique<SuggestionView>(); auto new_candidate = std::make_unique<SuggestionView>(this);
candidate_area_->AddChildView(new_candidate.get()); candidate_area_->AddChildView(new_candidate.get());
candidate_views_.push_back(std::move(new_candidate)); candidate_views_.push_back(std::move(new_candidate));
} }
...@@ -165,6 +166,20 @@ void SuggestionWindowView::SetBounds(const gfx::Rect& cursor_bounds) { ...@@ -165,6 +166,20 @@ void SuggestionWindowView::SetBounds(const gfx::Rect& cursor_bounds) {
SetAnchorRect(cursor_bounds); SetAnchorRect(cursor_bounds);
} }
// TODO(crbug/1099116): Add test for ButtonPressed.
void SuggestionWindowView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
for (size_t i = 0; i < candidate_views_.size(); i++) {
if (sender == candidate_views_[i].get()) {
AssistiveWindowButton button;
button.id = ui::ime::ButtonId::kSuggestion;
button.index = i;
delegate_->AssistiveWindowButtonClicked(button);
return;
}
}
}
const char* SuggestionWindowView::GetClassName() const { const char* SuggestionWindowView::GetClassName() const {
return "SuggestionWindowView"; return "SuggestionWindowView";
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "ui/chromeos/ui_chromeos_export.h" #include "ui/chromeos/ui_chromeos_export.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/controls/button/button.h"
namespace ui { namespace ui {
namespace ime { namespace ime {
...@@ -22,7 +23,8 @@ struct SuggestionDetails; ...@@ -22,7 +23,8 @@ struct SuggestionDetails;
// SuggestionWindowView is the main container of the suggestion window UI. // SuggestionWindowView is the main container of the suggestion window UI.
class UI_CHROMEOS_EXPORT SuggestionWindowView class UI_CHROMEOS_EXPORT SuggestionWindowView
: public views::BubbleDialogDelegateView { : public views::BubbleDialogDelegateView,
public views::ButtonListener {
public: public:
SuggestionWindowView(gfx::NativeView parent, AssistiveDelegate* delegate); SuggestionWindowView(gfx::NativeView parent, AssistiveDelegate* delegate);
~SuggestionWindowView() override; ~SuggestionWindowView() override;
...@@ -43,6 +45,9 @@ class UI_CHROMEOS_EXPORT SuggestionWindowView ...@@ -43,6 +45,9 @@ class UI_CHROMEOS_EXPORT SuggestionWindowView
private: private:
friend class SuggestionWindowViewTest; friend class SuggestionWindowViewTest;
// Overridden from views::ButtonListener:
void ButtonPressed(views::Button* sender, const ui::Event& event) override;
void MaybeInitializeSuggestionViews(size_t candidates_size); void MaybeInitializeSuggestionViews(size_t candidates_size);
void MakeVisible(); void MakeVisible();
......
...@@ -117,6 +117,7 @@ input_ime::AssistiveWindowButton ConvertAssistiveWindowButton( ...@@ -117,6 +117,7 @@ input_ime::AssistiveWindowButton ConvertAssistiveWindowButton(
switch (id) { switch (id) {
case ui::ime::ButtonId::kNone: case ui::ime::ButtonId::kNone:
case ui::ime::ButtonId::kSmartInputsSettingLink: case ui::ime::ButtonId::kSmartInputsSettingLink:
case ui::ime::ButtonId::kSuggestion:
return input_ime::ASSISTIVE_WINDOW_BUTTON_NONE; return input_ime::ASSISTIVE_WINDOW_BUTTON_NONE;
case ui::ime::ButtonId::kUndo: case ui::ime::ButtonId::kUndo:
return input_ime::ASSISTIVE_WINDOW_BUTTON_UNDO; return input_ime::ASSISTIVE_WINDOW_BUTTON_UNDO;
......
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