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

Unified Diff: chrome/browser/ui/views/tabs/media_indicator_button.cc

Issue 591963002: Tab audio mute control (views UI), behind a switch (off by default). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase + add about:flags experiment Created 6 years, 3 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
« no previous file with comments | « chrome/browser/ui/views/tabs/media_indicator_button.h ('k') | chrome/browser/ui/views/tabs/tab.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/views/tabs/media_indicator_button.cc
diff --git a/chrome/browser/ui/views/tabs/media_indicator_button.cc b/chrome/browser/ui/views/tabs/media_indicator_button.cc
new file mode 100644
index 0000000000000000000000000000000000000000..afcad3d155600b92ee34aeb7802eefd435f603af
--- /dev/null
+++ b/chrome/browser/ui/views/tabs/media_indicator_button.cc
@@ -0,0 +1,159 @@
+// Copyright 2014 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/ui/views/tabs/media_indicator_button.h"
+
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/browser/ui/views/tabs/tab_controller.h"
+#include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
+#include "content/public/browser/user_metrics.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image.h"
+
+using base::UserMetricsAction;
+
+const char MediaIndicatorButton::kViewClassName[] = "MediaIndicatorButton";
+
+class MediaIndicatorButton::FadeAnimationDelegate
+ : public gfx::AnimationDelegate {
+ public:
+ explicit FadeAnimationDelegate(MediaIndicatorButton* button)
+ : button_(button) {}
+ virtual ~FadeAnimationDelegate() {}
+
+ private:
+ // gfx::AnimationDelegate
+ virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE {
+ button_->SchedulePaint();
+ }
+
+ virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
+ button_->showing_media_state_ = button_->media_state_;
+ button_->SchedulePaint();
+ }
+
+ virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE {
+ button_->showing_media_state_ = button_->media_state_;
+ button_->SchedulePaint();
+ }
+
+ MediaIndicatorButton* const button_;
+
+ DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate);
+};
+
+MediaIndicatorButton::MediaIndicatorButton()
+ : views::ImageButton(NULL),
+ media_state_(TAB_MEDIA_STATE_NONE),
+ showing_media_state_(TAB_MEDIA_STATE_NONE) {
+ SetEventTargeter(
+ scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
+}
+
+MediaIndicatorButton::~MediaIndicatorButton() {}
+
+void MediaIndicatorButton::TransitionToMediaState(TabMediaState next_state) {
+ if (next_state == media_state_)
+ return;
+
+ if (next_state != TAB_MEDIA_STATE_NONE) {
+ const gfx::ImageSkia* const indicator_image =
+ chrome::GetTabMediaIndicatorImage(next_state).ToImageSkia();
+ SetImage(views::CustomButton::STATE_NORMAL, indicator_image);
+ SetImage(views::CustomButton::STATE_DISABLED, indicator_image);
+ const gfx::ImageSkia* const affordance_image =
+ chrome::GetTabMediaIndicatorAffordanceImage(next_state).ToImageSkia();
+ SetImage(views::CustomButton::STATE_HOVERED, affordance_image);
+ SetImage(views::CustomButton::STATE_PRESSED, affordance_image);
+ }
+
+ if ((media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING &&
+ next_state == TAB_MEDIA_STATE_AUDIO_MUTING) ||
+ (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
+ next_state == TAB_MEDIA_STATE_AUDIO_PLAYING) ||
+ (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
+ next_state == TAB_MEDIA_STATE_NONE)) {
+ // Instant user feedback: No fade animation.
+ showing_media_state_ = next_state;
+ fade_animation_.reset();
+ } else {
+ if (next_state == TAB_MEDIA_STATE_NONE)
+ showing_media_state_ = media_state_; // Fading-out indicator.
+ else
+ showing_media_state_ = next_state; // Fading-in to next indicator.
+ fade_animation_ = chrome::CreateTabMediaIndicatorFadeAnimation(next_state);
+ if (!fade_animation_delegate_)
+ fade_animation_delegate_.reset(new FadeAnimationDelegate(this));
+ fade_animation_->set_delegate(fade_animation_delegate_.get());
+ fade_animation_->Start();
+ }
+
+ SetEnabled(chrome::IsTabAudioMutingFeatureEnabled() &&
+ (next_state == TAB_MEDIA_STATE_AUDIO_PLAYING ||
+ next_state == TAB_MEDIA_STATE_AUDIO_MUTING));
+
+ // An indicator state change should be made visible immediately, instead of
+ // the user being surprised when their mouse leaves the button.
+ if (state() == views::CustomButton::STATE_HOVERED) {
+ SetState(enabled() ? views::CustomButton::STATE_NORMAL :
+ views::CustomButton::STATE_DISABLED);
+ }
+
+ media_state_ = next_state;
+
+ // Note: The calls to SetImage(), SetEnabled(), and SetState() above will call
+ // SchedulePaint() if necessary.
+}
+
+const char* MediaIndicatorButton::GetClassName() const {
+ return kViewClassName;
+}
+
+views::View* MediaIndicatorButton::GetTooltipHandlerForPoint(
+ const gfx::Point& point) {
+ return NULL; // Tab (the parent View) provides the tooltip.
+}
+
+bool MediaIndicatorButton::OnMouseDragged(const ui::MouseEvent& event) {
+ const ButtonState previous_state = state();
+ const bool ret = ImageButton::OnMouseDragged(event);
+ if (previous_state != views::CustomButton::STATE_NORMAL &&
+ state() == views::CustomButton::STATE_NORMAL)
+ content::RecordAction(UserMetricsAction("MediaIndicatorButton_Dragged"));
+ return ret;
+}
+
+void MediaIndicatorButton::OnPaint(gfx::Canvas* canvas) {
+ double opaqueness =
+ fade_animation_ ? fade_animation_->GetCurrentValue() : 1.0;
+ if (media_state_ == TAB_MEDIA_STATE_NONE)
+ opaqueness = 1.0 - opaqueness; // Fading out, not in.
+ if (opaqueness < 1.0)
+ canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE);
+ ImageButton::OnPaint(canvas);
+ if (opaqueness < 1.0)
+ canvas->Restore();
+}
+
+bool MediaIndicatorButton::DoesIntersectRect(const views::View* target,
+ const gfx::Rect& rect) const {
+ // If this button is not enabled, Tab (the parent View) handles all mouse
+ // events.
+ return enabled() &&
+ views::ViewTargeterDelegate::DoesIntersectRect(target, rect);
+}
+
+void MediaIndicatorButton::NotifyClick(const ui::Event& event) {
+ if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING)
+ content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute"));
+ else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING)
+ content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute"));
+ else
+ NOTREACHED();
+
+ DCHECK(parent() && !strcmp(parent()->GetClassName(), Tab::kViewClassName));
+ Tab* const tab = static_cast<Tab*>(parent());
+ tab->controller()->ToggleTabAudioMute(tab);
+}
« no previous file with comments | « chrome/browser/ui/views/tabs/media_indicator_button.h ('k') | chrome/browser/ui/views/tabs/tab.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698