11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved. 21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be 31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file. 41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/tabs/media_indicator_button.h" 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/tabs/tab.h" 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/tabs/tab_controller.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/ui/views/tabs/tab_renderer_data.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/user_metrics.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/animation/animation_delegate.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/canvas.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/image/image.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing base::UserMetricsAction; 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char MediaIndicatorButton::kViewClassName[] = "MediaIndicatorButton"; 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass MediaIndicatorButton::FadeAnimationDelegate 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : public gfx::AnimationDelegate { 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public: 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci explicit FadeAnimationDelegate(MediaIndicatorButton* button) 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : button_(button) {} 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual ~FadeAnimationDelegate() {} 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private: 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // gfx::AnimationDelegate 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual void AnimationProgressed(const gfx::Animation* animation) OVERRIDE { 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci button_->SchedulePaint(); 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE { 331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci button_->showing_media_state_ = button_->media_state_; 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci button_->SchedulePaint(); 351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE { 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci button_->showing_media_state_ = button_->media_state_; 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci button_->SchedulePaint(); 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci MediaIndicatorButton* const button_; 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate); 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}; 461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaIndicatorButton::MediaIndicatorButton() 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci : views::ImageButton(NULL), 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci media_state_(TAB_MEDIA_STATE_NONE), 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci showing_media_state_(TAB_MEDIA_STATE_NONE) { 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetEventTargeter( 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaIndicatorButton::~MediaIndicatorButton() {} 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaIndicatorButton::TransitionToMediaState(TabMediaState next_state) { 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (next_state == media_state_) 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (next_state != TAB_MEDIA_STATE_NONE) { 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const gfx::ImageSkia* const indicator_image = 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci chrome::GetTabMediaIndicatorImage(next_state).ToImageSkia(); 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetImage(views::CustomButton::STATE_NORMAL, indicator_image); 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetImage(views::CustomButton::STATE_DISABLED, indicator_image); 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const gfx::ImageSkia* const affordance_image = 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci chrome::GetTabMediaIndicatorAffordanceImage(next_state).ToImageSkia(); 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetImage(views::CustomButton::STATE_HOVERED, affordance_image); 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetImage(views::CustomButton::STATE_PRESSED, affordance_image); 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if ((media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING && 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci next_state == TAB_MEDIA_STATE_AUDIO_MUTING) || 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING && 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci next_state == TAB_MEDIA_STATE_AUDIO_PLAYING) || 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING && 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci next_state == TAB_MEDIA_STATE_NONE)) { 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Instant user feedback: No fade animation. 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci showing_media_state_ = next_state; 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_.reset(); 811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (next_state == TAB_MEDIA_STATE_NONE) 831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci showing_media_state_ = media_state_; // Fading-out indicator. 841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else 851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci showing_media_state_ = next_state; // Fading-in to next indicator. 861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_ = chrome::CreateTabMediaIndicatorFadeAnimation(next_state); 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!fade_animation_delegate_) 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_delegate_.reset(new FadeAnimationDelegate(this)); 891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_->set_delegate(fade_animation_delegate_.get()); 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_->Start(); 911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetEnabled(chrome::IsTabAudioMutingFeatureEnabled() && 941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci (next_state == TAB_MEDIA_STATE_AUDIO_PLAYING || 951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci next_state == TAB_MEDIA_STATE_AUDIO_MUTING)); 961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // An indicator state change should be made visible immediately, instead of 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // the user being surprised when their mouse leaves the button. 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (state() == views::CustomButton::STATE_HOVERED) { 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SetState(enabled() ? views::CustomButton::STATE_NORMAL : 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci views::CustomButton::STATE_DISABLED); 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci media_state_ = next_state; 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Note: The calls to SetImage(), SetEnabled(), and SetState() above will call 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // SchedulePaint() if necessary. 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char* MediaIndicatorButton::GetClassName() const { 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return kViewClassName; 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciviews::View* MediaIndicatorButton::GetTooltipHandlerForPoint( 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const gfx::Point& point) { 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return NULL; // Tab (the parent View) provides the tooltip. 1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool MediaIndicatorButton::OnMouseDragged(const ui::MouseEvent& event) { 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ButtonState previous_state = state(); 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const bool ret = ImageButton::OnMouseDragged(event); 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (previous_state != views::CustomButton::STATE_NORMAL && 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci state() == views::CustomButton::STATE_NORMAL) 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::RecordAction(UserMetricsAction("MediaIndicatorButton_Dragged")); 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return ret; 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaIndicatorButton::OnPaint(gfx::Canvas* canvas) { 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci double opaqueness = 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci fade_animation_ ? fade_animation_->GetCurrentValue() : 1.0; 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (media_state_ == TAB_MEDIA_STATE_NONE) 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci opaqueness = 1.0 - opaqueness; // Fading out, not in. 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (opaqueness < 1.0) 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE); 1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ImageButton::OnPaint(canvas); 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (opaqueness < 1.0) 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci canvas->Restore(); 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool MediaIndicatorButton::DoesIntersectRect(const views::View* target, 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const gfx::Rect& rect) const { 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If this button is not enabled, Tab (the parent View) handles all mouse 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // events. 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return enabled() && 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci views::ViewTargeterDelegate::DoesIntersectRect(target, rect); 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaIndicatorButton::NotifyClick(const ui::Event& event) { 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING) 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute")); 1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING) 1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute")); 1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else 1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci NOTREACHED(); 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(parent() && !strcmp(parent()->GetClassName(), Tab::kViewClassName)); 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Tab* const tab = static_cast<Tab*>(parent()); 1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tab->controller()->ToggleTabAudioMute(tab); 1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 160