Commit cae5f871 authored by James Cook's avatar James Cook Committed by Commit Bot

chromeos: Fix dictation into keyboard shortcut viewer app

Chrome creates a second InputMethodChromeOS when a remote mojo app
opens. This sets a new IMEInputContextHandler on IMEBridge, but does
not trigger an "engine switch".

Make sure the dictation code looks up the current IMEInputContextHandler
each time it tries to inject text.

Bug: 876448
Test: added to interactive_ui_tests
Change-Id: I100a62920ffb397ec823a4bcddb1adf94ec5f6a3
Reviewed-on: https://chromium-review.googlesource.com/1187135
Commit-Queue: James Cook <jamescook@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585632}
parent 50ca13ac
......@@ -32,14 +32,19 @@ std::string GetUserLocale(Profile* profile) {
return user_locale.empty() ? kDefaultProfileLocale : user_locale;
}
// Returns the current input context. This may change during the session, even
// if the IME engine does not change, because remote mojo applications have
// their own instance of InputMethodChromeOS. See comment on InputMethodBridge.
ui::IMEInputContextHandlerInterface* GetInputContext() {
return ui::IMEBridge::Get()->GetInputContextHandler();
}
} // namespace
DictationChromeos::DictationChromeos(Profile* profile)
: profile_(profile), weak_ptr_factory_(this) {
composition_ = std::make_unique<ui::CompositionText>();
input_context_ = ui::IMEBridge::Get()->GetInputContextHandler();
ui::IMEBridge::Get()->SetObserver(this);
}
: composition_(std::make_unique<ui::CompositionText>()),
profile_(profile),
weak_ptr_factory_(this) {}
DictationChromeos::~DictationChromeos() = default;
......@@ -68,8 +73,9 @@ void DictationChromeos::OnSpeechResult(const base::string16& query,
if (AccessibilityManager::Get()->IsSpokenFeedbackEnabled())
return;
if (input_context_)
input_context_->UpdateCompositionText(*composition_, 0, true);
ui::IMEInputContextHandlerInterface* input_context = GetInputContext();
if (input_context)
input_context->UpdateCompositionText(*composition_, 0, true);
return;
}
DictationOff();
......@@ -90,10 +96,6 @@ void DictationChromeos::OnSpeechRecognitionStateChanged(
void DictationChromeos::GetSpeechAuthParameters(std::string* auth_scope,
std::string* auth_token) {}
void DictationChromeos::OnRequestSwitchEngine() {
input_context_ = ui::IMEBridge::Get()->GetInputContextHandler();
}
void DictationChromeos::DictationOff() {
if (!speech_recognizer_)
return;
......@@ -101,8 +103,9 @@ void DictationChromeos::DictationOff() {
if (!composition_->text.empty()) {
media::SoundsManager::Get()->Play(chromeos::SOUND_DICTATION_END);
if (input_context_)
input_context_->CommitText(base::UTF16ToASCII(composition_->text));
ui::IMEInputContextHandlerInterface* input_context = GetInputContext();
if (input_context)
input_context->CommitText(base::UTF16ToUTF8(composition_->text));
composition_->text = base::string16();
} else {
......
......@@ -11,11 +11,9 @@
#include "base/memory/weak_ptr.h"
#include "chrome/browser/speech/speech_recognizer_delegate.h"
#include "content/public/browser/speech_recognition_session_preamble.h"
#include "ui/base/ime/ime_bridge_observer.h"
namespace ui {
struct CompositionText;
class IMEInputContextHandlerInterface;
} // namespace ui
class Profile;
......@@ -24,8 +22,7 @@ class SpeechRecognizer;
namespace chromeos {
// Provides global dictation (type what you speak) on Chrome OS.
class DictationChromeos : public SpeechRecognizerDelegate,
ui::IMEBridgeObserver {
class DictationChromeos : public SpeechRecognizerDelegate {
public:
explicit DictationChromeos(Profile* profile);
~DictationChromeos() override;
......@@ -34,6 +31,8 @@ class DictationChromeos : public SpeechRecognizerDelegate,
bool OnToggleDictation();
private:
friend class DictationTest;
// SpeechRecognizerDelegate:
void OnSpeechResult(const base::string16& query, bool is_final) override;
void OnSpeechSoundLevelChanged(int16_t level) override;
......@@ -42,21 +41,16 @@ class DictationChromeos : public SpeechRecognizerDelegate,
void GetSpeechAuthParameters(std::string* auth_scope,
std::string* auth_token) override;
// IMEBridgeObserver
void OnRequestSwitchEngine() override;
// Saves current dictation result and stops listening.
void DictationOff();
std::unique_ptr<SpeechRecognizer> speech_recognizer_;
std::unique_ptr<ui::CompositionText> composition_;
ui::IMEInputContextHandlerInterface* input_context_;
Profile* profile_;
base::WeakPtrFactory<DictationChromeos> weak_ptr_factory_;
friend class DictationTest;
DISALLOW_COPY_AND_ASSIGN(DictationChromeos);
};
......
......@@ -122,4 +122,27 @@ IN_PROC_BROWSER_TEST_F(DictationTest, UserEndsDictationWhenChromeVoxEnabled) {
EXPECT_EQ(kFinalSpeechResult, input_context_handler_->last_commit_text());
}
IN_PROC_BROWSER_TEST_F(DictationTest, SwitchInputContext) {
// Turn on dictation and say something.
AccessibilityManager::Get()->ToggleDictation();
SendSpeechResult(kFirstSpeechResult, true /* is_final */);
// Speech goes to the default IMEInputContextHandler.
EXPECT_EQ(kFirstSpeechResult, input_context_handler_->last_commit_text());
// Simulate a remote app instantiating a new IMEInputContextHandler, like the
// keyboard shortcut viewer app creating a second InputMethodChromeOS.
ui::MockIMEInputContextHandler input_context_handler2;
ui::IMEBridge::Get()->SetInputContextHandler(&input_context_handler2);
// Turn on dictation and say something else.
AccessibilityManager::Get()->ToggleDictation();
SendSpeechResult(kSecondSpeechResult, true /* is_final */);
// Speech goes to the new IMEInputContextHandler.
EXPECT_EQ(kSecondSpeechResult, input_context_handler2.last_commit_text());
ui::IMEBridge::Get()->SetInputContextHandler(nullptr);
}
} // namespace chromeos
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