Commit 3cb6c3fe authored by Shu Chen's avatar Shu Chen Committed by Commit Bot

Moves the IME mode indicator view to ash.

This cl also removes the unnecessary ModeIndicatorController, because
1) Init widget container can be done directly in ash.
2) ImeControllerClient has already listened to InputMethodChanged event.
3) The anchor bounds can be got via the IMECandidateWindowHandlerInterface.

Bug: 738531
Change-Id: Ieee87fde776be2f33121da52293b886933106205
Reviewed-on: https://chromium-review.googlesource.com/1170717
Commit-Queue: Shu Chen <shuchen@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583164}
parent d4bef811
...@@ -840,6 +840,10 @@ component("ash") { ...@@ -840,6 +840,10 @@ component("ash") {
"host/transformer_helper.cc", "host/transformer_helper.cc",
"ime/ime_controller.cc", "ime/ime_controller.cc",
"ime/ime_focus_handler.cc", "ime/ime_focus_handler.cc",
"ime/ime_mode_indicator_view.cc",
"ime/ime_mode_indicator_view.h",
"ime/mode_indicator_observer.cc",
"ime/mode_indicator_observer.h",
"keyboard/keyboard_ui.cc", "keyboard/keyboard_ui.cc",
"keyboard/keyboard_ui_mash.cc", "keyboard/keyboard_ui_mash.cc",
"keyboard/virtual_keyboard_container_layout_manager.cc", "keyboard/virtual_keyboard_container_layout_manager.cc",
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include "ash/ime/ime_controller.h" #include "ash/ime/ime_controller.h"
#include "ash/ime/ime_mode_indicator_view.h"
#include "ash/ime/mode_indicator_observer.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/system/tray/system_tray_notifier.h" #include "ash/system/tray/system_tray_notifier.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
...@@ -11,7 +13,8 @@ ...@@ -11,7 +13,8 @@
namespace ash { namespace ash {
ImeController::ImeController() = default; ImeController::ImeController()
: mode_indicator_observer_(std::make_unique<ModeIndicatorObserver>()) {}
ImeController::~ImeController() = default; ImeController::~ImeController() = default;
...@@ -155,6 +158,15 @@ void ImeController::SetExtraInputOptionsEnabledState( ...@@ -155,6 +158,15 @@ void ImeController::SetExtraInputOptionsEnabledState(
is_voice_enabled_ = is_voice_enabled; is_voice_enabled_ = is_voice_enabled;
} }
void ImeController::ShowModeIndicator(const gfx::Rect& anchor_bounds,
const base::string16& ime_short_name) {
ImeModeIndicatorView* mi_view =
new ImeModeIndicatorView(anchor_bounds, ime_short_name);
views::BubbleDialogDelegateView::CreateBubble(mi_view);
mode_indicator_observer_->AddModeIndicatorWidget(mi_view->GetWidget());
mi_view->ShowAndFadeOut();
}
void ImeController::SetCapsLockEnabled(bool caps_enabled) { void ImeController::SetCapsLockEnabled(bool caps_enabled) {
is_caps_lock_enabled_ = caps_enabled; is_caps_lock_enabled_ = caps_enabled;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef ASH_IME_IME_CONTROLLER_H_ #ifndef ASH_IME_IME_CONTROLLER_H_
#define ASH_IME_IME_CONTROLLER_H_ #define ASH_IME_IME_CONTROLLER_H_
#include <memory>
#include <vector> #include <vector>
#include "ash/ash_export.h" #include "ash/ash_export.h"
...@@ -20,6 +21,8 @@ class Accelerator; ...@@ -20,6 +21,8 @@ class Accelerator;
namespace ash { namespace ash {
class ModeIndicatorObserver;
// Connects ash IME users (e.g. the system tray) to the IME implementation, // Connects ash IME users (e.g. the system tray) to the IME implementation,
// which might live in Chrome browser or in a separate mojo service. // which might live in Chrome browser or in a separate mojo service.
class ASH_EXPORT ImeController : public mojom::ImeController { class ASH_EXPORT ImeController : public mojom::ImeController {
...@@ -96,6 +99,10 @@ class ASH_EXPORT ImeController : public mojom::ImeController { ...@@ -96,6 +99,10 @@ class ASH_EXPORT ImeController : public mojom::ImeController {
bool is_emoji_enabled, bool is_emoji_enabled,
bool is_handwriting_enabled, bool is_handwriting_enabled,
bool is_voice_enabled) override; bool is_voice_enabled) override;
// Show the mode indicator UI with the given text at the anchor bounds.
// The anchor bounds is in the universal screen coordinates in DIP.
void ShowModeIndicator(const gfx::Rect& anchor_bounds,
const base::string16& ime_short_name) override;
// Synchronously returns the cached caps lock state. // Synchronously returns the cached caps lock state.
bool IsCapsLockEnabled() const; bool IsCapsLockEnabled() const;
...@@ -107,6 +114,10 @@ class ASH_EXPORT ImeController : public mojom::ImeController { ...@@ -107,6 +114,10 @@ class ASH_EXPORT ImeController : public mojom::ImeController {
void FlushMojoForTesting(); void FlushMojoForTesting();
ModeIndicatorObserver* mode_indicator_observer() const {
return mode_indicator_observer_.get();
}
private: private:
// Returns the IDs of the subset of input methods which are active and are // Returns the IDs of the subset of input methods which are active and are
// associated with |accelerator|. For example, two Japanese IMEs can be // associated with |accelerator|. For example, two Japanese IMEs can be
...@@ -158,6 +169,8 @@ class ASH_EXPORT ImeController : public mojom::ImeController { ...@@ -158,6 +169,8 @@ class ASH_EXPORT ImeController : public mojom::ImeController {
base::ObserverList<Observer> observers_; base::ObserverList<Observer> observers_;
std::unique_ptr<ModeIndicatorObserver> mode_indicator_observer_;
DISALLOW_COPY_AND_ASSIGN(ImeController); DISALLOW_COPY_AND_ASSIGN(ImeController);
}; };
......
...@@ -6,19 +6,27 @@ ...@@ -6,19 +6,27 @@
#include <vector> #include <vector>
#include "ash/ime/mode_indicator_observer.h"
#include "ash/ime/test_ime_controller_client.h" #include "ash/ime/test_ime_controller_client.h"
#include "ash/public/interfaces/ime_info.mojom.h" #include "ash/public/interfaces/ime_info.mojom.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/system/ime/ime_observer.h" #include "ash/system/ime/ime_observer.h"
#include "ash/system/tray/system_tray_notifier.h" #include "ash/system/tray/system_tray_notifier.h"
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator.h"
#include "ui/base/ime/chromeos/extension_ime_util.h" #include "ui/base/ime/chromeos/extension_ime_util.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/keycodes/keyboard_codes.h"
#include "ui/views/widget/widget.h"
namespace ash { namespace ash {
namespace { namespace {
// 43 is the designed size of the inner contents.
// This value corresponds with kMinSize defined in
// mode_indicator_delegate_view.cc.
const int kInnerSize = 43;
// Refreshes the IME list with fake IMEs and fake menu items. // Refreshes the IME list with fake IMEs and fake menu items.
void RefreshImesWithMenuItems(const std::string& current_ime_id, void RefreshImesWithMenuItems(const std::string& current_ime_id,
const std::vector<std::string>& ime_ids, const std::vector<std::string>& ime_ids,
...@@ -296,5 +304,54 @@ TEST_F(ImeControllerTest, OnKeyboardLayoutNameChanged) { ...@@ -296,5 +304,54 @@ TEST_F(ImeControllerTest, OnKeyboardLayoutNameChanged) {
EXPECT_EQ("us(dvorak)", observer.last_keyboard_layout_name()); EXPECT_EQ("us(dvorak)", observer.last_keyboard_layout_name());
} }
TEST_F(ImeControllerTest, ShowModeIndicator) {
ImeController* controller = Shell::Get()->ime_controller();
base::string16 text = base::ASCIIToUTF16("US");
gfx::Rect cursor1_bounds(100, 100, 1, 20);
controller->ShowModeIndicator(cursor1_bounds, text);
views::Widget* widget1 =
controller->mode_indicator_observer()->active_widget();
EXPECT_TRUE(widget1);
// The widget bounds should be bigger than the inner size.
gfx::Rect bounds1 = widget1->GetWindowBoundsInScreen();
EXPECT_LE(kInnerSize, bounds1.width());
EXPECT_LE(kInnerSize, bounds1.height());
gfx::Rect cursor2_bounds(50, 200, 1, 20);
controller->ShowModeIndicator(cursor2_bounds, text);
views::Widget* widget2 =
controller->mode_indicator_observer()->active_widget();
EXPECT_TRUE(widget2);
EXPECT_NE(widget1, widget2);
// Check if the location of the mode indicator corresponds to the cursor
// bounds.
gfx::Rect bounds2 = widget2->GetWindowBoundsInScreen();
EXPECT_EQ(cursor1_bounds.x() - cursor2_bounds.x(), bounds1.x() - bounds2.x());
EXPECT_EQ(cursor1_bounds.y() - cursor2_bounds.y(), bounds1.y() - bounds2.y());
EXPECT_EQ(bounds1.width(), bounds2.width());
EXPECT_EQ(bounds1.height(), bounds2.height());
const gfx::Rect screen_bounds = display::Screen::GetScreen()
->GetDisplayMatching(cursor1_bounds)
.work_area();
const gfx::Rect cursor3_bounds(100, screen_bounds.bottom() - 25, 1, 20);
controller->ShowModeIndicator(cursor3_bounds, text);
views::Widget* widget3 =
controller->mode_indicator_observer()->active_widget();
EXPECT_TRUE(widget3);
EXPECT_NE(widget2, widget3);
// Check if the location of the mode indicator is considered with the screen
// size.
gfx::Rect bounds3 = widget3->GetWindowBoundsInScreen();
EXPECT_LT(bounds3.bottom(), screen_bounds.bottom());
}
} // namespace } // namespace
} // namespace ash } // namespace ash
// Copyright 2014 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ui/chromeos/ime/mode_indicator_view.h" #include "ash/ime/ime_mode_indicator_view.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/window_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/bubble/bubble_frame_view.h"
...@@ -13,8 +18,7 @@ ...@@ -13,8 +18,7 @@
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/wm/core/window_animations.h" #include "ui/wm/core/window_animations.h"
namespace ui { namespace ash {
namespace ime {
namespace { namespace {
...@@ -44,60 +48,59 @@ class ModeIndicatorFrameView : public views::BubbleFrameView { ...@@ -44,60 +48,59 @@ class ModeIndicatorFrameView : public views::BubbleFrameView {
} // namespace } // namespace
ModeIndicatorView::ModeIndicatorView(Delegate* delegate, ImeModeIndicatorView::ImeModeIndicatorView(const gfx::Rect& cursor_bounds,
const gfx::Rect& cursor_bounds, const base::string16& label)
const base::string16& label) : cursor_bounds_(cursor_bounds), label_view_(new views::Label(label)) {
: delegate_(delegate),
cursor_bounds_(cursor_bounds),
label_view_(new views::Label(label)) {
DCHECK(delegate_);
set_can_activate(false); set_can_activate(false);
set_accept_events(false); set_accept_events(false);
set_shadow(views::BubbleBorder::NO_SHADOW); set_shadow(views::BubbleBorder::NO_SHADOW);
set_arrow(views::BubbleBorder::TOP_CENTER); set_arrow(views::BubbleBorder::TOP_CENTER);
} }
ModeIndicatorView::~ModeIndicatorView() {} ImeModeIndicatorView::~ImeModeIndicatorView() = default;
void ModeIndicatorView::ShowAndFadeOut() { void ImeModeIndicatorView::ShowAndFadeOut() {
wm::SetWindowVisibilityAnimationTransition( ::wm::SetWindowVisibilityAnimationTransition(GetWidget()->GetNativeView(),
GetWidget()->GetNativeView(), ::wm::ANIMATE_HIDE);
wm::ANIMATE_HIDE);
GetWidget()->Show(); GetWidget()->Show();
timer_.Start(FROM_HERE, timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowingDuration),
base::TimeDelta::FromMilliseconds(kShowingDuration), GetWidget(), &views::Widget::Close);
GetWidget(),
&views::Widget::Close);
} }
void ModeIndicatorView::OnBeforeBubbleWidgetInit( void ImeModeIndicatorView::OnBeforeBubbleWidgetInit(
views::Widget::InitParams* params, views::Widget::InitParams* params,
views::Widget* widget) const { views::Widget* widget) const {
delegate_->InitWidgetContainer(params); aura::Window* window = wm::GetActiveWindow();
if (window) { // Null check for tests.
params->parent = Shell::GetContainer(window->GetRootWindow(),
kShellWindowId_SettingBubbleContainer);
} else {
params->parent = Shell::GetPrimaryRootWindow();
}
} }
gfx::Size ModeIndicatorView::CalculatePreferredSize() const { gfx::Size ImeModeIndicatorView::CalculatePreferredSize() const {
gfx::Size size = label_view_->GetPreferredSize(); gfx::Size size = label_view_->GetPreferredSize();
size.SetToMax(gfx::Size(kMinSize, kMinSize)); size.SetToMax(gfx::Size(kMinSize, kMinSize));
return size; return size;
} }
const char* ModeIndicatorView::GetClassName() const { const char* ImeModeIndicatorView::GetClassName() const {
return "ModeIndicatorView"; return "ImeModeIndicatorView";
} }
int ModeIndicatorView::GetDialogButtons() const { int ImeModeIndicatorView::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE; return ui::DIALOG_BUTTON_NONE;
} }
void ModeIndicatorView::Init() { void ImeModeIndicatorView::Init() {
SetLayoutManager(std::make_unique<views::FillLayout>()); SetLayoutManager(std::make_unique<views::FillLayout>());
AddChildView(label_view_); AddChildView(label_view_);
SetAnchorRect(cursor_bounds_); SetAnchorRect(cursor_bounds_);
} }
views::NonClientFrameView* ModeIndicatorView::CreateNonClientFrameView( views::NonClientFrameView* ImeModeIndicatorView::CreateNonClientFrameView(
views::Widget* widget) { views::Widget* widget) {
views::BubbleFrameView* frame = new ModeIndicatorFrameView(); views::BubbleFrameView* frame = new ModeIndicatorFrameView();
// arrow adjustment in BubbleDialogDelegateView is unnecessary because arrow // arrow adjustment in BubbleDialogDelegateView is unnecessary because arrow
...@@ -107,5 +110,4 @@ views::NonClientFrameView* ModeIndicatorView::CreateNonClientFrameView( ...@@ -107,5 +110,4 @@ views::NonClientFrameView* ModeIndicatorView::CreateNonClientFrameView(
return frame; return frame;
} }
} // namespace ime } // namespace ash
} // namespace ui
// Copyright 2014 The Chromium Authors. All rights reserved. // Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef UI_CHROMEOS_IME_MODE_INDICATOR_VIEW_H_ #ifndef ASH_IME_IME_MODE_INDICATOR_VIEW_H_
#define UI_CHROMEOS_IME_MODE_INDICATOR_VIEW_H_ #define ASH_IME_IME_MODE_INDICATOR_VIEW_H_
#include "ash/ash_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "ui/chromeos/ui_chromeos_export.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -17,26 +17,16 @@ namespace views { ...@@ -17,26 +17,16 @@ namespace views {
class Label; class Label;
} // namespace views } // namespace views
namespace ui { namespace ash {
namespace ime {
// A small bubble that shows the short name of the current IME (e.g. "DV" for // A small bubble that shows the short name of the current IME (e.g. "DV" for
// Dvorak) after switching IMEs with an accelerator (e.g. Ctrl-Space). // Dvorak) after switching IMEs with an accelerator (e.g. Ctrl-Space).
class UI_CHROMEOS_EXPORT ModeIndicatorView class ASH_EXPORT ImeModeIndicatorView : public views::BubbleDialogDelegateView {
: public views::BubbleDialogDelegateView {
public: public:
class Delegate { // The cursor bounds is in the universal screen coordinates in DIP.
public: ImeModeIndicatorView(const gfx::Rect& cursor_bounds,
virtual ~Delegate() = default; const base::string16& label);
~ImeModeIndicatorView() override;
// Configures the InitParams to place the bubble in the right container.
virtual void InitWidgetContainer(views::Widget::InitParams* params) = 0;
};
ModeIndicatorView(Delegate* delegate,
const gfx::Rect& cursor_bounds,
const base::string16& label);
~ModeIndicatorView() override;
// Show the mode indicator then hide with fading animation. // Show the mode indicator then hide with fading animation.
void ShowAndFadeOut(); void ShowAndFadeOut();
...@@ -55,15 +45,13 @@ class UI_CHROMEOS_EXPORT ModeIndicatorView ...@@ -55,15 +45,13 @@ class UI_CHROMEOS_EXPORT ModeIndicatorView
views::Widget* widget) override; views::Widget* widget) override;
private: private:
Delegate* delegate_;
gfx::Rect cursor_bounds_; gfx::Rect cursor_bounds_;
views::Label* label_view_; views::Label* label_view_;
base::OneShotTimer timer_; base::OneShotTimer timer_;
DISALLOW_COPY_AND_ASSIGN(ModeIndicatorView); DISALLOW_COPY_AND_ASSIGN(ImeModeIndicatorView);
}; };
} // namespace ime } // namespace ash
} // namespace ui
#endif // UI_CHROMEOS_IME_MODE_INDICATOR_VIEW_H_ #endif // ASH_IME_IME_MODE_INDICATOR_VIEW_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/ime/mode_indicator_observer.h"
#include "ui/views/widget/widget.h"
namespace ash {
ModeIndicatorObserver::ModeIndicatorObserver() : active_widget_(nullptr) {}
ModeIndicatorObserver::~ModeIndicatorObserver() {
if (active_widget_)
active_widget_->RemoveObserver(this);
}
void ModeIndicatorObserver::AddModeIndicatorWidget(views::Widget* widget) {
// If other active mode indicator widget is shown, close it immediately
// without fading animation. Then store this widget as the active widget.
DCHECK(widget);
if (active_widget_)
active_widget_->Close();
active_widget_ = widget;
widget->AddObserver(this);
}
void ModeIndicatorObserver::OnWidgetDestroying(views::Widget* widget) {
if (widget == active_widget_)
active_widget_ = nullptr;
}
} // namespace ash
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_IME_MODE_INDICATOR_OBSERVER_H_
#define ASH_IME_MODE_INDICATOR_OBSERVER_H_
#include "base/macros.h"
#include "ui/views/widget/widget_observer.h"
namespace ash {
// The observer for the mode indicator widget so that the widget can be
// closed immediately when a new mode indicator view tries to show before
// the fade out animation completes.
class ModeIndicatorObserver : public views::WidgetObserver {
public:
ModeIndicatorObserver();
~ModeIndicatorObserver() override;
void AddModeIndicatorWidget(views::Widget* widget);
// Exposes the active widget for testability.
views::Widget* active_widget() const { return active_widget_; }
// views::WidgetObserver override:
void OnWidgetDestroying(views::Widget* widget) override;
private:
views::Widget* active_widget_;
DISALLOW_COPY_AND_ASSIGN(ModeIndicatorObserver);
};
} // namespace ash
#endif // ASH_IME_MODE_INDICATOR_OBSERVER_H_
...@@ -60,4 +60,9 @@ void TestImeController::SetExtraInputOptionsEnabledState( ...@@ -60,4 +60,9 @@ void TestImeController::SetExtraInputOptionsEnabledState(
is_voice_enabled_ = is_voice_enabled; is_voice_enabled_ = is_voice_enabled;
} }
void TestImeController::ShowModeIndicator(const gfx::Rect& anchor_bounds,
const base::string16& text) {
show_mode_indicator_ = true;
}
} // namespace ash } // namespace ash
...@@ -36,6 +36,8 @@ class ASH_EXPORT TestImeController : mojom::ImeController { ...@@ -36,6 +36,8 @@ class ASH_EXPORT TestImeController : mojom::ImeController {
bool is_emoji_enabled, bool is_emoji_enabled,
bool is_handwriting_enabled, bool is_handwriting_enabled,
bool is_voice_enabled) override; bool is_voice_enabled) override;
void ShowModeIndicator(const gfx::Rect& anchor_bounds,
const base::string16& text) override;
// The most recent values received via mojo. // The most recent values received via mojo.
std::string current_ime_id_; std::string current_ime_id_;
...@@ -43,6 +45,7 @@ class ASH_EXPORT TestImeController : mojom::ImeController { ...@@ -43,6 +45,7 @@ class ASH_EXPORT TestImeController : mojom::ImeController {
std::vector<mojom::ImeMenuItemPtr> menu_items_; std::vector<mojom::ImeMenuItemPtr> menu_items_;
bool managed_by_policy_ = false; bool managed_by_policy_ = false;
bool show_ime_menu_on_shelf_ = false; bool show_ime_menu_on_shelf_ = false;
bool show_mode_indicator_ = false;
bool is_caps_lock_enabled_ = false; bool is_caps_lock_enabled_ = false;
std::string keyboard_layout_name_; std::string keyboard_layout_name_;
bool is_extra_input_options_enabled_ = false; bool is_extra_input_options_enabled_ = false;
......
...@@ -5,7 +5,9 @@ ...@@ -5,7 +5,9 @@
module ash.mojom; module ash.mojom;
import "ash/public/interfaces/ime_info.mojom"; import "ash/public/interfaces/ime_info.mojom";
import "mojo/public/mojom/base/string16.mojom";
import "ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom"; import "ui/base/ime/chromeos/public/interfaces/ime_keyset.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
// Interface for ash client (e.g. Chrome) to send input method info to ash. // Interface for ash client (e.g. Chrome) to send input method info to ash.
interface ImeController { interface ImeController {
...@@ -46,6 +48,12 @@ interface ImeController { ...@@ -46,6 +48,12 @@ interface ImeController {
bool is_emoji_enabled, bool is_emoji_enabled,
bool is_handwriting_enabled, bool is_handwriting_enabled,
bool is_voice_enabled); bool is_voice_enabled);
// Show the mode indicator view (e.g. a bubble with "DV" for Dvorak).
// The view fades out after a delay and close itself.
// The anchor bounds is in the universal screen coordinates in DIP.
ShowModeIndicator(gfx.mojom.Rect anchor_bounds,
mojo_base.mojom.String16 ime_short_name);
}; };
// Interface for ash to send input method requests to its client (e.g. Chrome). // Interface for ash to send input method requests to its client (e.g. Chrome).
......
...@@ -876,8 +876,6 @@ source_set("chromeos") { ...@@ -876,8 +876,6 @@ source_set("chromeos") {
"input_method/input_method_persistence.h", "input_method/input_method_persistence.h",
"input_method/input_method_syncer.cc", "input_method/input_method_syncer.cc",
"input_method/input_method_syncer.h", "input_method/input_method_syncer.h",
"input_method/mode_indicator_controller.cc",
"input_method/mode_indicator_controller.h",
"language_preferences.cc", "language_preferences.cc",
"language_preferences.h", "language_preferences.h",
"launchable.cc", "launchable.cc",
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "base/logging.h" #include "base/logging.h"
#include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
#include "ui/base/ime/ime_bridge.h" #include "ui/base/ime/ime_bridge.h"
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
#include "ui/chromeos/ime/infolist_window.h" #include "ui/chromeos/ime/infolist_window.h"
...@@ -24,17 +23,12 @@ namespace { ...@@ -24,17 +23,12 @@ namespace {
} // namespace } // namespace
CandidateWindowControllerImpl::CandidateWindowControllerImpl() CandidateWindowControllerImpl::CandidateWindowControllerImpl() {
: candidate_window_view_(NULL),
infolist_window_(NULL) {
ui::IMEBridge::Get()->SetCandidateWindowHandler(this); ui::IMEBridge::Get()->SetCandidateWindowHandler(this);
// Create the mode indicator controller.
mode_indicator_controller_.reset(
new ModeIndicatorController(InputMethodManager::Get()));
} }
CandidateWindowControllerImpl::~CandidateWindowControllerImpl() { CandidateWindowControllerImpl::~CandidateWindowControllerImpl() {
ui::IMEBridge::Get()->SetCandidateWindowHandler(NULL); ui::IMEBridge::Get()->SetCandidateWindowHandler(nullptr);
if (candidate_window_view_) { if (candidate_window_view_) {
candidate_window_view_->RemoveObserver(this); candidate_window_view_->RemoveObserver(this);
candidate_window_view_->GetWidget()->RemoveObserver(this); candidate_window_view_->GetWidget()->RemoveObserver(this);
...@@ -94,13 +88,14 @@ void CandidateWindowControllerImpl::SetCursorBounds( ...@@ -94,13 +88,14 @@ void CandidateWindowControllerImpl::SetCursorBounds(
// Remember the cursor bounds. // Remember the cursor bounds.
if (candidate_window_view_) if (candidate_window_view_)
candidate_window_view_->SetCursorBounds(cursor_bounds, composition_head); candidate_window_view_->SetCursorBounds(cursor_bounds, composition_head);
}
// Mode indicator controller also needs the cursor bounds. gfx::Rect CandidateWindowControllerImpl::GetCursorBounds() const {
mode_indicator_controller_->SetCursorBounds(cursor_bounds); return is_focused_ ? cursor_bounds_ : gfx::Rect();
} }
void CandidateWindowControllerImpl::FocusStateChanged(bool is_focused) { void CandidateWindowControllerImpl::FocusStateChanged(bool is_focused) {
mode_indicator_controller_->FocusStateChanged(is_focused); is_focused_ = is_focused;
if (candidate_window_view_) if (candidate_window_view_)
candidate_window_view_->HidePreeditText(); candidate_window_view_->HidePreeditText();
} }
...@@ -180,12 +175,12 @@ void CandidateWindowControllerImpl::OnCandidateCommitted(int index) { ...@@ -180,12 +175,12 @@ void CandidateWindowControllerImpl::OnCandidateCommitted(int index) {
void CandidateWindowControllerImpl::OnWidgetClosing(views::Widget* widget) { void CandidateWindowControllerImpl::OnWidgetClosing(views::Widget* widget) {
if (infolist_window_ && widget == infolist_window_->GetWidget()) { if (infolist_window_ && widget == infolist_window_->GetWidget()) {
widget->RemoveObserver(this); widget->RemoveObserver(this);
infolist_window_ = NULL; infolist_window_ = nullptr;
} else if (candidate_window_view_ && } else if (candidate_window_view_ &&
widget == candidate_window_view_->GetWidget()) { widget == candidate_window_view_->GetWidget()) {
widget->RemoveObserver(this); widget->RemoveObserver(this);
candidate_window_view_->RemoveObserver(this); candidate_window_view_->RemoveObserver(this);
candidate_window_view_ = NULL; candidate_window_view_ = nullptr;
for (auto& observer : observers_) for (auto& observer : observers_)
observer.CandidateWindowClosed(); observer.CandidateWindowClosed();
} }
......
...@@ -30,8 +30,6 @@ class Widget; ...@@ -30,8 +30,6 @@ class Widget;
namespace chromeos { namespace chromeos {
namespace input_method { namespace input_method {
class ModeIndicatorController;
// The implementation of CandidateWindowController. // The implementation of CandidateWindowController.
// CandidateWindowController controls the CandidateWindow. // CandidateWindowController controls the CandidateWindow.
class CandidateWindowControllerImpl class CandidateWindowControllerImpl
...@@ -64,6 +62,7 @@ class CandidateWindowControllerImpl ...@@ -64,6 +62,7 @@ class CandidateWindowControllerImpl
// IMECandidateWindowHandlerInterface implementation. // IMECandidateWindowHandlerInterface implementation.
void SetCursorBounds(const gfx::Rect& cursor_bounds, void SetCursorBounds(const gfx::Rect& cursor_bounds,
const gfx::Rect& composition_head) override; const gfx::Rect& composition_head) override;
gfx::Rect GetCursorBounds() const override;
void UpdateLookupTable(const ui::CandidateWindow& candidate_window, void UpdateLookupTable(const ui::CandidateWindow& candidate_window,
bool visible) override; bool visible) override;
void UpdatePreeditText(const base::string16& text, void UpdatePreeditText(const base::string16& text,
...@@ -74,17 +73,16 @@ class CandidateWindowControllerImpl ...@@ -74,17 +73,16 @@ class CandidateWindowControllerImpl
void InitCandidateWindowView(); void InitCandidateWindowView();
// The candidate window view. // The candidate window view.
ui::ime::CandidateWindowView* candidate_window_view_; ui::ime::CandidateWindowView* candidate_window_view_ = nullptr;
// This is the outer frame of the infolist window view. Owned by the widget. // This is the outer frame of the infolist window view. Owned by the widget.
ui::ime::InfolistWindow* infolist_window_; ui::ime::InfolistWindow* infolist_window_ = nullptr;
bool is_focused_ = false;
gfx::Rect cursor_bounds_; gfx::Rect cursor_bounds_;
gfx::Rect composition_head_; gfx::Rect composition_head_;
// This is the controller of the IME mode indicator.
std::unique_ptr<ModeIndicatorController> mode_indicator_controller_;
// The infolist entries and its focused index which currently shown in // The infolist entries and its focused index which currently shown in
// Infolist window. // Infolist window.
std::vector<ui::InfolistEntry> latest_infolist_entries_; std::vector<ui::InfolistEntry> latest_infolist_entries_;
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <algorithm>
#include "ash/shell.h"
#include "base/macros.h"
#include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/ime/chromeos/component_extension_ime_manager.h"
#include "ui/base/ime/chromeos/extension_ime_util.h"
#include "ui/base/ime/chromeos/ime_candidate_window_handler_interface.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/ime/chromeos/input_method_whitelist.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method_factory.h"
#include "ui/display/display.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace chromeos {
namespace input_method {
class ScopedModeIndicatorObserverForTesting :
public ModeIndicatorObserverInterface {
public:
ScopedModeIndicatorObserverForTesting()
: max_widget_list_size_(0) {
ModeIndicatorController::SetModeIndicatorObserverForTesting(this);
}
~ScopedModeIndicatorObserverForTesting() override {
for (size_t i = 0; i < widget_list_.size(); ++i) {
widget_list_[i]->RemoveObserver(this);
}
ModeIndicatorController::SetModeIndicatorObserverForTesting(NULL);
}
gfx::Rect last_bounds() const {
return last_bounds_;
}
bool is_displayed() const {
return is_displayed_;
}
const std::vector<views::Widget*>& widget_list() const {
return widget_list_;
}
size_t widget_list_size() const {
return widget_list_.size();
}
size_t max_widget_list_size() const {
return max_widget_list_size_;
}
// ModeIndicatorObserverInterface override:
void AddModeIndicatorWidget(views::Widget* widget) override {
widget_list_.push_back(widget);
max_widget_list_size_ =
std::max(max_widget_list_size_, widget_list_.size());
widget->AddObserver(this);
}
// views::WidgetObserver override:
void OnWidgetDestroying(views::Widget* widget) override {
std::vector<views::Widget*>::iterator it =
std::find(widget_list_.begin(), widget_list_.end(), widget);
if (it != widget_list_.end())
widget_list_.erase(it);
}
// views::WidgetObserver override:
void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override {
last_bounds_ = widget->GetWindowBoundsInScreen();
is_displayed_ |= visible;
}
private:
bool is_displayed_;
gfx::Rect last_bounds_;
size_t max_widget_list_size_;
std::vector<views::Widget*> widget_list_;
};
class ModeIndicatorBrowserTest : public InProcessBrowserTest {
public:
ModeIndicatorBrowserTest()
: InProcessBrowserTest() {}
~ModeIndicatorBrowserTest() override {}
void SetUpInProcessBrowserTestFixture() override {
ui::SetUpInputMethodFactoryForTesting();
}
void InitializeIMF() {
InputMethodManager::Get()
->GetInputMethodUtil()
->InitXkbInputMethodsForTesting(
*InputMethodWhitelist().GetSupportedInputMethods());
}
private:
DISALLOW_COPY_AND_ASSIGN(ModeIndicatorBrowserTest);
};
namespace {
// 43 is the designed size of the inner contents.
// This value corresponds with kMinSize defined in
// mode_indicator_delegate_view.cc.
const int kInnerSize = 43;
} // namespace
IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, Bounds) {
InitializeIMF();
InputMethodManager* imm = InputMethodManager::Get();
ASSERT_TRUE(imm);
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back(
extension_ime_util::GetInputMethodIDByEngineID("xkb:fr::fra"));
// Add keyboard layouts to enable the mode indicator.
imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts);
ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods());
chromeos::IMECandidateWindowHandlerInterface* candidate_window =
ui::IMEBridge::Get()->GetCandidateWindowHandler();
candidate_window->FocusStateChanged(true);
// Check if the size of the mode indicator is expected.
gfx::Rect cursor1_bounds(100, 100, 1, 20);
gfx::Rect mi1_bounds;
{
ScopedModeIndicatorObserverForTesting observer;
candidate_window->SetCursorBounds(cursor1_bounds, cursor1_bounds);
imm->GetActiveIMEState()->SwitchToNextInputMethod();
mi1_bounds = observer.last_bounds();
// The bounds should be bigger than the inner size.
EXPECT_LE(kInnerSize, mi1_bounds.width());
EXPECT_LE(kInnerSize, mi1_bounds.height());
EXPECT_TRUE(observer.is_displayed());
}
// Check if the location of the mode indicator is coresponded to
// the cursor bounds.
gfx::Rect cursor2_bounds(50, 200, 1, 20);
gfx::Rect mi2_bounds;
{
ScopedModeIndicatorObserverForTesting observer;
candidate_window->SetCursorBounds(cursor2_bounds, cursor2_bounds);
imm->GetActiveIMEState()->SwitchToNextInputMethod();
mi2_bounds = observer.last_bounds();
EXPECT_TRUE(observer.is_displayed());
}
EXPECT_EQ(cursor1_bounds.x() - cursor2_bounds.x(),
mi1_bounds.x() - mi2_bounds.x());
EXPECT_EQ(cursor1_bounds.y() - cursor2_bounds.y(),
mi1_bounds.y() - mi2_bounds.y());
EXPECT_EQ(mi1_bounds.width(), mi2_bounds.width());
EXPECT_EQ(mi1_bounds.height(), mi2_bounds.height());
const gfx::Rect screen_bounds = display::Screen::GetScreen()
->GetDisplayMatching(cursor1_bounds)
.work_area();
// Check if the location of the mode indicator is concidered with
// the screen size.
const gfx::Rect cursor3_bounds(100, screen_bounds.bottom() - 25, 1, 20);
gfx::Rect mi3_bounds;
{
ScopedModeIndicatorObserverForTesting observer;
candidate_window->SetCursorBounds(cursor3_bounds, cursor3_bounds);
imm->GetActiveIMEState()->SwitchToNextInputMethod();
mi3_bounds = observer.last_bounds();
EXPECT_TRUE(observer.is_displayed());
EXPECT_LT(mi3_bounds.bottom(), screen_bounds.bottom());
}
}
IN_PROC_BROWSER_TEST_F(ModeIndicatorBrowserTest, NumOfWidgets) {
InitializeIMF();
InputMethodManager* imm = InputMethodManager::Get();
ASSERT_TRUE(imm);
std::vector<std::string> keyboard_layouts;
keyboard_layouts.push_back(
extension_ime_util::GetInputMethodIDByEngineID("xkb:fr::fra"));
// Add keyboard layouts to enable the mode indicator.
imm->GetActiveIMEState()->EnableLoginLayouts("fr", keyboard_layouts);
ASSERT_LT(1UL, imm->GetActiveIMEState()->GetNumActiveInputMethods());
chromeos::IMECandidateWindowHandlerInterface* candidate_window =
ui::IMEBridge::Get()->GetCandidateWindowHandler();
candidate_window->FocusStateChanged(true);
{
ScopedModeIndicatorObserverForTesting observer;
imm->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(1UL, observer.max_widget_list_size());
const views::Widget* widget1 = observer.widget_list()[0];
imm->GetActiveIMEState()->SwitchToNextInputMethod();
EXPECT_EQ(2UL, observer.max_widget_list_size());
// When a new mode indicator is displayed, the previous one should be
// closed.
content::RunAllPendingInMessageLoop();
EXPECT_EQ(1UL, observer.widget_list_size());
const views::Widget* widget2 = observer.widget_list()[0];
EXPECT_NE(widget1, widget2);
}
}
} // namespace input_method
} // namespace chromeos
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/input_method/mode_indicator_controller.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/window_util.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "mojo/public/cpp/bindings/type_converter.h"
#include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/ui_base_features.h"
namespace chromeos {
namespace input_method {
namespace {
ModeIndicatorObserverInterface* g_mode_indicator_observer_for_testing = nullptr;
// The non-test version of the interface.
class ModeIndicatorObserver : public ModeIndicatorObserverInterface {
public:
ModeIndicatorObserver()
: active_widget_(NULL) {}
~ModeIndicatorObserver() override {
if (active_widget_)
active_widget_->RemoveObserver(this);
}
// If other active mode indicator widget is shown, close it immedicately
// without fading animation. Then store this widget as the active widget.
void AddModeIndicatorWidget(views::Widget* widget) override {
DCHECK(widget);
if (active_widget_)
active_widget_->Close();
active_widget_ = widget;
widget->AddObserver(this);
}
// views::WidgetObserver override:
void OnWidgetDestroying(views::Widget* widget) override {
if (widget == active_widget_)
active_widget_ = NULL;
}
private:
views::Widget* active_widget_;
};
} // namespace
ModeIndicatorController::ModeIndicatorController(InputMethodManager* imm)
: imm_(imm),
is_focused_(false),
mi_observer_(new ModeIndicatorObserver) {
DCHECK(imm_);
imm_->AddObserver(this);
}
ModeIndicatorController::~ModeIndicatorController() {
imm_->RemoveObserver(this);
}
void ModeIndicatorController::SetCursorBounds(
const gfx::Rect& cursor_bounds) {
cursor_bounds_ = cursor_bounds;
}
void ModeIndicatorController::FocusStateChanged(bool is_focused) {
is_focused_ = is_focused;
}
// static
void ModeIndicatorController::SetModeIndicatorObserverForTesting(
ModeIndicatorObserverInterface* observer) {
g_mode_indicator_observer_for_testing = observer;
}
void ModeIndicatorController::InputMethodChanged(InputMethodManager* manager,
Profile* /* profile */,
bool show_message) {
if (!show_message)
return;
ShowModeIndicator();
}
void ModeIndicatorController::InitWidgetContainer(
views::Widget::InitParams* params) {
// The bubble needs to be placed in the proper ash window container, even
// though it is created by Chrome.
// TODO(crbug.com/738531): Consider moving the ModeIndicatorView into ash.
const int container_id = ash::kShellWindowId_SettingBubbleContainer;
if (!features::IsAshInBrowserProcess()) {
using ui::mojom::WindowManager;
params->mus_properties[WindowManager::kContainerId_InitProperty] =
mojo::ConvertTo<std::vector<uint8_t>>(container_id);
} else {
params->parent = ash::Shell::GetContainer(
ash::wm::GetActiveWindow()->GetRootWindow(), container_id);
}
}
void ModeIndicatorController::ShowModeIndicator() {
// TODO(komatsu): Show the mode indicator in the right bottom of the
// display when the launch bar is hidden and the focus is out. To
// implement it, we should consider to use message center or system
// notification. Note, launch bar can be vertical and can be placed
// right/left side of display.
if (!is_focused_)
return;
// Get the short name of the changed input method (e.g. US, JA, etc.)
const InputMethodDescriptor descriptor =
imm_->GetActiveIMEState()->GetCurrentInputMethod();
const base::string16 short_name =
imm_->GetInputMethodUtil()->GetInputMethodShortName(descriptor);
ui::ime::ModeIndicatorView* mi_view =
new ui::ime::ModeIndicatorView(this, cursor_bounds_, short_name);
views::BubbleDialogDelegateView::CreateBubble(mi_view);
views::Widget* mi_widget = mi_view->GetWidget();
if (g_mode_indicator_observer_for_testing)
g_mode_indicator_observer_for_testing->AddModeIndicatorWidget(mi_widget);
mi_observer_->AddModeIndicatorWidget(mi_widget);
mi_view->ShowAndFadeOut();
}
} // namespace input_method
} // namespace chromeos
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_INPUT_METHOD_MODE_INDICATOR_CONTROLLER_H_
#define CHROME_BROWSER_CHROMEOS_INPUT_METHOD_MODE_INDICATOR_CONTROLLER_H_
#include <memory>
#include "base/macros.h"
#include "ui/base/ime/chromeos/input_method_manager.h"
#include "ui/chromeos/ime/mode_indicator_view.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/widget/widget_observer.h"
namespace chromeos {
namespace input_method {
// Publicly visible for testing.
class ModeIndicatorObserverInterface : public views::WidgetObserver {
public:
ModeIndicatorObserverInterface() {}
~ModeIndicatorObserverInterface() override {}
virtual void AddModeIndicatorWidget(views::Widget* widget) = 0;
};
// ModeIndicatorController is the controller of ModeIndicatiorDelegateView
// on the MVC model.
class ModeIndicatorController : public InputMethodManager::Observer,
public ui::ime::ModeIndicatorView::Delegate {
public:
explicit ModeIndicatorController(InputMethodManager* imm);
~ModeIndicatorController() override;
// Set cursor bounds, which is the base point to display this indicator.
// Bacisally this indicator is displayed underneath the cursor.
void SetCursorBounds(const gfx::Rect& cursor_location);
// Notify the focus state to the mode indicator.
void FocusStateChanged(bool is_focused);
// Accessor of the widget observer for testing. The caller keeps the
// ownership of the observer object.
static void SetModeIndicatorObserverForTesting(
ModeIndicatorObserverInterface* observer);
private:
// InputMethodManager::Observer implementation.
void InputMethodChanged(InputMethodManager* manager,
Profile* profile,
bool show_message) override;
// ui::ime::ModeIndicatorView::Delegate:
void InitWidgetContainer(views::Widget::InitParams* params) override;
// Show the mode inidicator with the current ime's short name if all
// the conditions are cleared.
void ShowModeIndicator();
InputMethodManager* imm_;
// Cursor bounds representing the anchor rect of the mode indicator.
gfx::Rect cursor_bounds_;
// True on a text field is focused.
bool is_focused_;
// Observer of the widgets created by BubbleDialogDelegateView. This is used
// to close the previous widget when a new widget is created.
std::unique_ptr<ModeIndicatorObserverInterface> mi_observer_;
DISALLOW_COPY_AND_ASSIGN(ModeIndicatorController);
};
} // namespace input_method
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_INPUT_METHOD_MODE_INDICATOR_CONTROLLER_H_
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "ui/base/ime/chromeos/ime_keyboard.h" #include "ui/base/ime/chromeos/ime_keyboard.h"
#include "ui/base/ime/chromeos/input_method_descriptor.h" #include "ui/base/ime/chromeos/input_method_descriptor.h"
#include "ui/base/ime/chromeos/input_method_util.h" #include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/ime/ime_bridge.h"
using chromeos::input_method::InputMethodDescriptor; using chromeos::input_method::InputMethodDescriptor;
using chromeos::input_method::InputMethodManager; using chromeos::input_method::InputMethodManager;
...@@ -124,6 +125,36 @@ void ImeControllerClient::InputMethodChanged(InputMethodManager* manager, ...@@ -124,6 +125,36 @@ void ImeControllerClient::InputMethodChanged(InputMethodManager* manager,
Profile* profile, Profile* profile,
bool show_message) { bool show_message) {
RefreshIme(); RefreshIme();
if (show_message)
ShowModeIndicator();
}
void ImeControllerClient::ShowModeIndicator() {
// Get the short name of the changed input method (e.g. US, JA, etc.)
const InputMethodDescriptor descriptor =
input_method_manager_->GetActiveIMEState()->GetCurrentInputMethod();
const base::string16 short_name =
input_method_manager_->GetInputMethodUtil()->GetInputMethodShortName(
descriptor);
chromeos::IMECandidateWindowHandlerInterface* cw_handler =
ui::IMEBridge::Get()->GetCandidateWindowHandler();
if (!cw_handler)
return;
gfx::Rect anchor_bounds = cw_handler->GetCursorBounds();
if (anchor_bounds == gfx::Rect()) {
// TODO(shuchen): Show the mode indicator in the right bottom of the
// display when the launch bar is hidden and the focus is out. To
// implement it, we should consider to use message center or system
// notification. Note, launch bar can be vertical and can be placed
// right/left side of display.
return;
}
// Mojo call to Ash to show the mode indicator view with the given anchor
// bounds and short name.
ime_controller_ptr_->ShowModeIndicator(anchor_bounds, short_name);
} }
// chromeos::input_method::InputMethodManager::ImeMenuObserver: // chromeos::input_method::InputMethodManager::ImeMenuObserver:
......
...@@ -85,6 +85,8 @@ class ImeControllerClient ...@@ -85,6 +85,8 @@ class ImeControllerClient
// Sends information about current and available IMEs to ash. // Sends information about current and available IMEs to ash.
void RefreshIme(); void RefreshIme();
void ShowModeIndicator();
chromeos::input_method::InputMethodManager* const input_method_manager_; chromeos::input_method::InputMethodManager* const input_method_manager_;
// Binds this object to the mojo interface. // Binds this object to the mojo interface.
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
#include "ui/base/ime/chromeos/fake_input_method_delegate.h" #include "ui/base/ime/chromeos/fake_input_method_delegate.h"
#include "ui/base/ime/chromeos/input_method_descriptor.h" #include "ui/base/ime/chromeos/input_method_descriptor.h"
#include "ui/base/ime/chromeos/input_method_util.h" #include "ui/base/ime/chromeos/input_method_util.h"
#include "ui/base/ime/chromeos/mock_ime_candidate_window_handler.h"
#include "ui/base/ime/chromeos/mock_input_method_manager.h" #include "ui/base/ime/chromeos/mock_input_method_manager.h"
#include "ui/base/ime/ime_bridge.h"
using chromeos::input_method::FakeInputMethodDelegate; using chromeos::input_method::FakeInputMethodDelegate;
using chromeos::input_method::InputMethodDescriptor; using chromeos::input_method::InputMethodDescriptor;
...@@ -247,6 +249,12 @@ TEST_F(ImeControllerClientTest, ShowImeMenuOnShelf) { ...@@ -247,6 +249,12 @@ TEST_F(ImeControllerClientTest, ShowImeMenuOnShelf) {
} }
TEST_F(ImeControllerClientTest, InputMethodChanged) { TEST_F(ImeControllerClientTest, InputMethodChanged) {
ui::IMEBridge::Initialize();
std::unique_ptr<chromeos::MockIMECandidateWindowHandler>
mock_candidate_window =
std::make_unique<chromeos::MockIMECandidateWindowHandler>();
ui::IMEBridge::Get()->SetCandidateWindowHandler(mock_candidate_window.get());
ImeControllerClient client(&input_method_manager_); ImeControllerClient client(&input_method_manager_);
client.InitForTesting(ime_controller_.CreateInterfacePtr()); client.InitForTesting(ime_controller_.CreateInterfacePtr());
...@@ -265,6 +273,16 @@ TEST_F(ImeControllerClientTest, InputMethodChanged) { ...@@ -265,6 +273,16 @@ TEST_F(ImeControllerClientTest, InputMethodChanged) {
EXPECT_EQ("id2", ime_controller_.available_imes_[1]->id); EXPECT_EQ("id2", ime_controller_.available_imes_[1]->id);
EXPECT_EQ(base::ASCIIToUTF16("name2"), EXPECT_EQ(base::ASCIIToUTF16("name2"),
ime_controller_.available_imes_[1]->name); ime_controller_.available_imes_[1]->name);
EXPECT_FALSE(ime_controller_.show_mode_indicator_);
// Simulate a switch and show message.
input_method_manager_.state_->current_ime_id_ = "id1";
client.InputMethodChanged(&input_method_manager_, nullptr /* profile */,
true /* show_message */);
client.FlushMojoForTesting();
// Mode indicator should be shown.
EXPECT_TRUE(ime_controller_.show_mode_indicator_);
} }
TEST_F(ImeControllerClientTest, NoActiveState) { TEST_F(ImeControllerClientTest, NoActiveState) {
...@@ -283,7 +301,6 @@ TEST_F(ImeControllerClientTest, NoActiveState) { ...@@ -283,7 +301,6 @@ TEST_F(ImeControllerClientTest, NoActiveState) {
TEST_F(ImeControllerClientTest, MenuItemChanged) { TEST_F(ImeControllerClientTest, MenuItemChanged) {
ImeControllerClient client(&input_method_manager_); ImeControllerClient client(&input_method_manager_);
client.InitForTesting(ime_controller_.CreateInterfacePtr()); client.InitForTesting(ime_controller_.CreateInterfacePtr());
const bool is_selection_item = true; const bool is_selection_item = true;
InputMethodMenuItem item1("key1", "label1", is_selection_item, InputMethodMenuItem item1("key1", "label1", is_selection_item,
true /* checked */); true /* checked */);
......
...@@ -1642,7 +1642,6 @@ test("browser_tests") { ...@@ -1642,7 +1642,6 @@ test("browser_tests") {
"../browser/chromeos/first_run/drive_first_run_browsertest.cc", "../browser/chromeos/first_run/drive_first_run_browsertest.cc",
"../browser/chromeos/first_run/goodies_displayer_browsertest.cc", "../browser/chromeos/first_run/goodies_displayer_browsertest.cc",
"../browser/chromeos/input_method/input_method_engine_browsertests.cc", "../browser/chromeos/input_method/input_method_engine_browsertests.cc",
"../browser/chromeos/input_method/mode_indicator_browsertest.cc",
"../browser/chromeos/input_method/textinput_test_helper.cc", "../browser/chromeos/input_method/textinput_test_helper.cc",
"../browser/chromeos/input_method/textinput_test_helper.h", "../browser/chromeos/input_method/textinput_test_helper.h",
"../browser/chromeos/lock_screen_apps/note_taking_browsertest.cc", "../browser/chromeos/lock_screen_apps/note_taking_browsertest.cc",
......
...@@ -39,6 +39,9 @@ class UI_BASE_IME_EXPORT IMECandidateWindowHandlerInterface { ...@@ -39,6 +39,9 @@ class UI_BASE_IME_EXPORT IMECandidateWindowHandlerInterface {
virtual void SetCursorBounds(const gfx::Rect& cursor_bounds, virtual void SetCursorBounds(const gfx::Rect& cursor_bounds,
const gfx::Rect& composition_head) = 0; const gfx::Rect& composition_head) = 0;
// Gets the cursor bounds that was set by |SetCursorBounds| method.
virtual gfx::Rect GetCursorBounds() const = 0;
// Called when the text field's focus state is changed. // Called when the text field's focus state is changed.
// |is_focused| is true when the text field gains the focus. // |is_focused| is true when the text field gains the focus.
virtual void FocusStateChanged(bool is_focused) {} virtual void FocusStateChanged(bool is_focused) {}
......
...@@ -34,6 +34,10 @@ void MockIMECandidateWindowHandler::SetCursorBounds( ...@@ -34,6 +34,10 @@ void MockIMECandidateWindowHandler::SetCursorBounds(
++set_cursor_bounds_call_count_; ++set_cursor_bounds_call_count_;
} }
gfx::Rect MockIMECandidateWindowHandler::GetCursorBounds() const {
return gfx::Rect(1, 1, 1, 1);
}
void MockIMECandidateWindowHandler::Reset() { void MockIMECandidateWindowHandler::Reset() {
set_cursor_bounds_call_count_ = 0; set_cursor_bounds_call_count_ = 0;
update_lookup_table_call_count_ = 0; update_lookup_table_call_count_ = 0;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ui/base/ime/candidate_window.h" #include "ui/base/ime/candidate_window.h"
#include "ui/base/ime/chromeos/ime_candidate_window_handler_interface.h" #include "ui/base/ime/chromeos/ime_candidate_window_handler_interface.h"
#include "ui/base/ime/ui_base_ime_export.h" #include "ui/base/ime/ui_base_ime_export.h"
#include "ui/gfx/geometry/rect.h"
namespace chromeos { namespace chromeos {
...@@ -37,6 +38,7 @@ class UI_BASE_IME_EXPORT MockIMECandidateWindowHandler ...@@ -37,6 +38,7 @@ class UI_BASE_IME_EXPORT MockIMECandidateWindowHandler
bool visible) override; bool visible) override;
void SetCursorBounds(const gfx::Rect& cursor_bounds, void SetCursorBounds(const gfx::Rect& cursor_bounds,
const gfx::Rect& composition_head) override; const gfx::Rect& composition_head) override;
gfx::Rect GetCursorBounds() const override;
int set_cursor_bounds_call_count() const { int set_cursor_bounds_call_count() const {
return set_cursor_bounds_call_count_; return set_cursor_bounds_call_count_;
......
...@@ -22,8 +22,6 @@ component("chromeos") { ...@@ -22,8 +22,6 @@ component("chromeos") {
"ime/input_method_menu_item.h", "ime/input_method_menu_item.h",
"ime/input_method_menu_manager.cc", "ime/input_method_menu_manager.cc",
"ime/input_method_menu_manager.h", "ime/input_method_menu_manager.h",
"ime/mode_indicator_view.cc",
"ime/mode_indicator_view.h",
"user_activity_power_manager_notifier.cc", "user_activity_power_manager_notifier.cc",
"user_activity_power_manager_notifier.h", "user_activity_power_manager_notifier.h",
] ]
......
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