blob: d68f595cb42d39a06e6119ffff343f8fae203ccc [file] [log] [blame]
// 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);
}