OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.media.ui; | 5 package org.chromium.chrome.browser.media.ui; |
6 | 6 |
7 import android.app.Activity; | 7 import android.app.Activity; |
8 import android.content.Intent; | 8 import android.content.Intent; |
9 import android.graphics.Bitmap; | 9 import android.graphics.Bitmap; |
10 import android.media.AudioManager; | 10 import android.media.AudioManager; |
11 import android.text.TextUtils; | 11 import android.text.TextUtils; |
12 | 12 |
13 import org.chromium.base.ContextUtils; | 13 import org.chromium.base.ContextUtils; |
14 import org.chromium.base.Log; | 14 import org.chromium.base.Log; |
| 15 import org.chromium.base.VisibleForTesting; |
15 import org.chromium.chrome.R; | 16 import org.chromium.chrome.R; |
16 import org.chromium.chrome.browser.metrics.MediaNotificationUma; | 17 import org.chromium.chrome.browser.metrics.MediaNotificationUma; |
17 import org.chromium.chrome.browser.metrics.MediaSessionUMA; | 18 import org.chromium.chrome.browser.metrics.MediaSessionUMA; |
18 import org.chromium.chrome.browser.tab.EmptyTabObserver; | 19 import org.chromium.chrome.browser.tab.EmptyTabObserver; |
19 import org.chromium.chrome.browser.tab.Tab; | 20 import org.chromium.chrome.browser.tab.Tab; |
20 import org.chromium.chrome.browser.tab.TabObserver; | 21 import org.chromium.chrome.browser.tab.TabObserver; |
21 import org.chromium.components.url_formatter.UrlFormatter; | 22 import org.chromium.components.url_formatter.UrlFormatter; |
| 23 import org.chromium.content.browser.ChromeMediaSession; |
| 24 import org.chromium.content.browser.MediaSessionObserver; |
22 import org.chromium.content_public.browser.WebContents; | 25 import org.chromium.content_public.browser.WebContents; |
23 import org.chromium.content_public.browser.WebContentsObserver; | |
24 import org.chromium.content_public.common.MediaMetadata; | 26 import org.chromium.content_public.common.MediaMetadata; |
25 import org.chromium.ui.base.WindowAndroid; | 27 import org.chromium.ui.base.WindowAndroid; |
26 | 28 |
27 import java.net.URI; | 29 import java.net.URI; |
28 import java.net.URISyntaxException; | 30 import java.net.URISyntaxException; |
29 | 31 |
| 32 import javax.annotation.Nullable; |
| 33 |
30 /** | 34 /** |
31 * A tab helper responsible for enabling/disabling media controls and passing | 35 * A tab helper responsible for enabling/disabling media controls and passing |
32 * media actions from the controls to the {@link org.chromium.content.browser.Me
diaSession} | 36 * media actions from the controls to the {@link org.chromium.content.browser.Me
diaSession} |
33 */ | 37 */ |
34 public class MediaSessionTabHelper implements MediaImageCallback { | 38 public class MediaSessionTabHelper implements MediaImageCallback { |
35 private static final String TAG = "MediaSession"; | 39 private static final String TAG = "MediaSession"; |
36 | 40 |
37 private static final String UNICODE_PLAY_CHARACTER = "\u25B6"; | 41 private static final String UNICODE_PLAY_CHARACTER = "\u25B6"; |
38 private static final int MINIMAL_FAVICON_SIZE = 114; | 42 private static final int MINIMAL_FAVICON_SIZE = 114; |
39 | 43 |
40 private Tab mTab; | 44 private Tab mTab; |
41 private Bitmap mPageMediaImage = null; | 45 private Bitmap mPageMediaImage = null; |
42 private Bitmap mFavicon = null; | 46 private Bitmap mFavicon = null; |
43 private Bitmap mCurrentMediaImage = null; | 47 private Bitmap mCurrentMediaImage = null; |
44 private String mOrigin = null; | 48 private String mOrigin = null; |
45 private WebContents mWebContents; | 49 private MediaSessionObserver mMediaSessionObserver; |
46 private WebContentsObserver mWebContentsObserver; | |
47 private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_T
YPE; | 50 private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_T
YPE; |
48 private MediaNotificationInfo.Builder mNotificationInfoBuilder = null; | 51 private MediaNotificationInfo.Builder mNotificationInfoBuilder = null; |
49 // The fallback title if |mPageMetadata| is null or its title is empty. | 52 // The fallback title if |mPageMetadata| is null or its title is empty. |
50 private String mFallbackTitle = null; | 53 private String mFallbackTitle = null; |
51 // The metadata set by the page. | 54 // The metadata set by the page. |
52 private MediaMetadata mPageMetadata = null; | 55 private MediaMetadata mPageMetadata = null; |
53 // The currently showing metadata. | 56 // The currently showing metadata. |
54 private MediaMetadata mCurrentMetadata = null; | 57 private MediaMetadata mCurrentMetadata = null; |
55 private MediaImageManager mMediaImageManager = null; | 58 private MediaImageManager mMediaImageManager = null; |
56 | 59 |
| 60 @VisibleForTesting |
| 61 @Nullable |
| 62 MediaSessionObserver getMediaSessionObserverForTesting() { |
| 63 return mMediaSessionObserver; |
| 64 } |
| 65 |
57 private MediaNotificationListener mControlsListener = new MediaNotificationL
istener() { | 66 private MediaNotificationListener mControlsListener = new MediaNotificationL
istener() { |
58 @Override | 67 @Override |
59 public void onPlay(int actionSource) { | 68 public void onPlay(int actionSource) { |
60 MediaSessionUMA | 69 MediaSessionUMA |
61 .recordPlay(MediaSessionTabHelper.convertMediaActionSourceTo
UMA(actionSource)); | 70 .recordPlay(MediaSessionTabHelper.convertMediaActionSourceTo
UMA(actionSource)); |
62 | 71 if (mMediaSessionObserver != null) mMediaSessionObserver.getSession(
).resume(); |
63 mWebContents.resumeMediaSession(); | |
64 } | 72 } |
65 | 73 |
66 @Override | 74 @Override |
67 public void onPause(int actionSource) { | 75 public void onPause(int actionSource) { |
68 MediaSessionUMA.recordPause( | 76 MediaSessionUMA.recordPause( |
69 MediaSessionTabHelper.convertMediaActionSourceToUMA(actionSo
urce)); | 77 MediaSessionTabHelper.convertMediaActionSourceToUMA(actionSo
urce)); |
70 | 78 if (mMediaSessionObserver != null) mMediaSessionObserver.getSession(
).suspend(); |
71 mWebContents.suspendMediaSession(); | |
72 } | 79 } |
73 | 80 |
74 @Override | 81 @Override |
75 public void onStop(int actionSource) { | 82 public void onStop(int actionSource) { |
76 MediaSessionUMA | 83 MediaSessionUMA |
77 .recordStop(MediaSessionTabHelper.convertMediaActionSourceTo
UMA(actionSource)); | 84 .recordStop(MediaSessionTabHelper.convertMediaActionSourceTo
UMA(actionSource)); |
78 | 85 if (mMediaSessionObserver != null) mMediaSessionObserver.getSession(
).stop(); |
79 mWebContents.stopMediaSession(); | |
80 } | 86 } |
81 }; | 87 }; |
82 | 88 |
83 void hideNotification() { | 89 void hideNotification() { |
84 if (mTab == null) { | 90 if (mTab == null) { |
85 return; | 91 return; |
86 } | 92 } |
87 MediaNotificationManager.hide(mTab.getId(), R.id.media_playback_notifica
tion); | 93 MediaNotificationManager.hide(mTab.getId(), R.id.media_playback_notifica
tion); |
88 Activity activity = getActivityFromTab(mTab); | 94 Activity activity = getActivityFromTab(mTab); |
89 if (activity != null) { | 95 if (activity != null) { |
90 activity.setVolumeControlStream(mPreviousVolumeControlStream); | 96 activity.setVolumeControlStream(mPreviousVolumeControlStream); |
91 } | 97 } |
92 mNotificationInfoBuilder = null; | 98 mNotificationInfoBuilder = null; |
93 } | 99 } |
94 | 100 |
95 private WebContentsObserver createWebContentsObserver(WebContents webContent
s) { | 101 private MediaSessionObserver createMediaSessionObserver(ChromeMediaSession s
ession) { |
96 return new WebContentsObserver(webContents) { | 102 return new MediaSessionObserver(session) { |
97 @Override | 103 @Override |
98 public void destroy() { | 104 public void mediaSessionDestroyed() { |
99 hideNotification(); | 105 hideNotification(); |
100 super.destroy(); | |
101 } | 106 } |
102 | 107 |
103 @Override | 108 @Override |
104 public void mediaSessionStateChanged(boolean isControllable, boolean
isPaused) { | 109 public void mediaSessionStateChanged(boolean isControllable, boolean
isPaused) { |
105 if (!isControllable) { | 110 if (!isControllable) { |
106 hideNotification(); | 111 hideNotification(); |
107 return; | 112 return; |
108 } | 113 } |
109 | 114 |
110 Intent contentIntent = Tab.createBringTabToFrontIntent(mTab.getI
d()); | 115 Intent contentIntent = Tab.createBringTabToFrontIntent(mTab.getI
d()); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 if (mPageMetadata != null) { | 151 if (mPageMetadata != null) { |
147 mMediaImageManager.downloadImage(mPageMetadata.getArtwork(), | 152 mMediaImageManager.downloadImage(mPageMetadata.getArtwork(), |
148 MediaSessionTabHelper.this); | 153 MediaSessionTabHelper.this); |
149 } | 154 } |
150 updateNotificationMetadata(); | 155 updateNotificationMetadata(); |
151 } | 156 } |
152 }; | 157 }; |
153 } | 158 } |
154 | 159 |
155 private void setWebContents(WebContents webContents) { | 160 private void setWebContents(WebContents webContents) { |
156 if (mWebContents == webContents) return; | 161 ChromeMediaSession session = ChromeMediaSession.fromWebContents(webConte
nts); |
| 162 if (mMediaSessionObserver != null && session == mMediaSessionObserver.ge
tSession()) { |
| 163 return; |
| 164 } |
157 | 165 |
158 cleanupWebContents(); | 166 cleanupMediaSessionObserver(); |
159 mWebContents = webContents; | 167 if (webContents != null) { |
160 if (mWebContents != null) mWebContentsObserver = createWebContentsObserv
er(mWebContents); | 168 mMediaSessionObserver = createMediaSessionObserver(session); |
161 mMediaImageManager.setWebContents(mWebContents); | 169 } |
| 170 mMediaImageManager.setWebContents(webContents); |
162 } | 171 } |
163 | 172 |
164 private void cleanupWebContents() { | 173 private void cleanupMediaSessionObserver() { |
165 if (mWebContentsObserver != null) mWebContentsObserver.destroy(); | 174 if (mMediaSessionObserver != null) { |
166 mWebContentsObserver = null; | 175 mMediaSessionObserver.getSession().removeObserver(mMediaSessionObser
ver); |
167 mWebContents = null; | 176 } |
| 177 mMediaSessionObserver = null; |
168 } | 178 } |
169 | 179 |
170 private final TabObserver mTabObserver = new EmptyTabObserver() { | 180 private final TabObserver mTabObserver = new EmptyTabObserver() { |
171 @Override | 181 @Override |
172 public void onContentChanged(Tab tab) { | 182 public void onContentChanged(Tab tab) { |
173 assert tab == mTab; | 183 assert tab == mTab; |
174 setWebContents(tab.getWebContents()); | 184 setWebContents(tab.getWebContents()); |
175 } | 185 } |
176 | 186 |
177 @Override | 187 @Override |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 if (!TextUtils.equals(mFallbackTitle, newFallbackTitle)) { | 225 if (!TextUtils.equals(mFallbackTitle, newFallbackTitle)) { |
216 mFallbackTitle = newFallbackTitle; | 226 mFallbackTitle = newFallbackTitle; |
217 updateNotificationMetadata(); | 227 updateNotificationMetadata(); |
218 } | 228 } |
219 } | 229 } |
220 | 230 |
221 @Override | 231 @Override |
222 public void onDestroyed(Tab tab) { | 232 public void onDestroyed(Tab tab) { |
223 assert mTab == tab; | 233 assert mTab == tab; |
224 | 234 |
225 cleanupWebContents(); | 235 cleanupMediaSessionObserver(); |
226 | 236 |
227 hideNotification(); | 237 hideNotification(); |
228 mTab.removeObserver(this); | 238 mTab.removeObserver(this); |
229 mTab = null; | 239 mTab = null; |
230 } | 240 } |
231 }; | 241 }; |
232 | 242 |
233 private MediaSessionTabHelper(Tab tab) { | 243 private MediaSessionTabHelper(Tab tab) { |
234 mTab = tab; | 244 mTab = tab; |
235 mTab.addObserver(mTabObserver); | 245 mTab.addObserver(mTabObserver); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 if (mNotificationInfoBuilder == null) return; | 374 if (mNotificationInfoBuilder == null) return; |
365 mNotificationInfoBuilder.setLargeIcon(mCurrentMediaImage); | 375 mNotificationInfoBuilder.setLargeIcon(mCurrentMediaImage); |
366 MediaNotificationManager.show( | 376 MediaNotificationManager.show( |
367 ContextUtils.getApplicationContext(), mNotificationInfoBuilder.b
uild()); | 377 ContextUtils.getApplicationContext(), mNotificationInfoBuilder.b
uild()); |
368 } | 378 } |
369 | 379 |
370 private Bitmap getNotificationImage() { | 380 private Bitmap getNotificationImage() { |
371 return (mPageMediaImage != null) ? mPageMediaImage : mFavicon; | 381 return (mPageMediaImage != null) ? mPageMediaImage : mFavicon; |
372 } | 382 } |
373 } | 383 } |
OLD | NEW |