Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / browser / ui / tabs / tab_utils.cc
blob18cd10e40a94b093bdb3106f5e4707d6f8939987
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/tabs/tab_utils.h"
7 #include "base/command_line.h"
8 #include "base/strings/string16.h"
9 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
10 #include "chrome/browser/media/media_stream_capture_indicator.h"
11 #include "chrome/browser/ui/tabs/tab_strip_model.h"
12 #include "chrome/common/chrome_switches.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "content/public/browser/web_contents.h"
15 #include "grit/theme_resources.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/gfx/animation/multi_animation.h"
20 struct LastMuteMetadata
21 : public content::WebContentsUserData<LastMuteMetadata> {
22 std::string cause; // Extension ID or constant from header file
23 // or empty string
24 private:
25 explicit LastMuteMetadata(content::WebContents* contents) {}
26 friend class content::WebContentsUserData<LastMuteMetadata>;
29 DEFINE_WEB_CONTENTS_USER_DATA_KEY(LastMuteMetadata);
31 namespace chrome {
33 const char kMutedToggleCauseUser[] = "user";
34 const char kMutedToggleCauseCapture[] = "auto-forced for capture";
36 namespace {
38 // Interval between frame updates of the tab indicator animations. This is not
39 // the usual 60 FPS because a trade-off must be made between tab UI animation
40 // smoothness and media recording/playback performance on low-end hardware.
41 const int kIndicatorFrameIntervalMs = 50; // 20 FPS
43 // Fade-in/out duration for the tab indicator animations. Fade-in is quick to
44 // immediately notify the user. Fade-out is more gradual, so that the user has
45 // a chance of finding a tab that has quickly "blipped" on and off.
46 const int kIndicatorFadeInDurationMs = 200;
47 const int kIndicatorFadeOutDurationMs = 1000;
49 // Animation that throbs in (towards 1.0) and out (towards 0.0), and ends in the
50 // "in" state.
51 class TabRecordingIndicatorAnimation : public gfx::MultiAnimation {
52 public:
53 ~TabRecordingIndicatorAnimation() override {}
55 // Overridden to provide alternating "towards in" and "towards out" behavior.
56 double GetCurrentValue() const override;
58 static scoped_ptr<TabRecordingIndicatorAnimation> Create();
60 private:
61 TabRecordingIndicatorAnimation(const gfx::MultiAnimation::Parts& parts,
62 const base::TimeDelta interval)
63 : MultiAnimation(parts, interval) {}
65 // Number of times to "toggle throb" the recording and tab capture indicators
66 // when they first appear.
67 static const int kCaptureIndicatorThrobCycles = 5;
70 double TabRecordingIndicatorAnimation::GetCurrentValue() const {
71 return current_part_index() % 2 ?
72 1.0 - MultiAnimation::GetCurrentValue() :
73 MultiAnimation::GetCurrentValue();
76 scoped_ptr<TabRecordingIndicatorAnimation>
77 TabRecordingIndicatorAnimation::Create() {
78 MultiAnimation::Parts parts;
79 static_assert(kCaptureIndicatorThrobCycles % 2 != 0,
80 "odd number of cycles required so animation finishes in showing state");
81 for (int i = 0; i < kCaptureIndicatorThrobCycles; ++i) {
82 parts.push_back(MultiAnimation::Part(
83 i % 2 ? kIndicatorFadeOutDurationMs : kIndicatorFadeInDurationMs,
84 gfx::Tween::EASE_IN));
86 const base::TimeDelta interval =
87 base::TimeDelta::FromMilliseconds(kIndicatorFrameIntervalMs);
88 scoped_ptr<TabRecordingIndicatorAnimation> animation(
89 new TabRecordingIndicatorAnimation(parts, interval));
90 animation->set_continuous(false);
91 return animation.Pass();
94 } // namespace
96 bool ShouldTabShowFavicon(int capacity,
97 bool is_pinned_tab,
98 bool is_active_tab,
99 bool has_favicon,
100 TabMediaState media_state) {
101 if (!has_favicon)
102 return false;
103 int required_capacity = 1;
104 if (ShouldTabShowCloseButton(capacity, is_pinned_tab, is_active_tab))
105 ++required_capacity;
106 if (ShouldTabShowMediaIndicator(
107 capacity, is_pinned_tab, is_active_tab, has_favicon, media_state)) {
108 ++required_capacity;
110 return capacity >= required_capacity;
113 bool ShouldTabShowMediaIndicator(int capacity,
114 bool is_pinned_tab,
115 bool is_active_tab,
116 bool has_favicon,
117 TabMediaState media_state) {
118 if (media_state == TAB_MEDIA_STATE_NONE)
119 return false;
120 if (ShouldTabShowCloseButton(capacity, is_pinned_tab, is_active_tab))
121 return capacity >= 2;
122 return capacity >= 1;
125 bool ShouldTabShowCloseButton(int capacity,
126 bool is_pinned_tab,
127 bool is_active_tab) {
128 if (is_pinned_tab)
129 return false;
130 else if (is_active_tab)
131 return true;
132 else
133 return capacity >= 3;
136 bool IsPlayingAudio(content::WebContents* contents) {
137 return contents->WasRecentlyAudible();
140 TabMediaState GetTabMediaStateForContents(content::WebContents* contents) {
141 if (!contents)
142 return TAB_MEDIA_STATE_NONE;
144 scoped_refptr<MediaStreamCaptureIndicator> indicator =
145 MediaCaptureDevicesDispatcher::GetInstance()->
146 GetMediaStreamCaptureIndicator();
147 if (indicator.get()) {
148 if (indicator->IsBeingMirrored(contents))
149 return TAB_MEDIA_STATE_CAPTURING;
150 if (indicator->IsCapturingUserMedia(contents))
151 return TAB_MEDIA_STATE_RECORDING;
154 if (IsTabAudioMutingFeatureEnabled() && contents->IsAudioMuted())
155 return TAB_MEDIA_STATE_AUDIO_MUTING;
156 if (IsPlayingAudio(contents))
157 return TAB_MEDIA_STATE_AUDIO_PLAYING;
159 return TAB_MEDIA_STATE_NONE;
162 const gfx::Image& GetTabMediaIndicatorImage(TabMediaState media_state) {
163 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
164 switch (media_state) {
165 case TAB_MEDIA_STATE_AUDIO_PLAYING:
166 return rb.GetNativeImageNamed(IDR_TAB_AUDIO_INDICATOR);
167 case TAB_MEDIA_STATE_AUDIO_MUTING:
168 return rb.GetNativeImageNamed(IDR_TAB_AUDIO_MUTING_INDICATOR);
169 case TAB_MEDIA_STATE_RECORDING:
170 return rb.GetNativeImageNamed(IDR_TAB_RECORDING_INDICATOR);
171 case TAB_MEDIA_STATE_CAPTURING:
172 return rb.GetNativeImageNamed(IDR_TAB_CAPTURE_INDICATOR);
173 case TAB_MEDIA_STATE_NONE:
174 break;
176 NOTREACHED();
177 return rb.GetNativeImageNamed(IDR_SAD_FAVICON);
180 const gfx::Image& GetTabMediaIndicatorAffordanceImage(
181 TabMediaState media_state) {
182 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
183 switch (media_state) {
184 case TAB_MEDIA_STATE_AUDIO_PLAYING:
185 case TAB_MEDIA_STATE_AUDIO_MUTING:
186 return rb.GetNativeImageNamed(IDR_TAB_AUDIO_MUTING_AFFORDANCE);
187 case TAB_MEDIA_STATE_NONE:
188 case TAB_MEDIA_STATE_RECORDING:
189 case TAB_MEDIA_STATE_CAPTURING:
190 return GetTabMediaIndicatorImage(media_state);
192 NOTREACHED();
193 return GetTabMediaIndicatorImage(media_state);
196 scoped_ptr<gfx::Animation> CreateTabMediaIndicatorFadeAnimation(
197 TabMediaState media_state) {
198 if (media_state == TAB_MEDIA_STATE_RECORDING ||
199 media_state == TAB_MEDIA_STATE_CAPTURING) {
200 return TabRecordingIndicatorAnimation::Create();
203 // Note: While it seems silly to use a one-part MultiAnimation, it's the only
204 // gfx::Animation implementation that lets us control the frame interval.
205 gfx::MultiAnimation::Parts parts;
206 const bool is_for_fade_in = (media_state != TAB_MEDIA_STATE_NONE);
207 parts.push_back(gfx::MultiAnimation::Part(
208 is_for_fade_in ? kIndicatorFadeInDurationMs : kIndicatorFadeOutDurationMs,
209 gfx::Tween::EASE_IN));
210 const base::TimeDelta interval =
211 base::TimeDelta::FromMilliseconds(kIndicatorFrameIntervalMs);
212 scoped_ptr<gfx::MultiAnimation> animation(
213 new gfx::MultiAnimation(parts, interval));
214 animation->set_continuous(false);
215 return animation.Pass();
218 base::string16 AssembleTabTooltipText(const base::string16& title,
219 TabMediaState media_state) {
220 if (media_state == TAB_MEDIA_STATE_NONE)
221 return title;
223 base::string16 result = title;
224 if (!result.empty())
225 result.append(1, '\n');
226 switch (media_state) {
227 case TAB_MEDIA_STATE_AUDIO_PLAYING:
228 result.append(
229 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_PLAYING));
230 break;
231 case TAB_MEDIA_STATE_AUDIO_MUTING:
232 result.append(
233 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_MUTING));
234 break;
235 case TAB_MEDIA_STATE_RECORDING:
236 result.append(
237 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_RECORDING));
238 break;
239 case TAB_MEDIA_STATE_CAPTURING:
240 result.append(
241 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_CAPTURING));
242 break;
243 case TAB_MEDIA_STATE_NONE:
244 NOTREACHED();
245 break;
247 return result;
250 bool IsTabAudioMutingFeatureEnabled() {
251 return base::CommandLine::ForCurrentProcess()->HasSwitch(
252 switches::kEnableTabAudioMuting);
255 bool CanToggleAudioMute(content::WebContents* contents) {
256 switch (GetTabMediaStateForContents(contents)) {
257 case TAB_MEDIA_STATE_NONE:
258 case TAB_MEDIA_STATE_AUDIO_PLAYING:
259 case TAB_MEDIA_STATE_AUDIO_MUTING:
260 return IsTabAudioMutingFeatureEnabled();
261 case TAB_MEDIA_STATE_RECORDING:
262 case TAB_MEDIA_STATE_CAPTURING:
263 return false;
265 NOTREACHED();
266 return false;
269 const std::string& GetTabAudioMutedCause(content::WebContents* contents) {
270 LastMuteMetadata::CreateForWebContents(contents); // Create if not exists.
271 if (GetTabMediaStateForContents(contents) == TAB_MEDIA_STATE_CAPTURING) {
272 // For tab capture, libcontent forces muting off.
273 LastMuteMetadata::FromWebContents(contents)->cause =
274 kMutedToggleCauseCapture;
276 return LastMuteMetadata::FromWebContents(contents)->cause;
279 void SetTabAudioMuted(content::WebContents* contents,
280 bool mute,
281 const std::string& cause) {
282 if (!contents || !chrome::CanToggleAudioMute(contents))
283 return;
285 LastMuteMetadata::CreateForWebContents(contents); // Create if not exists.
286 LastMuteMetadata::FromWebContents(contents)->cause = cause;
288 contents->SetAudioMuted(mute);
291 bool IsTabAudioMuted(content::WebContents* contents) {
292 return contents && contents->IsAudioMuted();
295 bool AreAllTabsMuted(const TabStripModel& tab_strip,
296 const std::vector<int>& indices) {
297 for (std::vector<int>::const_iterator i = indices.begin(); i != indices.end();
298 ++i) {
299 if (!IsTabAudioMuted(tab_strip.GetWebContentsAt(*i)))
300 return false;
302 return true;
305 } // namespace chrome