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.Context; | |
9 import android.graphics.Bitmap; | |
8 import android.media.AudioManager; | 10 import android.media.AudioManager; |
11 import android.os.Build; | |
9 import android.text.TextUtils; | 12 import android.text.TextUtils; |
10 | 13 |
11 import org.chromium.base.ApplicationStatus; | 14 import org.chromium.base.ApplicationStatus; |
12 import org.chromium.base.Log; | 15 import org.chromium.base.Log; |
13 import org.chromium.chrome.R; | 16 import org.chromium.chrome.R; |
14 import org.chromium.chrome.browser.metrics.MediaSessionUMA; | 17 import org.chromium.chrome.browser.metrics.MediaSessionUMA; |
15 import org.chromium.chrome.browser.tab.EmptyTabObserver; | 18 import org.chromium.chrome.browser.tab.EmptyTabObserver; |
16 import org.chromium.chrome.browser.tab.Tab; | 19 import org.chromium.chrome.browser.tab.Tab; |
17 import org.chromium.chrome.browser.tab.TabObserver; | 20 import org.chromium.chrome.browser.tab.TabObserver; |
18 import org.chromium.chrome.browser.util.UrlUtilities; | 21 import org.chromium.chrome.browser.util.UrlUtilities; |
19 import org.chromium.content_public.browser.WebContents; | 22 import org.chromium.content_public.browser.WebContents; |
20 import org.chromium.content_public.browser.WebContentsObserver; | 23 import org.chromium.content_public.browser.WebContentsObserver; |
21 import org.chromium.content_public.common.MediaMetadata; | 24 import org.chromium.content_public.common.MediaMetadata; |
22 import org.chromium.ui.base.WindowAndroid; | 25 import org.chromium.ui.base.WindowAndroid; |
23 | 26 |
24 import java.net.URI; | 27 import java.net.URI; |
25 import java.net.URISyntaxException; | 28 import java.net.URISyntaxException; |
26 | 29 |
27 /** | 30 /** |
28 * A tab helper responsible for enabling/disabling media controls and passing | 31 * A tab helper responsible for enabling/disabling media controls and passing |
29 * media actions from the controls to the {@link org.chromium.content.browser.Me diaSession} | 32 * media actions from the controls to the {@link org.chromium.content.browser.Me diaSession} |
30 */ | 33 */ |
31 public class MediaSessionTabHelper { | 34 public class MediaSessionTabHelper { |
32 private static final String TAG = "MediaSession"; | 35 private static final String TAG = "MediaSession"; |
33 | 36 |
34 private static final String UNICODE_PLAY_CHARACTER = "\u25B6"; | 37 private static final String UNICODE_PLAY_CHARACTER = "\u25B6"; |
35 | 38 |
36 private Tab mTab; | 39 private Tab mTab; |
40 private Bitmap mFavicon = null; | |
41 private String mOrigin = null; | |
37 private WebContents mWebContents; | 42 private WebContents mWebContents; |
38 private WebContentsObserver mWebContentsObserver; | 43 private WebContentsObserver mWebContentsObserver; |
39 private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_T YPE; | 44 private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_T YPE; |
40 private MediaNotificationInfo.Builder mNotificationInfoBuilder = null; | 45 private MediaNotificationInfo.Builder mNotificationInfoBuilder = null; |
41 private MediaMetadata mFallbackMetadata; | 46 private MediaMetadata mFallbackMetadata; |
42 | 47 |
43 private MediaNotificationListener mControlsListener = new MediaNotificationL istener() { | 48 private MediaNotificationListener mControlsListener = new MediaNotificationL istener() { |
44 @Override | 49 @Override |
45 public void onPlay(int actionSource) { | 50 public void onPlay(int actionSource) { |
46 MediaSessionUMA | 51 MediaSessionUMA |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
86 super.destroy(); | 91 super.destroy(); |
87 } | 92 } |
88 | 93 |
89 @Override | 94 @Override |
90 public void mediaSessionStateChanged(boolean isControllable, boolean isPaused, | 95 public void mediaSessionStateChanged(boolean isControllable, boolean isPaused, |
91 MediaMetadata metadata) { | 96 MediaMetadata metadata) { |
92 if (!isControllable) { | 97 if (!isControllable) { |
93 hideNotification(); | 98 hideNotification(); |
94 return; | 99 return; |
95 } | 100 } |
96 String origin = mTab.getUrl(); | |
97 try { | |
98 origin = UrlUtilities.formatUrlForSecurityDisplay(new URI(or igin), true); | |
99 } catch (URISyntaxException e) { | |
100 Log.e(TAG, "Unable to parse the origin from the URL. " | |
101 + "Showing the full URL instead."); | |
102 } | |
103 | 101 |
104 mFallbackMetadata = null; | 102 mFallbackMetadata = null; |
105 | 103 |
106 // The page's title is used as a placeholder if no title is spec ified in the | 104 // The page's title is used as a placeholder if no title is spec ified in the |
107 // metadata. | 105 // metadata. |
108 if (TextUtils.isEmpty(metadata.getTitle())) { | 106 if (TextUtils.isEmpty(metadata.getTitle())) { |
109 mFallbackMetadata = new MediaMetadata( | 107 mFallbackMetadata = new MediaMetadata( |
110 sanitizeMediaTitle(mTab.getTitle()), | 108 sanitizeMediaTitle(mTab.getTitle()), |
111 metadata.getArtist(), | 109 metadata.getArtist(), |
112 metadata.getAlbum()); | 110 metadata.getAlbum()); |
113 metadata = mFallbackMetadata; | 111 metadata = mFallbackMetadata; |
114 } | 112 } |
115 | 113 |
116 mNotificationInfoBuilder = new MediaNotificationInfo.Builder() | 114 mNotificationInfoBuilder = |
117 .setMetadata(metadata) | 115 new MediaNotificationInfo.Builder() |
118 .setPaused(isPaused) | 116 .setMetadata(metadata) |
119 .setOrigin(origin) | 117 .setPaused(isPaused) |
120 .setTabId(mTab.getId()) | 118 .setOrigin(mOrigin) |
121 .setPrivate(mTab.isIncognito()) | 119 .setTabId(mTab.getId()) |
122 .setIcon(R.drawable.audio_playing) | 120 .setPrivate(mTab.isIncognito()) |
123 .setActions(MediaNotificationInfo.ACTION_PLAY_PAUSE | 121 .setIcon(R.drawable.audio_playing) |
124 | MediaNotificationInfo.ACTION_SWIPEAWAY) | 122 .setLargeIcon(mFavicon) |
125 .setContentIntent(Tab.createBringTabToFrontIntent(mTab.g etId())) | 123 .setActions(MediaNotificationInfo.ACTION_PLAY_PA USE |
126 .setId(R.id.media_playback_notification) | 124 | MediaNotificationInfo.ACTION_SWIPEAWAY ) |
127 .setListener(mControlsListener); | 125 .setContentIntent(Tab.createBringTabToFrontInten t(mTab.getId())) |
126 .setId(R.id.media_playback_notification) | |
127 .setListener(mControlsListener); | |
128 | 128 |
129 MediaNotificationManager.show(ApplicationStatus.getApplicationCo ntext(), | 129 MediaNotificationManager.show(ApplicationStatus.getApplicationCo ntext(), |
130 mNotificationInfoBuilder.build()); | 130 mNotificationInfoBuilder.build()); |
131 | 131 |
132 Activity activity = getActivityFromTab(mTab); | 132 Activity activity = getActivityFromTab(mTab); |
133 if (activity != null) { | 133 if (activity != null) { |
134 activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); | 134 activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); |
135 } | 135 } |
136 } | 136 } |
137 }; | 137 }; |
(...skipping 14 matching lines...) Expand all Loading... | |
152 } | 152 } |
153 | 153 |
154 private final TabObserver mTabObserver = new EmptyTabObserver() { | 154 private final TabObserver mTabObserver = new EmptyTabObserver() { |
155 @Override | 155 @Override |
156 public void onContentChanged(Tab tab) { | 156 public void onContentChanged(Tab tab) { |
157 assert tab == mTab; | 157 assert tab == mTab; |
158 setWebContents(tab.getWebContents()); | 158 setWebContents(tab.getWebContents()); |
159 } | 159 } |
160 | 160 |
161 @Override | 161 @Override |
162 public void onFaviconUpdated(Tab tab, Bitmap icon) { | |
163 assert tab == mTab; | |
164 if (!updateFavicon(icon)) return; | |
165 | |
166 if (mNotificationInfoBuilder == null) return; | |
167 | |
168 mNotificationInfoBuilder.setLargeIcon(mFavicon); | |
169 MediaNotificationManager.show( | |
170 ApplicationStatus.getApplicationContext(), mNotificationInfo Builder.build()); | |
171 } | |
172 | |
173 @Override | |
174 public void onUrlUpdated(Tab tab) { | |
175 assert tab == mTab; | |
176 | |
177 String origin = mTab.getUrl(); | |
178 try { | |
179 origin = UrlUtilities.formatUrlForSecurityDisplay(new URI(origin ), true); | |
180 } catch (URISyntaxException e) { | |
181 Log.e(TAG, "Unable to parse the origin from the URL. " | |
182 + "Using the full URL instead."); | |
183 } | |
184 | |
185 if (mOrigin != null && mOrigin.equals(origin)) return; | |
186 mOrigin = origin; | |
187 mFavicon = null; | |
188 | |
189 if (mNotificationInfoBuilder == null) return; | |
190 | |
191 mNotificationInfoBuilder.setLargeIcon(mFavicon); | |
192 MediaNotificationManager.show( | |
193 ApplicationStatus.getApplicationContext(), mNotificationInfo Builder.build()); | |
194 } | |
195 | |
196 @Override | |
162 public void onTitleUpdated(Tab tab) { | 197 public void onTitleUpdated(Tab tab) { |
163 assert tab == mTab; | 198 assert tab == mTab; |
164 if (mNotificationInfoBuilder == null || mFallbackMetadata == null) r eturn; | 199 if (mNotificationInfoBuilder == null || mFallbackMetadata == null) r eturn; |
165 | 200 |
166 mFallbackMetadata = new MediaMetadata(mFallbackMetadata); | 201 mFallbackMetadata = new MediaMetadata(mFallbackMetadata); |
167 mFallbackMetadata.setTitle(sanitizeMediaTitle(mTab.getTitle())); | 202 mFallbackMetadata.setTitle(sanitizeMediaTitle(mTab.getTitle())); |
168 mNotificationInfoBuilder.setMetadata(mFallbackMetadata); | 203 mNotificationInfoBuilder.setMetadata(mFallbackMetadata); |
169 | 204 |
170 MediaNotificationManager.show(ApplicationStatus.getApplicationContex t(), | 205 MediaNotificationManager.show(ApplicationStatus.getApplicationContex t(), |
171 mNotificationInfoBuilder.build()); | 206 mNotificationInfoBuilder.build()); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
233 assert false; | 268 assert false; |
234 return MediaSessionUMA.MEDIA_SESSION_ACTION_SOURCE_MAX; | 269 return MediaSessionUMA.MEDIA_SESSION_ACTION_SOURCE_MAX; |
235 } | 270 } |
236 | 271 |
237 private Activity getActivityFromTab(Tab tab) { | 272 private Activity getActivityFromTab(Tab tab) { |
238 WindowAndroid windowAndroid = tab.getWindowAndroid(); | 273 WindowAndroid windowAndroid = tab.getWindowAndroid(); |
239 if (windowAndroid == null) return null; | 274 if (windowAndroid == null) return null; |
240 | 275 |
241 return windowAndroid.getActivity().get(); | 276 return windowAndroid.getActivity().get(); |
242 } | 277 } |
278 | |
279 /** | |
280 * Updates the best favicon if the given icon is better. | |
281 * @return whether the best favicon is updated. | |
282 */ | |
283 private boolean updateFavicon(Bitmap icon) { | |
284 if (icon == null) return false; | |
285 | |
286 Context context = ApplicationStatus.getApplicationContext(); | |
287 | |
288 float displayDensity = context.getResources().getDisplayMetrics().densit y; | |
Zhiqiang Zhang (Slow)
2016/04/11 09:26:28
remove
| |
289 | |
290 int largeIconSizeInDp = 0; | |
291 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { | |
292 largeIconSizeInDp = 128; | |
293 } else { | |
294 // TODO(zqzhang): Get this value via Resource.getDimension() if N ha s a resource id. | |
295 largeIconSizeInDp = 96; | |
296 } | |
297 int minimalIconSizeInPx = Math.round(largeIconSizeInDp * 0.75f); | |
298 | |
299 if (icon.getWidth() < minimalIconSizeInPx || icon.getHeight() < minimalI conSizeInPx) { | |
300 return false; | |
301 } | |
302 if (mFavicon != null && (icon.getWidth() < mFavicon.getWidth() | |
303 || icon.getHeight() < mFavicon.getHeight ())) { | |
304 return false; | |
305 } | |
306 mFavicon = icon; | |
307 return true; | |
308 } | |
243 } | 309 } |
OLD | NEW |