1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/system/ime/tray_ime_chromeos.h"
9 #include "ash/metrics/user_metrics_recorder.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/session/session_state_delegate.h"
12 #include "ash/shelf/shelf_widget.h"
13 #include "ash/shell.h"
14 #include "ash/system/tray/hover_highlight_view.h"
15 #include "ash/system/tray/system_tray.h"
16 #include "ash/system/tray/system_tray_delegate.h"
17 #include "ash/system/tray/system_tray_notifier.h"
18 #include "ash/system/tray/tray_constants.h"
19 #include "ash/system/tray/tray_details_view.h"
20 #include "ash/system/tray/tray_item_more.h"
21 #include "ash/system/tray/tray_item_view.h"
22 #include "ash/system/tray/tray_utils.h"
23 #include "ash/system/tray_accessibility.h"
24 #include "ash/virtual_keyboard_controller.h"
25 #include "base/logging.h"
26 #include "base/strings/utf_string_conversions.h"
27 #include "grit/ash_resources.h"
28 #include "grit/ash_strings.h"
29 #include "ui/accessibility/ax_enums.h"
30 #include "ui/accessibility/ax_view_state.h"
31 #include "ui/base/resource/resource_bundle.h"
32 #include "ui/gfx/font.h"
33 #include "ui/gfx/image/image.h"
34 #include "ui/keyboard/keyboard_util.h"
35 #include "ui/views/controls/label.h"
36 #include "ui/views/layout/box_layout.h"
37 #include "ui/views/widget/widget.h"
42 // A |HoverHighlightView| that uses bold or normal font depending on whether
43 // it is selected. This view exposes itself as a checkbox to the accessibility
45 class SelectableHoverHighlightView
: public HoverHighlightView
{
47 SelectableHoverHighlightView(ViewClickListener
* listener
,
48 const base::string16
& label
,
50 : HoverHighlightView(listener
), selected_(selected
) {
51 AddLabel(label
, gfx::ALIGN_LEFT
, selected
);
54 ~SelectableHoverHighlightView() override
{}
57 // Overridden from views::View.
58 void GetAccessibleState(ui::AXViewState
* state
) override
{
59 HoverHighlightView::GetAccessibleState(state
);
60 state
->role
= ui::AX_ROLE_CHECK_BOX
;
62 state
->AddStateFlag(ui::AX_STATE_CHECKED
);
68 DISALLOW_COPY_AND_ASSIGN(SelectableHoverHighlightView
);
71 class IMEDefaultView
: public TrayItemMore
{
73 explicit IMEDefaultView(SystemTrayItem
* owner
, const base::string16
& label
)
74 : TrayItemMore(owner
, true) {
75 ui::ResourceBundle
& bundle
= ui::ResourceBundle::GetSharedInstance();
76 SetImage(bundle
.GetImageNamed(IDR_AURA_UBER_TRAY_IME
).ToImageSkia());
80 ~IMEDefaultView() override
{}
82 void UpdateLabel(const base::string16
& label
) {
84 SetAccessibleName(label
);
88 DISALLOW_COPY_AND_ASSIGN(IMEDefaultView
);
91 class IMEDetailedView
: public TrayDetailsView
, public ViewClickListener
{
93 IMEDetailedView(SystemTrayItem
* owner
,
94 user::LoginStatus login
,
95 bool show_keyboard_toggle
)
96 : TrayDetailsView(owner
), login_(login
) {
97 SystemTrayDelegate
* delegate
= Shell::GetInstance()->system_tray_delegate();
99 delegate
->GetAvailableIMEList(&list
);
100 IMEPropertyInfoList property_list
;
101 delegate
->GetCurrentIMEProperties(&property_list
);
102 Update(list
, property_list
, show_keyboard_toggle
);
105 ~IMEDetailedView() override
{}
107 void Update(const IMEInfoList
& list
,
108 const IMEPropertyInfoList
& property_list
,
109 bool show_keyboard_toggle
) {
112 property_map_
.clear();
113 CreateScrollableList();
117 if (!property_list
.empty())
118 AppendIMEProperties(property_list
);
120 if (show_keyboard_toggle
) {
121 if (list
.size() > 1 || !property_list
.empty())
122 AddScrollSeparator();
123 AppendKeyboardStatus();
126 bool userAddingRunning
= ash::Shell::GetInstance()
127 ->session_state_delegate()
128 ->IsInSecondaryLoginScreen();
129 if (login_
!= user::LOGGED_IN_NONE
&& login_
!= user::LOGGED_IN_LOCKED
&&
139 void AppendHeaderEntry() { CreateSpecialRow(IDS_ASH_STATUS_TRAY_IME
, this); }
141 // Appends the IMEs to the scrollable area of the detailed view.
142 void AppendIMEList(const IMEInfoList
& list
) {
143 DCHECK(ime_map_
.empty());
144 for (size_t i
= 0; i
< list
.size(); i
++) {
145 HoverHighlightView
* container
= new SelectableHoverHighlightView(
146 this, list
[i
].name
, list
[i
].selected
);
147 scroll_content()->AddChildView(container
);
148 ime_map_
[container
] = list
[i
].id
;
152 // Appends the IME listed to the scrollable area of the detailed
154 void AppendIMEProperties(const IMEPropertyInfoList
& property_list
) {
155 DCHECK(property_map_
.empty());
156 for (size_t i
= 0; i
< property_list
.size(); i
++) {
157 HoverHighlightView
* container
= new SelectableHoverHighlightView(
158 this, property_list
[i
].name
, property_list
[i
].selected
);
160 container
->SetBorder(views::Border::CreateSolidSidedBorder(
161 1, 0, 0, 0, kBorderLightColor
));
162 scroll_content()->AddChildView(container
);
163 property_map_
[container
] = property_list
[i
].key
;
167 void AppendKeyboardStatus() {
168 HoverHighlightView
* container
= new HoverHighlightView(this);
169 int id
= keyboard::IsKeyboardEnabled()
170 ? IDS_ASH_STATUS_TRAY_DISABLE_KEYBOARD
171 : IDS_ASH_STATUS_TRAY_ENABLE_KEYBOARD
;
173 ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id
),
174 gfx::ALIGN_LEFT
, false /* highlight */);
175 scroll_content()->AddChildView(container
);
176 keyboard_status_
= container
;
179 void AppendSettings() {
180 HoverHighlightView
* container
= new HoverHighlightView(this);
182 ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
183 IDS_ASH_STATUS_TRAY_IME_SETTINGS
),
184 gfx::ALIGN_LEFT
, false /* highlight */);
185 AddChildView(container
);
186 settings_
= container
;
189 // Overridden from ViewClickListener.
190 void OnViewClicked(views::View
* sender
) override
{
191 SystemTrayDelegate
* delegate
= Shell::GetInstance()->system_tray_delegate();
192 if (sender
== footer()->content()) {
193 TransitionToDefaultView();
194 } else if (sender
== settings_
) {
195 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
196 ash::UMA_STATUS_AREA_IME_SHOW_DETAILED
);
197 delegate
->ShowIMESettings();
198 } else if (sender
== keyboard_status_
) {
199 Shell::GetInstance()->virtual_keyboard_controller()
200 ->ToggleIgnoreExternalKeyboard();
202 std::map
<views::View
*, std::string
>::const_iterator ime_find
;
203 ime_find
= ime_map_
.find(sender
);
204 if (ime_find
!= ime_map_
.end()) {
205 Shell::GetInstance()->metrics()->RecordUserMetricsAction(
206 ash::UMA_STATUS_AREA_IME_SWITCH_MODE
);
207 std::string ime_id
= ime_find
->second
;
208 delegate
->SwitchIME(ime_id
);
209 GetWidget()->Close();
211 std::map
<views::View
*, std::string
>::const_iterator prop_find
;
212 prop_find
= property_map_
.find(sender
);
213 if (prop_find
!= property_map_
.end()) {
214 const std::string key
= prop_find
->second
;
215 delegate
->ActivateIMEProperty(key
);
216 GetWidget()->Close();
222 user::LoginStatus login_
;
224 std::map
<views::View
*, std::string
> ime_map_
;
225 std::map
<views::View
*, std::string
> property_map_
;
226 views::View
* settings_
;
227 views::View
* keyboard_status_
;
229 DISALLOW_COPY_AND_ASSIGN(IMEDetailedView
);
234 TrayIME::TrayIME(SystemTray
* system_tray
)
235 : SystemTrayItem(system_tray
),
239 keyboard_suppressed_(false) {
240 Shell::GetInstance()->system_tray_notifier()->AddIMEObserver(this);
241 Shell::GetInstance()->system_tray_notifier()->AddVirtualKeyboardObserver(
243 Shell::GetInstance()->system_tray_notifier()->AddAccessibilityObserver(this);
246 TrayIME::~TrayIME() {
247 Shell::GetInstance()->system_tray_notifier()->RemoveIMEObserver(this);
248 Shell::GetInstance()->system_tray_notifier()->RemoveAccessibilityObserver(
250 Shell::GetInstance()->system_tray_notifier()->RemoveVirtualKeyboardObserver(
254 void TrayIME::OnKeyboardSuppressionChanged(bool suppressed
) {
255 keyboard_suppressed_
= suppressed
;
259 void TrayIME::OnAccessibilityModeChanged(
260 ui::AccessibilityNotificationVisibility notify
) {
264 void TrayIME::Update() {
265 UpdateTrayLabel(current_ime_
, ime_list_
.size());
267 default_
->SetVisible(ShouldDefaultViewBeVisible());
268 default_
->UpdateLabel(GetDefaultViewLabel(ime_list_
.size() > 1));
271 detailed_
->Update(ime_list_
, property_list_
, ShouldShowKeyboardToggle());
274 void TrayIME::UpdateTrayLabel(const IMEInfo
& current
, size_t count
) {
276 bool visible
= count
> 1;
277 tray_label_
->SetVisible(visible
);
278 // Do not change label before hiding because this change is noticeable.
281 if (current
.third_party
) {
282 tray_label_
->label()->SetText(current
.short_name
+
283 base::UTF8ToUTF16("*"));
285 tray_label_
->label()->SetText(current
.short_name
);
287 SetTrayLabelItemBorder(tray_label_
, system_tray()->shelf_alignment());
288 tray_label_
->Layout();
292 bool TrayIME::ShouldShowKeyboardToggle() {
293 return keyboard_suppressed_
&&
294 !Shell::GetInstance()
295 ->accessibility_delegate()
296 ->IsVirtualKeyboardEnabled();
299 base::string16
TrayIME::GetDefaultViewLabel(bool show_ime_label
) {
300 if (show_ime_label
) {
302 Shell::GetInstance()->system_tray_delegate()->GetCurrentIME(¤t
);
305 // Display virtual keyboard status instead.
306 int id
= keyboard::IsKeyboardEnabled()
307 ? IDS_ASH_STATUS_TRAY_KEYBOARD_ENABLED
308 : IDS_ASH_STATUS_TRAY_KEYBOARD_DISABLED
;
309 return ui::ResourceBundle::GetSharedInstance().GetLocalizedString(id
);
313 views::View
* TrayIME::CreateTrayView(user::LoginStatus status
) {
314 CHECK(tray_label_
== NULL
);
315 tray_label_
= new TrayItemView(this);
316 tray_label_
->CreateLabel();
317 SetupLabelForTray(tray_label_
->label());
318 // Hide IME tray when it is created, it will be updated when it is notified
319 // of the IME refresh event.
320 tray_label_
->SetVisible(false);
324 views::View
* TrayIME::CreateDefaultView(user::LoginStatus status
) {
325 CHECK(default_
== NULL
);
327 new tray::IMEDefaultView(this, GetDefaultViewLabel(ime_list_
.size() > 1));
328 default_
->SetVisible(ShouldDefaultViewBeVisible());
332 views::View
* TrayIME::CreateDetailedView(user::LoginStatus status
) {
333 CHECK(detailed_
== NULL
);
335 new tray::IMEDetailedView(this, status
, ShouldShowKeyboardToggle());
339 void TrayIME::DestroyTrayView() {
343 void TrayIME::DestroyDefaultView() {
347 void TrayIME::DestroyDetailedView() {
351 void TrayIME::UpdateAfterLoginStatusChange(user::LoginStatus status
) {
354 void TrayIME::UpdateAfterShelfAlignmentChange(ShelfAlignment alignment
) {
355 SetTrayLabelItemBorder(tray_label_
, alignment
);
356 tray_label_
->Layout();
359 void TrayIME::OnIMERefresh() {
360 // Caches the current ime state.
361 SystemTrayDelegate
* delegate
= Shell::GetInstance()->system_tray_delegate();
363 property_list_
.clear();
364 delegate
->GetCurrentIME(¤t_ime_
);
365 delegate
->GetAvailableIMEList(&ime_list_
);
366 delegate
->GetCurrentIMEProperties(&property_list_
);
371 bool TrayIME::ShouldDefaultViewBeVisible() {
372 return ime_list_
.size() > 1 || property_list_
.size() > 1 ||
373 ShouldShowKeyboardToggle();