Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/media/ui/NotificationMediaPlaybackControls.java

Issue 1159113006: [Android] A prototype of the interactive media notification. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Moved OnMediaSessionStateChanged to WebContentsImpl Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.media.ui;
6
7 import android.app.Notification;
8 import android.app.PendingIntent;
9 import android.app.Service;
10 import android.content.Context;
11 import android.content.Intent;
12 import android.os.IBinder;
13 import android.provider.Browser;
14 import android.support.v4.app.NotificationCompat;
15 import android.widget.RemoteViews;
16
17 import org.chromium.chrome.R;
18 import org.chromium.chrome.browser.IntentHandler.TabOpenType;
19
20 /**
21 * A class for notifications that provide information and optional media control s for a given media.
22 * Internally implements a Service for transforming notification Intents into
23 * {@link MediaPlaybackListener} calls for all registered listeners.
24 */
25 public class NotificationMediaPlaybackControls {
26 private static final Object LOCK = new Object();
27 private static NotificationMediaPlaybackControls sInstance;
28
29 /**
30 * Service used to transform intent requests triggered from the notification into
31 * {@code Listener} callbacks. Ideally this class should be private, but pub lic is required to
32 * create as a service.
33 */
34 public static class ListenerService extends Service {
35 private static final String ACTION_PLAY =
36 "NotificationMediaPlaybackControls.ListenerService.PLAY";
37 private static final String ACTION_PAUSE =
38 "NotificationMediaPlaybackControls.ListenerService.PAUSE";
39
40 private PendingIntent getPendingIntent(String action) {
41 Intent intent = new Intent(this, ListenerService.class);
42 intent.setAction(action);
43 return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_ CANCEL_CURRENT);
44 }
45
46 @Override
47 public IBinder onBind(Intent intent) {
48 return null;
49 }
50
51 @Override
52 public void onCreate() {
53 super.onCreate();
54 onServiceStarted(this);
55 }
56
57 @Override
58 public void onDestroy() {
59 super.onDestroy();
60 onServiceDestroyed();
61 }
62
63 @Override
64 public int onStartCommand(Intent intent, int flags, int startId) {
65 if (intent == null
66 || sInstance == null
67 || sInstance.mMediaInfo == null
68 || sInstance.mMediaInfo.listener == null) {
69 stopSelf();
70 return START_NOT_STICKY;
71 }
72
73 String action = intent.getAction();
74 if (ACTION_PLAY.equals(action)) {
75 sInstance.mMediaInfo.listener.onPlay();
76 sInstance.onPlaybackStateChanged(false);
77 } else if (ACTION_PAUSE.equals(action)) {
78 sInstance.mMediaInfo.listener.onPause();
79 sInstance.onPlaybackStateChanged(true);
80 }
81
82 return START_NOT_STICKY;
83 }
84 }
85
86 /**
87 * Shows the notification with media controls with the specified media info. Replaces/updates
88 * the current notification if already showing. Does nothing if |mediaInfo| hasn't changed from
89 * the last one.
90 *
91 * @param applicationContext context to create the notification with
92 * @param mediaInfo information to show in the notification
93 */
94 public static void show(Context applicationContext, MediaInfo mediaInfo) {
95 synchronized (LOCK) {
96 if (sInstance == null) {
97 sInstance = new NotificationMediaPlaybackControls(applicationCon text);
98 }
99 }
100 sInstance.showNotification(mediaInfo);
101 }
102
103 /**
104 * Hides the notification for the specified tabId.
105 *
106 * @param tabId the id of the tab that showed the notification or invalid ta b id.
107 */
108 public static void hide(int tabId) {
109 if (sInstance == null) return;
110 sInstance.hideNotification(tabId);
111 }
112
113 /**
114 * Hides any notification if shown by this service.
115 */
116 public static void clear() {
117 if (sInstance == null) return;
118 sInstance.clearNotification();
119 }
120
121 /**
122 * Registers the started {@link Service} with the singleton and creates the notification.
123 *
124 * @param service the service that was started
125 */
126 private static void onServiceStarted(ListenerService service) {
127 assert sInstance != null;
128 assert sInstance.mService == null;
129 sInstance.mService = service;
130 sInstance.updateNotification();
131 }
132
133 /**
134 * Handles the destruction
135 */
136 private static void onServiceDestroyed() {
137 assert sInstance != null;
138 assert sInstance.mService != null;
139 sInstance.mNotification = null;
140 sInstance.mService = null;
141 }
142
143 private final Context mContext;
144
145 // ListenerService running for the notification. Only non-null when showing.
146 private ListenerService mService;
147
148 private final String mPlayDescription;
149
150 private final String mPauseDescription;
151
152 private Notification mNotification;
153
154 private MediaInfo mMediaInfo;
155
156 private NotificationMediaPlaybackControls(Context context) {
157 mContext = context;
158 mPlayDescription = context.getResources().getString(R.string.accessibili ty_play);
159 mPauseDescription = context.getResources().getString(R.string.accessibil ity_pause);
160 }
161
162 private void showNotification(MediaInfo mediaInfo) {
163 mContext.startService(new Intent(mContext, ListenerService.class));
164
165 assert mediaInfo != null;
166
167 if (mediaInfo.equals(mMediaInfo)) return;
168
169 mMediaInfo = mediaInfo;
170 updateNotification();
171 }
172
173 private void clearNotification() {
174 mMediaInfo = null;
175 mContext.stopService(new Intent(mContext, ListenerService.class));
176 }
177
178 private void hideNotification(int tabId) {
179 if (mMediaInfo == null || tabId != mMediaInfo.tabId) return;
180 clearNotification();
181 }
182
183 private void onPlaybackStateChanged(boolean isPaused) {
184 assert mMediaInfo != null;
185 mMediaInfo = new MediaInfo(
186 mMediaInfo.title,
187 isPaused,
188 mMediaInfo.origin,
189 mMediaInfo.tabId,
190 mMediaInfo.listener);
191 updateNotification();
192 }
193
194 private RemoteViews createContentView() {
195 RemoteViews contentView =
196 new RemoteViews(mContext.getPackageName(), R.layout.playback_not ification_bar);
197 return contentView;
198 }
199
200 private String getStatus() {
201 if (mMediaInfo.origin != null) {
202 return mContext.getString(R.string.media_notification_link_text, mMe diaInfo.origin);
203 }
204 return mContext.getString(R.string.media_notification_text_no_link);
205 }
206
207 private String getTitle() {
208 String mediaTitle = mMediaInfo.title;
209 if (mMediaInfo.isPaused) {
210 return mContext.getString(
211 R.string.media_playback_notification_paused_for_media, media Title);
212 }
213 return mContext.getString(
214 R.string.media_playback_notification_playing_for_media, mediaTit le);
215 }
216
217 private PendingIntent createContentIntent() {
218 int tabId = mMediaInfo.tabId;
219 Intent intent = new Intent(Intent.ACTION_MAIN);
220 intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()) ;
221 intent.putExtra(TabOpenType.BRING_TAB_TO_FRONT.name(), tabId);
222 intent.setPackage(mContext.getPackageName());
223 return PendingIntent.getActivity(mContext, tabId, intent, 0);
224 }
225
226 private void updateNotification() {
227 if (mService == null) return;
228
229 if (mMediaInfo == null) {
230 // Notification was hidden before we could update it.
231 assert mNotification == null;
232 return;
233 }
234
235 if (mNotification == null) {
236 NotificationCompat.Builder notificationBuilder =
237 new NotificationCompat.Builder(mContext)
238 .setSmallIcon(R.drawable.audio_playing)
239 .setAutoCancel(false)
240 .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
241 .setOngoing(true)
242 .setContent(createContentView())
243 .setContentIntent(createContentIntent());
244 mNotification = notificationBuilder.build();
245 }
246
247 RemoteViews contentView = createContentView();
248
249 contentView.setTextViewText(R.id.title, getTitle());
250 contentView.setTextViewText(R.id.status, getStatus());
251 contentView.setImageViewResource(R.id.icon, R.drawable.audio_playing);
252
253 if (mMediaInfo.isPaused) {
254 contentView.setImageViewResource(R.id.playpause, R.drawable.ic_vidco ntrol_play);
255 contentView.setContentDescription(R.id.playpause, mPlayDescription);
256 contentView.setOnClickPendingIntent(R.id.playpause,
257 mService.getPendingIntent(ListenerService.ACTION_PLAY));
258 } else {
259 contentView.setImageViewResource(R.id.playpause, R.drawable.ic_vidco ntrol_pause);
260 contentView.setContentDescription(R.id.playpause, mPauseDescription) ;
261 contentView.setOnClickPendingIntent(R.id.playpause,
262 mService.getPendingIntent(ListenerService.ACTION_PAUSE));
263 }
264
265 mNotification.contentView = contentView;
266
267 mService.startForeground(R.id.media_playback_notification, mNotification );
268 }
269 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698