Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2569)

Unified Diff: ash/system/toast/toast_overlay.cc

Issue 1782793002: Ash: Implement Toasts (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add comment Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ash/system/toast/toast_overlay.cc
diff --git a/ash/system/toast/toast_overlay.cc b/ash/system/toast/toast_overlay.cc
new file mode 100644
index 0000000000000000000000000000000000000000..7c442088cf77cc7623a51b782e57da52164d2570
--- /dev/null
+++ b/ash/system/toast/toast_overlay.cc
@@ -0,0 +1,265 @@
+// Copyright 2016 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/system/toast/toast_overlay.h"
+
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "ash/wm/window_animations.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "grit/ash_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_list.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+namespace ash {
+
+namespace {
+
+// Horizontal offset of the overlay from the bottom of the screen.
+const int kVerticalOffset = 5;
+
+// Font style used for modifier key labels.
+const ui::ResourceBundle::FontStyle kTextFontStyle =
+ ui::ResourceBundle::MediumFont;
+
+// Duration of slide animation when overlay is shown or hidden.
+const int kSlideAnimationDurationMs = 100;
+
+} // anonymous namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// ToastOverlayLabel
+class ToastOverlayLabel : public views::Label {
+ public:
+ explicit ToastOverlayLabel(const std::string& label);
+ ~ToastOverlayLabel() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ToastOverlayLabel);
+};
+
+ToastOverlayLabel::ToastOverlayLabel(const std::string& label) {
+ ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+
+ SetText(base::UTF8ToUTF16(label));
+ SetHorizontalAlignment(gfx::ALIGN_LEFT);
+ SetFontList(rb->GetFontList(kTextFontStyle));
+ SetAutoColorReadabilityEnabled(false);
+ SetFocusable(false);
+ SetEnabledColor(SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF));
+ SetDisabledColor(SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF));
+ SetSubpixelRenderingEnabled(false);
+}
+
+ToastOverlayLabel::~ToastOverlayLabel() {}
+
+///////////////////////////////////////////////////////////////////////////////
+// ToastOverlayButton
+class ToastOverlayButton : public views::LabelButton {
+ public:
+ explicit ToastOverlayButton(const base::string16& label,
+ views::ButtonListener* listener);
+ ~ToastOverlayButton() override {}
+
+ private:
+ friend class ToastOverlay; // To call NotifyClick().
+
+ DISALLOW_COPY_AND_ASSIGN(ToastOverlayButton);
+};
+
+ToastOverlayButton::ToastOverlayButton(const base::string16& label,
+ views::ButtonListener* listener)
+ : views::LabelButton(listener, label) {
+ ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
+
+ SetTextColor(STATE_NORMAL, SkColorSetARGB(0xFF, 0x64, 0xA5, 0xF5));
+ SetTextColor(STATE_HOVERED, SkColorSetARGB(0xFF, 0xE3, 0xF2, 0xFD));
+ SetTextColor(STATE_PRESSED, SkColorSetARGB(0xFF, 0x64, 0xA5, 0xF5));
+ SetFontList(rb->GetFontList(kTextFontStyle));
+ SetBorder(views::Border::NullBorder());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ToastOverlayView
+class ToastOverlayView : public views::View, public views::ButtonListener {
+ public:
+ // This object is not owned by the views hiearchy or by the widget.
+ ToastOverlayView(ToastOverlay* overlay, const std::string& text);
+ ~ToastOverlayView() override;
+
+ // views::View overrides:
+ void OnPaint(gfx::Canvas* canvas) override;
+
+ ToastOverlayButton* button() { return button_; }
+
+ private:
+ ToastOverlay* overlay_; // weak
+ ToastOverlayButton* button_; // weak
+
+ void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ DISALLOW_COPY_AND_ASSIGN(ToastOverlayView);
+};
+
+ToastOverlayView::ToastOverlayView(ToastOverlay* overlay,
+ const std::string& text)
+ : overlay_(overlay),
+ button_(new ToastOverlayButton(
+ l10n_util::GetStringUTF16(IDS_ASH_TOAST_DISMISS_BUTTON),
+ this)) {
+ // The parent ToastOverlay object owns this view.
+ set_owned_by_client();
oshima 2016/03/15 09:07:33 this was necessary because you store the view in s
yoshiki 2016/03/15 15:04:22 Thanks! Done.
+
+ const gfx::Font& font =
+ ui::ResourceBundle::GetSharedInstance().GetFont(kTextFontStyle);
+ int font_size = font.GetFontSize();
+
+ // Text should have a margin of 0.5 times the font size on each side, so
+ // the spacing between two labels will be the same as the font size.
+ int horizontal_spacing = font_size * 2;
+ int vertical_spacing = font_size;
+ int child_spacing = font_size * 4;
+
+ SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
+ horizontal_spacing, vertical_spacing,
+ child_spacing));
+
+ ToastOverlayLabel* label = new ToastOverlayLabel(text);
+ AddChildView(label);
+ label->SetVisible(true);
+
+ AddChildView(button_);
+}
+
+ToastOverlayView::~ToastOverlayView() {}
+
+void ToastOverlayView::OnPaint(gfx::Canvas* canvas) {
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SkColorSetARGB(0xFF, 0x32, 0x32, 0x32));
+ canvas->DrawRoundRect(GetLocalBounds(), 2, paint);
+ views::View::OnPaint(canvas);
+}
+
+void ToastOverlayView::ButtonPressed(views::Button* sender,
+ const ui::Event& event) {
+ overlay_->Show(false);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// ToastOverlay
+ToastOverlay::ToastOverlay(Delegate* delegate, const std::string& text)
+ : delegate_(delegate),
+ overlay_view_(new ToastOverlayView(this, text)),
+ widget_size_(overlay_view_->GetPreferredSize()) {
+ views::Widget::InitParams params;
+ params.type = views::Widget::InitParams::TYPE_POPUP;
+ params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.accept_events = true;
+ params.keep_on_top = true;
+ params.remove_standard_frame = true;
+ params.bounds = CalculateOverlayBounds();
+ // Show toasts above the app list and below the lock screen.
+ params.parent = Shell::GetContainer(Shell::GetTargetRootWindow(),
+ kShellWindowId_SystemModalContainer);
+ overlay_widget_.reset(new views::Widget);
+ overlay_widget_->Init(params);
+ overlay_widget_->SetVisibilityChangedAnimationsEnabled(true);
+ overlay_widget_->SetContentsView(overlay_view_.get());
+ overlay_widget_->SetBounds(CalculateOverlayBounds());
+ overlay_widget_->GetNativeView()->SetName("ToastOverlay");
+
+ gfx::NativeWindow native_view = overlay_widget_->GetNativeView();
+ wm::SetWindowVisibilityAnimationType(
+ native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
+ wm::SetWindowVisibilityAnimationDuration(
+ native_view,
+ base::TimeDelta::FromMilliseconds(kSlideAnimationDurationMs));
+}
+
+ToastOverlay::~ToastOverlay() {
+ gfx::NativeWindow native_view = overlay_widget_->GetNativeView();
+ wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_NONE);
+
+ // Remove ourself from the animator to avoid being re-entrantly called in
+ // |overlay_widget_|'s destructor.
+ ui::Layer* layer = overlay_widget_->GetLayer();
+ if (layer) {
+ ui::LayerAnimator* animator = layer->GetAnimator();
+ if (animator)
+ animator->RemoveObserver(this);
+ }
+
+ overlay_widget_->Close();
+}
+
+void ToastOverlay::Show(bool visible) {
+ if (is_visible_ == visible)
+ return;
+
+ is_visible_ = visible;
+
+ overlay_widget_->GetLayer()->GetAnimator()->AddObserver(this);
+
+ if (is_visible_)
+ overlay_widget_->Show();
+ else
+ overlay_widget_->Hide();
+}
+
+gfx::Rect ToastOverlay::CalculateOverlayBounds() {
+ ShelfLayoutManager* shelf_layout_manager =
+ Shelf::ForPrimaryDisplay()->shelf_layout_manager();
+ gfx::Rect root_bounds = Shell::GetPrimaryRootWindow()->bounds();
+ int bottom = (shelf_layout_manager->GetAlignment() == SHELF_ALIGNMENT_BOTTOM)
+ ? shelf_layout_manager->GetIdealBounds().y()
+ : root_bounds.height();
oshima 2016/03/15 09:07:33 Can you use ScreenUtil::GetShelfDisplayBoundsInRoo
yoshiki 2016/03/15 15:04:22 I uses ShelfLayoutManager::user_work_area_bounds()
+
+ return gfx::Rect(gfx::Point((root_bounds.width() - widget_size_.width()) / 2,
+ bottom - widget_size_.height() - kVerticalOffset),
+ widget_size_);
+}
+
+void ToastOverlay::OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) {
+ ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
+ if (animator)
+ animator->RemoveObserver(this);
+ if (!is_visible_) {
+ // Acync operation, since delegate may remove this instance and removing
+ // this here causes crash.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&Delegate::OnClosed, base::Unretained(delegate_)));
+ }
+}
+
+void ToastOverlay::OnLayerAnimationAborted(
+ ui::LayerAnimationSequence* sequence) {
+ ui::LayerAnimator* animator = overlay_widget_->GetLayer()->GetAnimator();
+ if (animator)
+ animator->RemoveObserver(this);
+}
+
+void ToastOverlay::OnLayerAnimationScheduled(
+ ui::LayerAnimationSequence* sequence) {}
+
+void ToastOverlay::ClickDismissButtonForTesting(const ui::Event& event) {
+ overlay_view_->button()->NotifyClick(event);
+}
+
+} // namespace ash
« ash/system/toast/toast_manager_unittest.cc ('K') | « ash/system/toast/toast_overlay.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698