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.Notification; | 7 import android.app.Notification; |
8 import android.app.PendingIntent; | 8 import android.app.PendingIntent; |
9 import android.app.Service; | 9 import android.app.Service; |
10 import android.content.ComponentName; | 10 import android.content.ComponentName; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 * each type of notification since one class corresponds to one instance of the service only. | 50 * each type of notification since one class corresponds to one instance of the service only. |
51 */ | 51 */ |
52 private abstract static class ListenerService extends Service { | 52 private abstract static class ListenerService extends Service { |
53 private static final String ACTION_PLAY = | 53 private static final String ACTION_PLAY = |
54 "MediaNotificationManager.ListenerService.PLAY"; | 54 "MediaNotificationManager.ListenerService.PLAY"; |
55 private static final String ACTION_PAUSE = | 55 private static final String ACTION_PAUSE = |
56 "MediaNotificationManager.ListenerService.PAUSE"; | 56 "MediaNotificationManager.ListenerService.PAUSE"; |
57 private static final String ACTION_STOP = | 57 private static final String ACTION_STOP = |
58 "MediaNotificationManager.ListenerService.STOP"; | 58 "MediaNotificationManager.ListenerService.STOP"; |
59 private static final String EXTRA_NOTIFICATION_ID = | 59 private static final String EXTRA_NOTIFICATION_ID = |
60 "MediaNotificationManager.ListenerService.NOTIFICATION_ID"; | 60 MediaButtonReceiver.EXTRA_NOTIFICATION_ID; |
61 | 61 |
62 // The notification id this service instance corresponds to. | 62 // The notification id this service instance corresponds to. |
63 private int mNotificationId = MediaNotificationInfo.INVALID_ID; | 63 private int mNotificationId = MediaNotificationInfo.INVALID_ID; |
64 | 64 |
65 private PendingIntent getPendingIntent(String action) { | 65 private PendingIntent getPendingIntent(String action) { |
66 Intent intent = getIntent(this, mNotificationId).setAction(action); | 66 Intent intent = getIntent(this, mNotificationId).setAction(action); |
67 return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_ CANCEL_CURRENT); | 67 return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_ CANCEL_CURRENT); |
68 } | 68 } |
69 | 69 |
70 @Override | 70 @Override |
(...skipping 14 matching lines...) Expand all Loading... | |
85 @Override | 85 @Override |
86 public int onStartCommand(Intent intent, int flags, int startId) { | 86 public int onStartCommand(Intent intent, int flags, int startId) { |
87 if (!processIntent(intent)) stopSelf(); | 87 if (!processIntent(intent)) stopSelf(); |
88 | 88 |
89 return START_NOT_STICKY; | 89 return START_NOT_STICKY; |
90 } | 90 } |
91 | 91 |
92 private boolean processIntent(Intent intent) { | 92 private boolean processIntent(Intent intent) { |
93 if (intent == null) return false; | 93 if (intent == null) return false; |
94 | 94 |
95 mNotificationId = intent.getIntExtra( | 95 int notificationId = intent.getIntExtra( |
96 EXTRA_NOTIFICATION_ID, MediaNotificationInfo.INVALID_ID); | 96 EXTRA_NOTIFICATION_ID, MediaNotificationInfo.INVALID_ID); |
97 if (mNotificationId == MediaNotificationInfo.INVALID_ID) return fals e; | 97 |
98 if (notificationId == MediaNotificationInfo.INVALID_ID) { | |
99 // The intent doesn't have the valid notification id. | |
100 return false; | |
101 } else if (mNotificationId != notificationId | |
102 && mNotificationId != MediaNotificationInfo.INVALID_ID) { | |
mlamouri (slow - plz ping)
2015/11/06 18:01:08
Is such a thing even possible? I would merge these
whywhat
2015/11/08 13:11:51
Can some other app send an ignorant/malicious inte
Bernhard Bauer
2015/11/08 23:43:13
It definitely _can_ happen that someone outside of
whywhat
2015/11/09 00:47:53
Agree. Will stop the service in that case and log
| |
103 // The intent's notification id doesn't match the id we've recei ved before. | |
104 return false; | |
105 } else { | |
mlamouri (slow - plz ping)
2015/11/06 18:01:08
No need for |else| if we return above.
whywhat
2015/11/08 13:11:51
Ack.
| |
106 // Either the notification id matches or it's the first intent w e've got. | |
107 mNotificationId = notificationId; | |
108 } | |
109 | |
110 assert mNotificationId != MediaNotificationInfo.INVALID_ID; | |
98 | 111 |
99 MediaNotificationManager manager = getManager(mNotificationId); | 112 MediaNotificationManager manager = getManager(mNotificationId); |
100 if (manager == null || manager.mMediaNotificationInfo == null) retur n false; | 113 if (manager == null || manager.mMediaNotificationInfo == null) retur n false; |
101 | 114 |
102 manager.onServiceStarted(this); | 115 manager.onServiceStarted(this); |
103 | 116 |
104 processAction(intent, manager); | 117 processAction(intent, manager); |
105 return true; | 118 return true; |
106 } | 119 } |
107 | 120 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
157 private static final int NOTIFICATION_ID = R.id.media_playback_notificat ion; | 170 private static final int NOTIFICATION_ID = R.id.media_playback_notificat ion; |
158 } | 171 } |
159 | 172 |
160 /** | 173 /** |
161 * This class is used internally but have to be public to be able to launch the service. | 174 * This class is used internally but have to be public to be able to launch the service. |
162 */ | 175 */ |
163 public static final class PresentationListenerService extends ListenerServic e { | 176 public static final class PresentationListenerService extends ListenerServic e { |
164 private static final int NOTIFICATION_ID = R.id.presentation_notificatio n; | 177 private static final int NOTIFICATION_ID = R.id.presentation_notificatio n; |
165 } | 178 } |
166 | 179 |
180 // Two classes to specify the right notification id in the intent. | |
181 | |
182 /** | |
183 * This class is used internally but have to be public to be able to launch the service. | |
184 */ | |
185 public static final class PlaybackMediaButtonReceiver extends MediaButtonRec eiver { | |
186 @Override | |
187 public int getNotificationId() { | |
188 return PlaybackListenerService.NOTIFICATION_ID; | |
189 } | |
190 } | |
191 | |
192 /** | |
193 * This class is used internally but have to be public to be able to launch the service. | |
194 */ | |
195 public static final class PresentationMediaButtonReceiver extends MediaButto nReceiver { | |
196 @Override | |
197 public int getNotificationId() { | |
198 return PresentationListenerService.NOTIFICATION_ID; | |
199 } | |
200 } | |
201 | |
167 private static Intent getIntent(Context context, int notificationId) { | 202 private static Intent getIntent(Context context, int notificationId) { |
168 Intent intent = null; | 203 Intent intent = null; |
169 if (notificationId == PlaybackListenerService.NOTIFICATION_ID) { | 204 if (notificationId == PlaybackListenerService.NOTIFICATION_ID) { |
170 intent = new Intent(context, PlaybackListenerService.class); | 205 intent = new Intent(context, PlaybackListenerService.class); |
171 } else if (notificationId == PresentationListenerService.NOTIFICATION_ID ) { | 206 } else if (notificationId == PresentationListenerService.NOTIFICATION_ID ) { |
172 intent = new Intent(context, PresentationListenerService.class); | 207 intent = new Intent(context, PresentationListenerService.class); |
173 } else { | 208 } else { |
174 return null; | 209 return null; |
175 } | 210 } |
176 return intent.putExtra(ListenerService.EXTRA_NOTIFICATION_ID, notificati onId); | 211 return intent.putExtra(ListenerService.EXTRA_NOTIFICATION_ID, notificati onId); |
177 } | 212 } |
178 | 213 |
214 private static String getButtonReceiverClassName(int notificationId) { | |
215 if (notificationId == PlaybackListenerService.NOTIFICATION_ID) { | |
216 return PlaybackMediaButtonReceiver.class.getName(); | |
217 } else if (notificationId == PresentationListenerService.NOTIFICATION_ID ) { | |
Bernhard Bauer
2015/11/08 23:43:13
Same here; no else necessary.
whywhat
2015/11/09 00:47:53
Done.
| |
218 return PresentationMediaButtonReceiver.class.getName(); | |
219 } | |
220 | |
221 assert false; | |
222 return null; | |
223 } | |
224 | |
179 /** | 225 /** |
180 * Shows the notification with media controls with the specified media info. Replaces/updates | 226 * Shows the notification with media controls with the specified media info. Replaces/updates |
181 * the current notification if already showing. Does nothing if |mediaNotifi cationInfo| hasn't | 227 * the current notification if already showing. Does nothing if |mediaNotifi cationInfo| hasn't |
182 * changed from the last one. | 228 * changed from the last one. |
183 * | 229 * |
184 * @param applicationContext context to create the notification with | 230 * @param applicationContext context to create the notification with |
185 * @param notificationInfoBuilder information to show in the notification | 231 * @param notificationInfoBuilder information to show in the notification |
186 */ | 232 */ |
187 public static void show(Context applicationContext, | 233 public static void show(Context applicationContext, |
188 MediaNotificationInfo.Builder notificationInfoBuilde r) { | 234 MediaNotificationInfo.Builder notificationInfoBuilde r) { |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
528 } else { | 574 } else { |
529 mService.startForeground(mMediaNotificationInfo.id, notification); | 575 mService.startForeground(mMediaNotificationInfo.id, notification); |
530 } | 576 } |
531 } | 577 } |
532 | 578 |
533 private MediaSessionCompat createMediaSession() { | 579 private MediaSessionCompat createMediaSession() { |
534 MediaSessionCompat mediaSession = new MediaSessionCompat( | 580 MediaSessionCompat mediaSession = new MediaSessionCompat( |
535 mContext, | 581 mContext, |
536 mContext.getString(R.string.app_name), | 582 mContext.getString(R.string.app_name), |
537 new ComponentName(mContext.getPackageName(), | 583 new ComponentName(mContext.getPackageName(), |
538 MediaButtonReceiver.class.getName()), | 584 getButtonReceiverClassName(mMediaNotificationInfo.id)), |
539 null); | 585 null); |
540 mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | 586 mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
541 | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); | 587 | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); |
542 mediaSession.setCallback(mMediaSessionCallback); | 588 mediaSession.setCallback(mMediaSessionCallback); |
543 | 589 |
544 // TODO(mlamouri): the following code is to work around a bug that hopef ully | 590 // TODO(mlamouri): the following code is to work around a bug that hopef ully |
545 // MediaSessionCompat will handle directly. see b/24051980. | 591 // MediaSessionCompat will handle directly. see b/24051980. |
546 try { | 592 try { |
547 mediaSession.setActive(true); | 593 mediaSession.setActive(true); |
548 } catch (NullPointerException e) { | 594 } catch (NullPointerException e) { |
549 // Some versions of KitKat do not support AudioManager.registerMedia ButtonIntent | 595 // Some versions of KitKat do not support AudioManager.registerMedia ButtonIntent |
550 // with a PendingIntent. They will throw a NullPointerException, in which case | 596 // with a PendingIntent. They will throw a NullPointerException, in which case |
551 // they should be able to activate a MediaSessionCompat with only tr ansport | 597 // they should be able to activate a MediaSessionCompat with only tr ansport |
552 // controls. | 598 // controls. |
553 mediaSession.setActive(false); | 599 mediaSession.setActive(false); |
554 mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONT ROLS); | 600 mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONT ROLS); |
555 mediaSession.setActive(true); | 601 mediaSession.setActive(true); |
556 } | 602 } |
557 return mediaSession; | 603 return mediaSession; |
558 } | 604 } |
559 | 605 |
560 private Bitmap drawableToBitmap(Drawable drawable) { | 606 private Bitmap drawableToBitmap(Drawable drawable) { |
561 if (!(drawable instanceof BitmapDrawable)) return null; | 607 if (!(drawable instanceof BitmapDrawable)) return null; |
562 | 608 |
563 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; | 609 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; |
564 return bitmapDrawable.getBitmap(); | 610 return bitmapDrawable.getBitmap(); |
565 } | 611 } |
566 } | 612 } |
OLD | NEW |