OLD | NEW |
| (Empty) |
1 // Copyright 2016 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. | |
4 | |
5 #include "ash/common/system/chromeos/palette/palette_tray.h" | |
6 | |
7 #include "ash/common/material_design/material_design_controller.h" | |
8 #include "ash/common/session/session_state_delegate.h" | |
9 #include "ash/common/shelf/shelf_constants.h" | |
10 #include "ash/common/shelf/wm_shelf.h" | |
11 #include "ash/common/shelf/wm_shelf_util.h" | |
12 #include "ash/common/system/chromeos/palette/palette_tool_manager.h" | |
13 #include "ash/common/system/chromeos/palette/palette_utils.h" | |
14 #include "ash/common/system/tray/system_menu_button.h" | |
15 #include "ash/common/system/tray/system_tray_controller.h" | |
16 #include "ash/common/system/tray/system_tray_delegate.h" | |
17 #include "ash/common/system/tray/tray_bubble_wrapper.h" | |
18 #include "ash/common/system/tray/tray_constants.h" | |
19 #include "ash/common/system/tray/tray_popup_header_button.h" | |
20 #include "ash/common/system/tray/tray_popup_item_style.h" | |
21 #include "ash/common/wm_shell.h" | |
22 #include "ash/common/wm_window.h" | |
23 #include "ash/public/cpp/shell_window_ids.h" | |
24 #include "ash/resources/grit/ash_resources.h" | |
25 #include "ash/resources/vector_icons/vector_icons.h" | |
26 #include "ash/root_window_controller.h" | |
27 #include "ash/strings/grit/ash_strings.h" | |
28 #include "base/metrics/histogram_macros.h" | |
29 #include "ui/base/l10n/l10n_util.h" | |
30 #include "ui/base/resource/resource_bundle.h" | |
31 #include "ui/events/devices/input_device_manager.h" | |
32 #include "ui/events/devices/stylus_state.h" | |
33 #include "ui/gfx/color_palette.h" | |
34 #include "ui/gfx/paint_vector_icon.h" | |
35 #include "ui/gfx/vector_icons_public.h" | |
36 #include "ui/views/controls/image_view.h" | |
37 #include "ui/views/controls/label.h" | |
38 #include "ui/views/controls/separator.h" | |
39 #include "ui/views/layout/box_layout.h" | |
40 #include "ui/views/layout/fill_layout.h" | |
41 | |
42 namespace ash { | |
43 | |
44 namespace { | |
45 | |
46 // Padding for tray icon (dp; the button that shows the palette menu). | |
47 constexpr int kTrayIconMainAxisInset = 8; | |
48 constexpr int kTrayIconCrossAxisInset = 0; | |
49 | |
50 // Width of the palette itself (dp). | |
51 constexpr int kPaletteWidth = 332; | |
52 | |
53 // Padding at the top/bottom of the palette (dp). | |
54 constexpr int kPalettePaddingOnTop = 4; | |
55 constexpr int kPalettePaddingOnBottom = 2; | |
56 | |
57 // Margins between the title view and the edges around it (dp). | |
58 constexpr int kPaddingBetweenTitleAndLeftEdge = 12; | |
59 constexpr int kPaddingBetweenTitleAndSeparator = 3; | |
60 | |
61 // Color of the separator. | |
62 const SkColor kPaletteSeparatorColor = SkColorSetARGB(0x1E, 0x00, 0x00, 0x00); | |
63 | |
64 // Returns true if we are in a user session that can show the stylus tools. | |
65 bool IsInUserSession() { | |
66 SessionStateDelegate* session_state_delegate = | |
67 WmShell::Get()->GetSessionStateDelegate(); | |
68 return !session_state_delegate->IsUserSessionBlocked() && | |
69 session_state_delegate->GetSessionState() == | |
70 session_manager::SessionState::ACTIVE && | |
71 WmShell::Get()->system_tray_delegate()->GetUserLoginStatus() != | |
72 LoginStatus::KIOSK_APP; | |
73 } | |
74 | |
75 class TitleView : public views::View, public views::ButtonListener { | |
76 public: | |
77 explicit TitleView(PaletteTray* palette_tray) : palette_tray_(palette_tray) { | |
78 // TODO(tdanderson|jdufault): Use TriView to handle the layout of the title. | |
79 // See crbug.com/614453. | |
80 auto* box_layout = | |
81 new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0); | |
82 SetLayoutManager(box_layout); | |
83 | |
84 auto* title_label = | |
85 new views::Label(l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE)); | |
86 title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); | |
87 AddChildView(title_label); | |
88 TrayPopupItemStyle style(TrayPopupItemStyle::FontStyle::TITLE); | |
89 style.SetupLabel(title_label); | |
90 box_layout->SetFlexForView(title_label, 1); | |
91 if (MaterialDesignController::IsSystemTrayMenuMaterial()) { | |
92 help_button_ = | |
93 new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, | |
94 kSystemMenuHelpIcon, IDS_ASH_STATUS_TRAY_HELP); | |
95 settings_button_ = new SystemMenuButton( | |
96 this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon, | |
97 IDS_ASH_PALETTE_SETTINGS); | |
98 } else { | |
99 gfx::ImageSkia help_icon = | |
100 gfx::CreateVectorIcon(kSystemMenuHelpIcon, kMenuIconColor); | |
101 gfx::ImageSkia settings_icon = | |
102 gfx::CreateVectorIcon(kSystemMenuSettingsIcon, kMenuIconColor); | |
103 | |
104 auto* help_button = new ash::TrayPopupHeaderButton( | |
105 this, help_icon, IDS_ASH_STATUS_TRAY_HELP); | |
106 help_button->SetTooltipText( | |
107 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HELP)); | |
108 help_button_ = help_button; | |
109 | |
110 auto* settings_button = new ash::TrayPopupHeaderButton( | |
111 this, settings_icon, IDS_ASH_STATUS_TRAY_SETTINGS); | |
112 settings_button->SetTooltipText( | |
113 l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SETTINGS)); | |
114 settings_button_ = settings_button; | |
115 } | |
116 | |
117 AddChildView(help_button_); | |
118 AddChildView(settings_button_); | |
119 } | |
120 | |
121 ~TitleView() override {} | |
122 | |
123 private: | |
124 // views::ButtonListener: | |
125 void ButtonPressed(views::Button* sender, const ui::Event& event) override { | |
126 if (sender == settings_button_) { | |
127 palette_tray_->RecordPaletteOptionsUsage( | |
128 PaletteTrayOptions::PALETTE_SETTINGS_BUTTON); | |
129 WmShell::Get()->system_tray_controller()->ShowPaletteSettings(); | |
130 palette_tray_->HidePalette(); | |
131 } else if (sender == help_button_) { | |
132 palette_tray_->RecordPaletteOptionsUsage( | |
133 PaletteTrayOptions::PALETTE_HELP_BUTTON); | |
134 WmShell::Get()->system_tray_controller()->ShowPaletteHelp(); | |
135 palette_tray_->HidePalette(); | |
136 } else { | |
137 NOTREACHED(); | |
138 } | |
139 } | |
140 | |
141 // Unowned pointers to button views so we can determine which button was | |
142 // clicked. | |
143 views::View* settings_button_; | |
144 views::View* help_button_; | |
145 PaletteTray* palette_tray_; | |
146 | |
147 DISALLOW_COPY_AND_ASSIGN(TitleView); | |
148 }; | |
149 | |
150 } // namespace | |
151 | |
152 PaletteTray::PaletteTray(WmShelf* wm_shelf) | |
153 : TrayBackgroundView(wm_shelf), | |
154 palette_tool_manager_(new PaletteToolManager(this)), | |
155 weak_factory_(this) { | |
156 PaletteTool::RegisterToolInstances(palette_tool_manager_.get()); | |
157 | |
158 if (MaterialDesignController::IsShelfMaterial()) { | |
159 SetInkDropMode(InkDropMode::ON); | |
160 SetContentsBackground(false); | |
161 } else { | |
162 SetContentsBackground(true); | |
163 } | |
164 | |
165 SetLayoutManager(new views::FillLayout()); | |
166 icon_ = new views::ImageView(); | |
167 UpdateTrayIcon(); | |
168 | |
169 tray_container()->SetMargin(kTrayIconMainAxisInset, kTrayIconCrossAxisInset); | |
170 tray_container()->AddChildView(icon_); | |
171 | |
172 WmShell::Get()->AddShellObserver(this); | |
173 WmShell::Get()->GetSessionStateDelegate()->AddSessionStateObserver(this); | |
174 ui::InputDeviceManager::GetInstance()->AddObserver(this); | |
175 } | |
176 | |
177 PaletteTray::~PaletteTray() { | |
178 if (bubble_) | |
179 bubble_->bubble_view()->reset_delegate(); | |
180 | |
181 ui::InputDeviceManager::GetInstance()->RemoveObserver(this); | |
182 WmShell::Get()->RemoveShellObserver(this); | |
183 WmShell::Get()->GetSessionStateDelegate()->RemoveSessionStateObserver(this); | |
184 } | |
185 | |
186 bool PaletteTray::PerformAction(const ui::Event& event) { | |
187 if (bubble_) { | |
188 if (num_actions_in_bubble_ == 0) | |
189 RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); | |
190 HidePalette(); | |
191 return true; | |
192 } | |
193 | |
194 return ShowPalette(); | |
195 } | |
196 | |
197 bool PaletteTray::ShowPalette() { | |
198 if (bubble_) | |
199 return false; | |
200 | |
201 DCHECK(tray_container()); | |
202 | |
203 views::TrayBubbleView::InitParams init_params(GetAnchorAlignment(), | |
204 kPaletteWidth, kPaletteWidth); | |
205 init_params.can_activate = true; | |
206 init_params.close_on_deactivate = true; | |
207 | |
208 DCHECK(tray_container()); | |
209 | |
210 // The views::TrayBubbleView ctor will cause a shelf auto hide update check. | |
211 // Make sure to block auto hiding before that check happens. | |
212 should_block_shelf_auto_hide_ = true; | |
213 | |
214 // TODO(tdanderson): Refactor into common row layout code. | |
215 // TODO(tdanderson|jdufault): Add material design ripple effects to the menu | |
216 // rows. | |
217 | |
218 // Create and customize bubble view. | |
219 views::TrayBubbleView* bubble_view = | |
220 views::TrayBubbleView::Create(GetBubbleAnchor(), this, &init_params); | |
221 bubble_view->set_anchor_view_insets(GetBubbleAnchorInsets()); | |
222 bubble_view->set_margins( | |
223 gfx::Insets(kPalettePaddingOnTop, 0, kPalettePaddingOnBottom, 0)); | |
224 | |
225 // Add title. | |
226 auto* title_view = new TitleView(this); | |
227 title_view->SetBorder(views::CreateEmptyBorder( | |
228 gfx::Insets(0, kPaddingBetweenTitleAndLeftEdge, 0, 0))); | |
229 bubble_view->AddChildView(title_view); | |
230 | |
231 // Add horizontal separator. | |
232 views::Separator* separator = new views::Separator(); | |
233 separator->SetColor(kPaletteSeparatorColor); | |
234 separator->SetBorder(views::CreateEmptyBorder(gfx::Insets( | |
235 kPaddingBetweenTitleAndSeparator, 0, kMenuSeparatorVerticalPadding, 0))); | |
236 bubble_view->AddChildView(separator); | |
237 | |
238 // Add palette tools. | |
239 // TODO(tdanderson|jdufault): Use SystemMenuButton to get the material design | |
240 // ripples. | |
241 std::vector<PaletteToolView> views = palette_tool_manager_->CreateViews(); | |
242 for (const PaletteToolView& view : views) | |
243 bubble_view->AddChildView(view.view); | |
244 | |
245 // Show the bubble. | |
246 bubble_.reset(new ash::TrayBubbleWrapper(this, bubble_view)); | |
247 SetIsActive(true); | |
248 return true; | |
249 } | |
250 | |
251 bool PaletteTray::ContainsPointInScreen(const gfx::Point& point) { | |
252 if (icon_ && icon_->GetBoundsInScreen().Contains(point)) | |
253 return true; | |
254 | |
255 return bubble_ && bubble_->bubble_view()->GetBoundsInScreen().Contains(point); | |
256 } | |
257 | |
258 void PaletteTray::SessionStateChanged(session_manager::SessionState state) { | |
259 UpdateIconVisibility(); | |
260 } | |
261 | |
262 void PaletteTray::OnLockStateChanged(bool locked) { | |
263 UpdateIconVisibility(); | |
264 | |
265 // The user can eject the stylus during the lock screen transition, which will | |
266 // open the palette. Make sure to close it if that happens. | |
267 if (locked) | |
268 HidePalette(); | |
269 } | |
270 | |
271 void PaletteTray::ClickedOutsideBubble() { | |
272 if (num_actions_in_bubble_ == 0) | |
273 RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION); | |
274 HidePalette(); | |
275 } | |
276 | |
277 base::string16 PaletteTray::GetAccessibleNameForTray() { | |
278 return l10n_util::GetStringUTF16(IDS_ASH_STYLUS_TOOLS_TITLE); | |
279 } | |
280 | |
281 void PaletteTray::HideBubbleWithView(const views::TrayBubbleView* bubble_view) { | |
282 if (bubble_->bubble_view() == bubble_view) | |
283 HidePalette(); | |
284 } | |
285 | |
286 void PaletteTray::OnTouchscreenDeviceConfigurationChanged() { | |
287 UpdateIconVisibility(); | |
288 } | |
289 | |
290 void PaletteTray::OnStylusStateChanged(ui::StylusState stylus_state) { | |
291 PaletteDelegate* palette_delegate = WmShell::Get()->palette_delegate(); | |
292 | |
293 // Don't do anything if the palette should not be shown or if the user has | |
294 // disabled it all-together. | |
295 if (!IsInUserSession() || !palette_delegate->ShouldShowPalette()) | |
296 return; | |
297 | |
298 // Auto show/hide the palette if allowed by the user. | |
299 if (palette_delegate->ShouldAutoOpenPalette()) { | |
300 if (stylus_state == ui::StylusState::REMOVED && !bubble_) { | |
301 is_bubble_auto_opened_ = true; | |
302 ShowPalette(); | |
303 } else if (stylus_state == ui::StylusState::INSERTED && bubble_) { | |
304 HidePalette(); | |
305 } | |
306 } | |
307 | |
308 // Disable any active modes if the stylus has been inserted. | |
309 if (stylus_state == ui::StylusState::INSERTED) | |
310 palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); | |
311 } | |
312 | |
313 void PaletteTray::BubbleViewDestroyed() { | |
314 palette_tool_manager_->NotifyViewsDestroyed(); | |
315 SetIsActive(false); | |
316 } | |
317 | |
318 void PaletteTray::OnMouseEnteredView() {} | |
319 | |
320 void PaletteTray::OnMouseExitedView() {} | |
321 | |
322 base::string16 PaletteTray::GetAccessibleNameForBubble() { | |
323 return GetAccessibleNameForTray(); | |
324 } | |
325 | |
326 void PaletteTray::OnBeforeBubbleWidgetInit( | |
327 views::Widget* anchor_widget, | |
328 views::Widget* bubble_widget, | |
329 views::Widget::InitParams* params) const { | |
330 // Place the bubble in the same root window as |anchor_widget|. | |
331 WmWindow::Get(anchor_widget->GetNativeWindow()) | |
332 ->GetRootWindowController() | |
333 ->ConfigureWidgetInitParamsForContainer( | |
334 bubble_widget, kShellWindowId_SettingBubbleContainer, params); | |
335 } | |
336 | |
337 void PaletteTray::HideBubble(const views::TrayBubbleView* bubble_view) { | |
338 HideBubbleWithView(bubble_view); | |
339 } | |
340 | |
341 void PaletteTray::HidePalette() { | |
342 should_block_shelf_auto_hide_ = false; | |
343 is_bubble_auto_opened_ = false; | |
344 num_actions_in_bubble_ = 0; | |
345 bubble_.reset(); | |
346 | |
347 shelf()->UpdateAutoHideState(); | |
348 } | |
349 | |
350 void PaletteTray::HidePaletteImmediately() { | |
351 if (bubble_) | |
352 bubble_->bubble_widget()->SetVisibilityChangedAnimationsEnabled(false); | |
353 HidePalette(); | |
354 } | |
355 | |
356 void PaletteTray::RecordPaletteOptionsUsage(PaletteTrayOptions option) { | |
357 DCHECK_NE(option, PaletteTrayOptions::PALETTE_OPTIONS_COUNT); | |
358 | |
359 if (is_bubble_auto_opened_) { | |
360 UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage.AutoOpened", option, | |
361 PaletteTrayOptions::PALETTE_OPTIONS_COUNT); | |
362 } else { | |
363 UMA_HISTOGRAM_ENUMERATION("Ash.Shelf.Palette.Usage", option, | |
364 PaletteTrayOptions::PALETTE_OPTIONS_COUNT); | |
365 } | |
366 } | |
367 | |
368 void PaletteTray::RecordPaletteModeCancellation(PaletteModeCancelType type) { | |
369 if (type == PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT) | |
370 return; | |
371 | |
372 UMA_HISTOGRAM_ENUMERATION( | |
373 "Ash.Shelf.Palette.ModeCancellation", type, | |
374 PaletteModeCancelType::PALETTE_MODE_CANCEL_TYPE_COUNT); | |
375 } | |
376 | |
377 bool PaletteTray::ShouldBlockShelfAutoHide() const { | |
378 return should_block_shelf_auto_hide_; | |
379 } | |
380 | |
381 void PaletteTray::OnActiveToolChanged() { | |
382 ++num_actions_in_bubble_; | |
383 UpdateTrayIcon(); | |
384 } | |
385 | |
386 WmWindow* PaletteTray::GetWindow() { | |
387 return shelf()->GetWindow(); | |
388 } | |
389 | |
390 void PaletteTray::SetShelfAlignment(ShelfAlignment alignment) { | |
391 if (alignment == shelf_alignment()) | |
392 return; | |
393 | |
394 TrayBackgroundView::SetShelfAlignment(alignment); | |
395 } | |
396 | |
397 void PaletteTray::AnchorUpdated() { | |
398 if (bubble_) | |
399 bubble_->bubble_view()->UpdateBubble(); | |
400 } | |
401 | |
402 void PaletteTray::Initialize() { | |
403 PaletteDelegate* delegate = WmShell::Get()->palette_delegate(); | |
404 // |delegate| can be null in tests. | |
405 if (!delegate) | |
406 return; | |
407 | |
408 // OnPaletteEnabledPrefChanged will get called with the initial pref value, | |
409 // which will take care of showing the palette. | |
410 palette_enabled_subscription_ = delegate->AddPaletteEnableListener(base::Bind( | |
411 &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr())); | |
412 } | |
413 | |
414 void PaletteTray::UpdateTrayIcon() { | |
415 icon_->SetImage(CreateVectorIcon( | |
416 palette_tool_manager_->GetActiveTrayIcon( | |
417 palette_tool_manager_->GetActiveTool(ash::PaletteGroup::MODE)), | |
418 kTrayIconSize, kShelfIconColor)); | |
419 } | |
420 | |
421 void PaletteTray::OnPaletteEnabledPrefChanged(bool enabled) { | |
422 is_palette_enabled_ = enabled; | |
423 | |
424 if (!enabled) { | |
425 SetVisible(false); | |
426 palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE); | |
427 } else { | |
428 UpdateIconVisibility(); | |
429 } | |
430 } | |
431 | |
432 void PaletteTray::UpdateIconVisibility() { | |
433 SetVisible(is_palette_enabled_ && palette_utils::HasStylusInput() && | |
434 IsInUserSession()); | |
435 } | |
436 | |
437 } // namespace ash | |
OLD | NEW |