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; | 5 package org.chromium.chrome.browser.media; |
6 | 6 |
7 import android.app.Notification; | 7 import android.app.Notification; |
8 import android.app.NotificationManager; | 8 import android.app.NotificationManager; |
9 import android.app.PendingIntent; | 9 import android.app.PendingIntent; |
10 import android.app.Service; | 10 import android.app.Service; |
11 import android.content.Context; | 11 import android.content.Context; |
12 import android.content.Intent; | 12 import android.content.Intent; |
13 import android.content.SharedPreferences; | 13 import android.content.SharedPreferences; |
14 import android.os.IBinder; | 14 import android.os.IBinder; |
15 import android.support.v4.app.NotificationCompat; | 15 import android.support.v4.app.NotificationCompat; |
16 import android.util.SparseIntArray; | 16 import android.util.SparseIntArray; |
17 | 17 |
18 import org.chromium.base.ContextUtils; | 18 import org.chromium.base.ContextUtils; |
19 import org.chromium.base.Log; | 19 import org.chromium.base.Log; |
20 import org.chromium.chrome.R; | 20 import org.chromium.chrome.R; |
21 import org.chromium.chrome.browser.tab.Tab; | 21 import org.chromium.chrome.browser.tab.Tab; |
| 22 import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid; |
22 | 23 |
23 import java.net.MalformedURLException; | 24 import java.net.MalformedURLException; |
24 import java.net.URL; | 25 import java.net.URL; |
25 import java.util.HashSet; | 26 import java.util.HashSet; |
26 import java.util.Iterator; | 27 import java.util.Iterator; |
27 import java.util.Set; | 28 import java.util.Set; |
28 | 29 |
29 /** | 30 /** |
30 * Service that creates/destroys the WebRTC notification when media capture star
ts/stops. | 31 * Service that creates/destroys the WebRTC notification when media capture star
ts/stops. |
31 */ | 32 */ |
32 public class MediaCaptureNotificationService extends Service { | 33 public class MediaCaptureNotificationService extends Service { |
33 | 34 |
34 private static final String NOTIFICATION_NAMESPACE = "MediaCaptureNotificati
onService"; | 35 private static final String NOTIFICATION_NAMESPACE = "MediaCaptureNotificati
onService"; |
35 | 36 |
36 private static final String NOTIFICATION_ID_EXTRA = "NotificationId"; | 37 private static final String NOTIFICATION_ID_EXTRA = "NotificationId"; |
37 private static final String NOTIFICATION_MEDIA_TYPE_EXTRA = "NotificationMed
iaType"; | 38 private static final String NOTIFICATION_MEDIA_TYPE_EXTRA = "NotificationMed
iaType"; |
38 private static final String NOTIFICATION_MEDIA_URL_EXTRA = "NotificationMedi
aUrl"; | 39 private static final String NOTIFICATION_MEDIA_URL_EXTRA = "NotificationMedi
aUrl"; |
| 40 private static final String ACTION_MEDIA_CAPTURE_UPDATE = |
| 41 "org.chromium.chrome.browser.media.SCREEN_CAPTURE_UPDATE"; |
| 42 private static final String ACTION_SCREEN_CAPTURE_STOP = |
| 43 "org.chromium.chrome.browser.media.SCREEN_CAPTURE_STOP"; |
| 44 private static final String ACTION_SCREEN_CAPTURE_DISMISS = |
| 45 "org.chromium.chrome.browser.media.SCREEN_CAPTURE_DISMISS"; |
39 | 46 |
40 private static final String WEBRTC_NOTIFICATION_IDS = "WebRTCNotificationIds
"; | 47 private static final String WEBRTC_NOTIFICATION_IDS = "WebRTCNotificationIds
"; |
41 private static final String TAG = "MediaCapture"; | 48 private static final String TAG = "MediaCapture"; |
42 | 49 |
43 private static final int MEDIATYPE_NO_MEDIA = 0; | 50 private static final int MEDIATYPE_NO_MEDIA = 0; |
44 private static final int MEDIATYPE_AUDIO_AND_VIDEO = 1; | 51 private static final int MEDIATYPE_AUDIO_AND_VIDEO = 1; |
45 private static final int MEDIATYPE_VIDEO_ONLY = 2; | 52 private static final int MEDIATYPE_VIDEO_ONLY = 2; |
46 private static final int MEDIATYPE_AUDIO_ONLY = 3; | 53 private static final int MEDIATYPE_AUDIO_ONLY = 3; |
| 54 private static final int MEDIATYPE_SCREEN_CAPTURE = 4; |
47 | 55 |
48 private NotificationManager mNotificationManager; | 56 private NotificationManager mNotificationManager; |
49 private Context mContext; | 57 private Context mContext; |
50 private SharedPreferences mSharedPreferences; | 58 private SharedPreferences mSharedPreferences; |
51 private final SparseIntArray mNotifications = new SparseIntArray(); | 59 private final SparseIntArray mNotifications = new SparseIntArray(); |
52 | 60 |
53 @Override | 61 @Override |
54 public void onCreate() { | 62 public void onCreate() { |
55 mContext = getApplicationContext(); | 63 mContext = getApplicationContext(); |
56 mNotificationManager = (NotificationManager) mContext.getSystemService( | 64 mNotificationManager = (NotificationManager) mContext.getSystemService( |
(...skipping 19 matching lines...) Expand all Loading... |
76 private boolean doesNotificationExist(int notificationId) { | 84 private boolean doesNotificationExist(int notificationId) { |
77 return mNotifications.indexOfKey(notificationId) >= 0; | 85 return mNotifications.indexOfKey(notificationId) >= 0; |
78 } | 86 } |
79 | 87 |
80 @Override | 88 @Override |
81 public int onStartCommand(Intent intent, int flags, int startId) { | 89 public int onStartCommand(Intent intent, int flags, int startId) { |
82 if (intent == null || intent.getExtras() == null) { | 90 if (intent == null || intent.getExtras() == null) { |
83 cancelPreviousWebRtcNotifications(); | 91 cancelPreviousWebRtcNotifications(); |
84 stopSelf(); | 92 stopSelf(); |
85 } else { | 93 } else { |
86 updateNotification( | 94 String action = intent.getAction(); |
87 intent.getIntExtra(NOTIFICATION_ID_EXTRA, Tab.INVALID_TAB_ID
), | 95 int notificationId = intent.getIntExtra(NOTIFICATION_ID_EXTRA, Tab.I
NVALID_TAB_ID); |
88 intent.getIntExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, MEDIATYPE_
NO_MEDIA), | 96 int mediaType = intent.getIntExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, ME
DIATYPE_NO_MEDIA); |
89 intent.getStringExtra(NOTIFICATION_MEDIA_URL_EXTRA)); | 97 String url = intent.getStringExtra(NOTIFICATION_MEDIA_URL_EXTRA); |
| 98 |
| 99 switch (action) { |
| 100 case ACTION_MEDIA_CAPTURE_UPDATE: |
| 101 updateNotification(notificationId, mediaType, url); |
| 102 break; |
| 103 |
| 104 case ACTION_SCREEN_CAPTURE_STOP: |
| 105 // Notify native to stop screen capture when the STOP button
in notification |
| 106 // is clicked. |
| 107 TabWebContentsDelegateAndroid.notifyStopped(notificationId); |
| 108 break; |
| 109 |
| 110 case ACTION_SCREEN_CAPTURE_DISMISS: |
| 111 // Update current notification without head up when the DISM
ISS button in |
| 112 // notification is clicked. |
| 113 createNotification(notificationId, mediaType, url, false); |
| 114 break; |
| 115 |
| 116 default: |
| 117 break; |
| 118 } |
90 } | 119 } |
91 return super.onStartCommand(intent, flags, startId); | 120 return super.onStartCommand(intent, flags, startId); |
92 } | 121 } |
93 | 122 |
94 /** | 123 /** |
95 * Cancel all previously existing notifications. Essential while doing a cle
an start (may be | 124 * Cancel all previously existing notifications. Essential while doing a cle
an start (may be |
96 * after a browser crash which caused old notifications to exist). | 125 * after a browser crash which caused old notifications to exist). |
97 */ | 126 */ |
98 private void cancelPreviousWebRtcNotifications() { | 127 private void cancelPreviousWebRtcNotifications() { |
99 Set<String> notificationIds = | 128 Set<String> notificationIds = |
(...skipping 15 matching lines...) Expand all Loading... |
115 * @param mediaType Media type of the notification. | 144 * @param mediaType Media type of the notification. |
116 * @param url Url of the current webrtc call. | 145 * @param url Url of the current webrtc call. |
117 */ | 146 */ |
118 private void updateNotification(int notificationId, int mediaType, String ur
l) { | 147 private void updateNotification(int notificationId, int mediaType, String ur
l) { |
119 if (doesNotificationExist(notificationId) | 148 if (doesNotificationExist(notificationId) |
120 && !doesNotificationNeedUpdate(notificationId, mediaType)) { | 149 && !doesNotificationNeedUpdate(notificationId, mediaType)) { |
121 return; | 150 return; |
122 } | 151 } |
123 destroyNotification(notificationId); | 152 destroyNotification(notificationId); |
124 if (mediaType != MEDIATYPE_NO_MEDIA) { | 153 if (mediaType != MEDIATYPE_NO_MEDIA) { |
125 createNotification(notificationId, mediaType, url); | 154 createNotification(notificationId, mediaType, url, true); |
126 } | 155 } |
127 if (mNotifications.size() == 0) stopSelf(); | 156 if (mNotifications.size() == 0) stopSelf(); |
128 } | 157 } |
129 | 158 |
130 /** | 159 /** |
131 * Destroys the notification for the id notificationId. | 160 * Destroys the notification for the id notificationId. |
132 * @param notificationId Unique id of the notification. | 161 * @param notificationId Unique id of the notification. |
133 */ | 162 */ |
134 private void destroyNotification(int notificationId) { | 163 private void destroyNotification(int notificationId) { |
135 if (doesNotificationExist(notificationId)) { | 164 if (doesNotificationExist(notificationId)) { |
136 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); | 165 mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId); |
137 mNotifications.delete(notificationId); | 166 mNotifications.delete(notificationId); |
138 updateSharedPreferencesEntry(notificationId, true); | 167 updateSharedPreferencesEntry(notificationId, true); |
139 } | 168 } |
140 } | 169 } |
141 | 170 |
142 /** | 171 /** |
143 * Creates a notification for the provided notificationId and mediaType. | 172 * Creates a notification for the provided notificationId and mediaType. |
144 * @param notificationId Unique id of the notification. | 173 * @param notificationId Unique id of the notification. |
145 * @param mediaType Media type of the notification. | 174 * @param mediaType Media type of the notification. |
146 * @param url Url of the current webrtc call. | 175 * @param url Url of the current webrtc call. |
147 */ | 176 */ |
148 private void createNotification(int notificationId, int mediaType, String ur
l) { | 177 private void createNotification(int notificationId, int mediaType, String ur
l, boolean headup) { |
149 int notificationContentTextId = 0; | 178 int notificationContentTextId = 0; |
150 int notificationIconId = 0; | 179 int notificationIconId = 0; |
151 if (mediaType == MEDIATYPE_AUDIO_AND_VIDEO) { | 180 if (mediaType == MEDIATYPE_AUDIO_AND_VIDEO) { |
152 notificationContentTextId = R.string.video_audio_call_notification_t
ext_2; | 181 notificationContentTextId = R.string.video_audio_call_notification_t
ext_2; |
153 notificationIconId = R.drawable.webrtc_video; | 182 notificationIconId = R.drawable.webrtc_video; |
154 } else if (mediaType == MEDIATYPE_VIDEO_ONLY) { | 183 } else if (mediaType == MEDIATYPE_VIDEO_ONLY) { |
155 notificationContentTextId = R.string.video_call_notification_text_2; | 184 notificationContentTextId = R.string.video_call_notification_text_2; |
156 notificationIconId = R.drawable.webrtc_video; | 185 notificationIconId = R.drawable.webrtc_video; |
157 } else if (mediaType == MEDIATYPE_AUDIO_ONLY) { | 186 } else if (mediaType == MEDIATYPE_AUDIO_ONLY) { |
158 notificationContentTextId = R.string.audio_call_notification_text_2; | 187 notificationContentTextId = R.string.audio_call_notification_text_2; |
159 notificationIconId = R.drawable.webrtc_audio; | 188 notificationIconId = R.drawable.webrtc_audio; |
| 189 } else if (mediaType == MEDIATYPE_SCREEN_CAPTURE) { |
| 190 notificationContentTextId = R.string.screen_capture_notification_tex
t; |
| 191 notificationIconId = R.drawable.webrtc_video; |
160 } | 192 } |
161 | 193 |
162 NotificationCompat.Builder builder = new NotificationCompat.Builder(mCon
text) | 194 NotificationCompat.Builder builder = new NotificationCompat.Builder(mCon
text) |
163 .setAutoCancel(false) | 195 .setAutoCancel(false) |
164 .setOngoing(true) | 196 .setOngoing(true) |
165 .setContentTitle(mContext.getString(R.string.app_name)) | 197 .setContentTitle(mContext.getString(R.string.app_name)) |
166 .setSmallIcon(notificationIconId) | 198 .setSmallIcon(notificationIconId) |
167 .setLocalOnly(true); | 199 .setLocalOnly(true); |
168 | 200 |
169 StringBuilder contentText = new StringBuilder( | 201 StringBuilder contentText = |
170 mContext.getResources().getString(notificationContentTextId)).ap
pend('.'); | 202 new StringBuilder(mContext.getResources().getString(notification
ContentTextId, url)) |
| 203 .append('.'); |
171 Intent tabIntent = Tab.createBringTabToFrontIntent(notificationId); | 204 Intent tabIntent = Tab.createBringTabToFrontIntent(notificationId); |
172 if (tabIntent != null) { | 205 if (tabIntent != null) { |
173 PendingIntent contentIntent = PendingIntent.getActivity( | 206 PendingIntent contentIntent = PendingIntent.getActivity( |
174 mContext, notificationId, tabIntent, 0); | 207 mContext, notificationId, tabIntent, 0); |
175 builder.setContentIntent(contentIntent); | 208 builder.setContentIntent(contentIntent); |
176 contentText.append( | 209 if (mediaType == MEDIATYPE_SCREEN_CAPTURE) { |
177 mContext.getResources().getString(R.string.media_notificatio
n_link_text, url)); | 210 // To screen capture notification, add two action buttons and en
able head up |
| 211 // notification if needed. |
| 212 if (headup) { |
| 213 // Enable the head up notification. Click Dismiss button to
dismiss the head up |
| 214 // notification. |
| 215 builder.addAction(R.drawable.btn_close, "Dismiss", |
| 216 buildPendingIntent(ACTION_SCREEN_CAPTURE_DISMISS, no
tificationId, |
| 217 mediaType, url)); |
| 218 builder.setPriority(Notification.PRIORITY_HIGH); |
| 219 builder.setVibrate(new long[0]); |
| 220 } else { |
| 221 // Disable the head up notification. Click Dismiss button to
bring tab to |
| 222 // front. |
| 223 builder.addAction(R.drawable.btn_close, "Dismiss", contentIn
tent); |
| 224 } |
| 225 builder.addAction(R.drawable.ic_vidcontrol_stop, "Stop", |
| 226 buildPendingIntent(ACTION_SCREEN_CAPTURE_STOP, notificat
ionId, mediaType, |
| 227 url)); |
| 228 } else { |
| 229 contentText.append(mContext.getResources().getString( |
| 230 R.string.media_notification_link_text, url)); |
| 231 } |
178 } else { | 232 } else { |
179 contentText.append(" ").append(url); | 233 contentText.append(" ").append(url); |
180 } | 234 } |
181 builder.setContentText(contentText); | 235 builder.setContentText(contentText); |
182 | 236 |
183 Notification notification = new NotificationCompat.BigTextStyle(builder) | 237 Notification notification = new NotificationCompat.BigTextStyle(builder) |
184 .bigText(contentText).build(); | 238 .bigText(contentText).build(); |
185 mNotificationManager.notify(NOTIFICATION_NAMESPACE, notificationId, noti
fication); | 239 mNotificationManager.notify(NOTIFICATION_NAMESPACE, notificationId, noti
fication); |
186 mNotifications.put(notificationId, mediaType); | 240 mNotifications.put(notificationId, mediaType); |
187 updateSharedPreferencesEntry(notificationId, false); | 241 updateSharedPreferencesEntry(notificationId, false); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 } | 274 } |
221 | 275 |
222 @Override | 276 @Override |
223 public IBinder onBind(Intent intent) { | 277 public IBinder onBind(Intent intent) { |
224 return null; | 278 return null; |
225 } | 279 } |
226 | 280 |
227 /** | 281 /** |
228 * @param audio If audio is being captured. | 282 * @param audio If audio is being captured. |
229 * @param video If video is being captured. | 283 * @param video If video is being captured. |
| 284 * @param screen If screen is being captured. |
230 * @return A constant identify what media is being captured. | 285 * @return A constant identify what media is being captured. |
231 */ | 286 */ |
232 public static int getMediaType(boolean audio, boolean video) { | 287 public static int getMediaType(boolean audio, boolean video, boolean screen)
{ |
233 if (audio && video) { | 288 if (screen) { |
| 289 return MEDIATYPE_SCREEN_CAPTURE; |
| 290 } else if (audio && video) { |
234 return MEDIATYPE_AUDIO_AND_VIDEO; | 291 return MEDIATYPE_AUDIO_AND_VIDEO; |
235 } else if (audio) { | 292 } else if (audio) { |
236 return MEDIATYPE_AUDIO_ONLY; | 293 return MEDIATYPE_AUDIO_ONLY; |
237 } else if (video) { | 294 } else if (video) { |
238 return MEDIATYPE_VIDEO_ONLY; | 295 return MEDIATYPE_VIDEO_ONLY; |
239 } else { | 296 } else { |
240 return MEDIATYPE_NO_MEDIA; | 297 return MEDIATYPE_NO_MEDIA; |
241 } | 298 } |
242 } | 299 } |
243 | 300 |
(...skipping 13 matching lines...) Expand all Loading... |
257 | 314 |
258 /** | 315 /** |
259 * Send an intent to MediaCaptureNotificationService to either create, updat
e or destroy the | 316 * Send an intent to MediaCaptureNotificationService to either create, updat
e or destroy the |
260 * notification identified by tabId. | 317 * notification identified by tabId. |
261 * @param tabId Unique notification id. | 318 * @param tabId Unique notification id. |
262 * @param audio If audio is being captured. | 319 * @param audio If audio is being captured. |
263 * @param video If video is being captured. | 320 * @param video If video is being captured. |
264 * @param fullUrl Url of the current webrtc call. | 321 * @param fullUrl Url of the current webrtc call. |
265 */ | 322 */ |
266 public static void updateMediaNotificationForTab( | 323 public static void updateMediaNotificationForTab( |
267 Context context, int tabId, boolean audio, boolean video, String ful
lUrl) { | 324 Context context, int tabId, int mediaType, String fullUrl) { |
268 int mediaType = getMediaType(audio, video); | |
269 if (!shouldStartService(context, mediaType, tabId)) return; | 325 if (!shouldStartService(context, mediaType, tabId)) return; |
270 Intent intent = new Intent(context, MediaCaptureNotificationService.clas
s); | 326 Intent intent = new Intent(context, MediaCaptureNotificationService.clas
s); |
| 327 intent.setAction(ACTION_MEDIA_CAPTURE_UPDATE); |
271 intent.putExtra(NOTIFICATION_ID_EXTRA, tabId); | 328 intent.putExtra(NOTIFICATION_ID_EXTRA, tabId); |
272 String baseUrl = fullUrl; | 329 String baseUrl = fullUrl; |
273 try { | 330 try { |
274 URL url = new URL(fullUrl); | 331 URL url = new URL(fullUrl); |
275 baseUrl = url.getProtocol() + "://" + url.getHost(); | 332 baseUrl = url.getProtocol() + "://" + url.getHost(); |
276 } catch (MalformedURLException e) { | 333 } catch (MalformedURLException e) { |
277 Log.w(TAG, "Error parsing the webrtc url, %s ", fullUrl); | 334 Log.w(TAG, "Error parsing the webrtc url, %s ", fullUrl); |
278 } | 335 } |
279 intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, baseUrl); | 336 intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, baseUrl); |
280 intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType); | 337 intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType); |
281 context.startService(intent); | 338 context.startService(intent); |
282 } | 339 } |
283 | 340 |
284 /** | 341 /** |
285 * Clear any previous media notifications. | 342 * Clear any previous media notifications. |
286 */ | 343 */ |
287 public static void clearMediaNotifications(Context context) { | 344 public static void clearMediaNotifications(Context context) { |
288 SharedPreferences sharedPreferences = | 345 SharedPreferences sharedPreferences = |
289 ContextUtils.getAppSharedPreferences(); | 346 ContextUtils.getAppSharedPreferences(); |
290 Set<String> notificationIds = | 347 Set<String> notificationIds = |
291 sharedPreferences.getStringSet(WEBRTC_NOTIFICATION_IDS, null); | 348 sharedPreferences.getStringSet(WEBRTC_NOTIFICATION_IDS, null); |
292 if (notificationIds == null || notificationIds.isEmpty()) return; | 349 if (notificationIds == null || notificationIds.isEmpty()) return; |
293 | 350 |
294 context.startService(new Intent(context, MediaCaptureNotificationService
.class)); | 351 context.startService(new Intent(context, MediaCaptureNotificationService
.class)); |
295 } | 352 } |
| 353 |
| 354 /** |
| 355 * Build PendingIntent for the actions of screen capture notification. |
| 356 */ |
| 357 private PendingIntent buildPendingIntent( |
| 358 String action, int notificationId, int mediaType, String url) { |
| 359 Intent intent = new Intent(this, MediaCaptureNotificationService.class); |
| 360 intent.setAction(action); |
| 361 intent.putExtra(NOTIFICATION_ID_EXTRA, notificationId); |
| 362 intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType); |
| 363 intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, url); |
| 364 return PendingIntent.getService( |
| 365 mContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURR
ENT); |
| 366 } |
296 } | 367 } |
OLD | NEW |