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

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/media/MediaNotificationService.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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 side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/media/MediaNotificationService.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/media/MediaNotificationService.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/media/MediaNotificationService.java
new file mode 100644
index 0000000000000000000000000000000000000000..fadd38351402c80b3629f5fba5e0dec37b4c03cd
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/media/MediaNotificationService.java
@@ -0,0 +1,318 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.media;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.provider.Browser;
+import android.support.v4.app.NotificationCompat;
+import android.util.Log;
+import android.util.SparseIntArray;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.chrome.browser.IntentHandler.TabOpenType;
+import org.chromium.chrome.browser.Tab;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Service that creates/destroys media related notifications.
+ * There are two kinds of notifications:
+ * 1. The WebRTC notification when media capture starts/stops.
+ * 2. The audio playback notification when a tab is playing audio.
+ * These notifications are made mutually exclusive: there can be
+ * only one media notification for a tab.
+ */
+public class MediaNotificationService extends Service {
+
+ private static final String NOTIFICATION_NAMESPACE = "MediaNotificationService";
+
+ private static final String NOTIFICATION_ID_EXTRA = "NotificationId";
+ private static final String NOTIFICATION_MEDIA_TYPE_EXTRA = "NotificationMediaType";
+ private static final String NOTIFICATION_MEDIA_URL_EXTRA = "NotificationMediaUrl";
+
+ private static final String MEDIA_NOTIFICATION_IDS = "WebRTCNotificationIds";
+ private static final String LOG_TAG = "MediaNotificationService";
+
+ private static final int MEDIATYPE_NO_MEDIA = 0;
+ private static final int MEDIATYPE_AUDIO_AND_VIDEO_CAPTURE = 1;
+ private static final int MEDIATYPE_VIDEO_CAPTURE_ONLY = 2;
+ private static final int MEDIATYPE_AUDIO_CAPTURE_ONLY = 3;
+ private static final int MEDIATYPE_AUDIO_PLAYBACK = 4;
+
+ private NotificationManager mNotificationManager;
+ private Context mContext;
+ private SharedPreferences mSharedPreferences;
+ private final SparseIntArray mNotifications = new SparseIntArray();
+
+ @Override
+ public void onCreate() {
+ mContext = getApplicationContext();
+ mNotificationManager = (NotificationManager) mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+ mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
+ super.onCreate();
+ }
+
+ /**
+ * @param notificationId Unique id of the notification.
+ * @param mediaType Media type of the notification.
+ * @return Whether the notification has already been created for provided notification id and
+ * mediaType.
+ */
+ private boolean doesNotificationNeedUpdate(int notificationId, int mediaType) {
+ return mNotifications.get(notificationId) != mediaType;
+ }
+
+ /**
+ * @param notificationId Unique id of the notification.
+ * @return Whether the notification has already been created for the provided notification id.
+ */
+ private boolean doesNotificationExist(int notificationId) {
+ return mNotifications.indexOfKey(notificationId) >= 0;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null || intent.getExtras() == null) {
+ cancelPreviousWebRtcNotifications();
+ stopSelf();
+ } else {
+ updateNotification(
+ intent.getIntExtra(NOTIFICATION_ID_EXTRA, Tab.INVALID_TAB_ID),
+ intent.getIntExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, MEDIATYPE_NO_MEDIA),
+ intent.getStringExtra(NOTIFICATION_MEDIA_URL_EXTRA));
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+
+ /**
+ * Cancel all previously existing notifications. Essential while doing a clean start (may be
+ * after a browser crash which caused old notifications to exist).
+ */
+ private void cancelPreviousWebRtcNotifications() {
+ Set<String> notificationIds =
+ mSharedPreferences.getStringSet(MEDIA_NOTIFICATION_IDS, null);
+ if (notificationIds == null) return;
+ Iterator<String> iterator = notificationIds.iterator();
+ while (iterator.hasNext()) {
+ mNotificationManager.cancel(NOTIFICATION_NAMESPACE, Integer.parseInt(iterator.next()));
+ }
+ SharedPreferences.Editor sharedPreferenceEditor = mSharedPreferences.edit();
+ sharedPreferenceEditor.remove(MediaNotificationService.MEDIA_NOTIFICATION_IDS);
+ sharedPreferenceEditor.apply();
+ }
+
+ /**
+ * Updates the extisting notification or creates one if none exist for the provided
+ * notificationId and mediaType.
+ * @param notificationId Unique id of the notification.
+ * @param mediaType Media type of the notification.
+ * @param url Url of the current webrtc call.
+ */
+ private void updateNotification(int notificationId, int mediaType, String url) {
+ if (doesNotificationExist(notificationId)
+ && !doesNotificationNeedUpdate(notificationId, mediaType)) {
+ return;
+ }
+ destroyNotification(notificationId);
+ if (mediaType != MEDIATYPE_NO_MEDIA) {
+ createNotification(notificationId, mediaType, url);
+ }
+ if (mNotifications.size() == 0) stopSelf();
+ }
+
+ /**
+ * Destroys the notification for the id notificationId.
+ * @param notificationId Unique id of the notification.
+ */
+ private void destroyNotification(int notificationId) {
+ if (doesNotificationExist(notificationId)) {
+ mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
+ mNotifications.delete(notificationId);
+ updateSharedPreferencesEntry(notificationId, true);
+ }
+ }
+
+ /**
+ * Creates a notification for the provided notificationId and mediaType.
+ * @param notificationId Unique id of the notification.
+ * @param mediaType Media type of the notification.
+ * @param url Url of the current webrtc call.
+ */
+ private void createNotification(int notificationId, int mediaType, String url) {
+ int notificationContentTextId = 0;
+ int notificationIconId = 0;
+ if (mediaType == MEDIATYPE_AUDIO_AND_VIDEO_CAPTURE) {
+ notificationContentTextId = R.string.video_audio_call_notification_text_2;
+ notificationIconId = R.drawable.webrtc_video;
+ } else if (mediaType == MEDIATYPE_VIDEO_CAPTURE_ONLY) {
+ notificationContentTextId = R.string.video_call_notification_text_2;
+ notificationIconId = R.drawable.webrtc_video;
+ } else if (mediaType == MEDIATYPE_AUDIO_CAPTURE_ONLY) {
+ notificationContentTextId = R.string.audio_call_notification_text_2;
+ notificationIconId = R.drawable.webrtc_audio;
+ } else if (mediaType == MEDIATYPE_AUDIO_PLAYBACK) {
+ notificationContentTextId = R.string.audio_playback_notification_text;
+ notificationIconId = R.drawable.audio_playing;
+ }
+
+ Intent tabIntent = createMediaTabOpenIntent(notificationId);
+ PendingIntent contentIntent = PendingIntent.getActivity(
+ mContext, notificationId, tabIntent, 0);
+ String contentText = mContext.getResources().getString(notificationContentTextId) + ". "
+ + mContext.getResources().getString(
+ R.string.media_notification_link_text, url);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
+ .setAutoCancel(false)
+ .setOngoing(true)
+ .setContentIntent(contentIntent)
+ .setContentTitle(mContext.getString(R.string.app_name))
+ .setContentText(contentText)
+ .setSmallIcon(notificationIconId)
+ .setLocalOnly(true);
+
+ Notification notification = new NotificationCompat.BigTextStyle(builder)
+ .bigText(contentText).build();
+ mNotificationManager.notify(NOTIFICATION_NAMESPACE, notificationId, notification);
+ mNotifications.put(notificationId, mediaType);
+ updateSharedPreferencesEntry(notificationId, false);
+ }
+
+ /**
+ * Returns the Intent that opens the tab with the WebRTC call on click of the notification.
+ */
+ private Intent createMediaTabOpenIntent(int tabId) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
+ intent.putExtra(TabOpenType.BRING_TAB_TO_FRONT.name(), tabId);
+ intent.setPackage(mContext.getPackageName());
+ return intent;
+ }
+
+ /**
+ * Update shared preferences entry with ids of the visible notifications.
+ * @param notificationId Id of the notification.
+ * @param remove Boolean describing if the notification was added or removed.
+ */
+ private void updateSharedPreferencesEntry(int notificationId, boolean remove) {
+ Set<String> notificationIds =
+ new HashSet<String>(mSharedPreferences.getStringSet(MEDIA_NOTIFICATION_IDS,
+ new HashSet<String>()));
+ if (remove && !notificationIds.isEmpty()
+ && notificationIds.contains(String.valueOf(notificationId))) {
+ notificationIds.remove(String.valueOf(notificationId));
+ } else if (!remove) {
+ notificationIds.add(String.valueOf(notificationId));
+ }
+ SharedPreferences.Editor sharedPreferenceEditor = mSharedPreferences.edit();
+ sharedPreferenceEditor.putStringSet(MEDIA_NOTIFICATION_IDS, notificationIds);
+ sharedPreferenceEditor.apply();
+ }
+
+ @Override
+ public void onDestroy() {
+ cancelPreviousWebRtcNotifications();
+ super.onDestroy();
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ cancelPreviousWebRtcNotifications();
+ return super.onUnbind(intent);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ /**
+ * @param audio If audio is being captured.
+ * @param video If video is being captured.
+ * @return A constant identify what media is being captured.
+ */
+ public static int getMediaType(boolean audioCapture,
+ boolean videoCapture, boolean audioPlayback) {
+ if (audioCapture && videoCapture) {
+ return MEDIATYPE_AUDIO_AND_VIDEO_CAPTURE;
+ } else if (audioCapture) {
+ return MEDIATYPE_AUDIO_CAPTURE_ONLY;
+ } else if (videoCapture) {
+ return MEDIATYPE_VIDEO_CAPTURE_ONLY;
+ } else if (audioPlayback) {
+ return MEDIATYPE_AUDIO_PLAYBACK;
+ } else {
+ return MEDIATYPE_NO_MEDIA;
+ }
+ }
+
+ private static boolean shouldStartService(Context context, int mediaType, int tabId) {
+ if (mediaType != MEDIATYPE_NO_MEDIA) return true;
+ SharedPreferences sharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ Set<String> notificationIds =
+ sharedPreferences.getStringSet(MEDIA_NOTIFICATION_IDS, null);
+ if (notificationIds != null
+ && !notificationIds.isEmpty()
+ && notificationIds.contains(String.valueOf(tabId))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Send an intent to MediaNotificationService to either create, update or destroy the
+ * notification identified by tabId.
+ * @param tabId Unique notification id.
+ * @param audio If audio is being captured.
+ * @param video If video is being captured.
+ * @param fullUrl Url of the current webrtc call.
+ */
+ public static void updateMediaNotificationForTab(Context context, int tabId,
+ boolean audioCapture, boolean videoCapture, boolean audioPlayback,
+ String fullUrl) {
+ int mediaType = getMediaType(audioCapture, videoCapture, audioPlayback);
+ if (!shouldStartService(context, mediaType, tabId)) return;
+ Intent intent = new Intent(context, MediaNotificationService.class);
+ intent.putExtra(NOTIFICATION_ID_EXTRA, tabId);
+ String baseUrl = fullUrl;
+ try {
+ URL url = new URL(fullUrl);
+ baseUrl = url.getProtocol() + "://" + url.getHost();
+ } catch (MalformedURLException e) {
+ Log.w(LOG_TAG, "Error parsing the webrtc url " + fullUrl);
+ }
+ intent.putExtra(NOTIFICATION_MEDIA_URL_EXTRA, baseUrl);
+ intent.putExtra(NOTIFICATION_MEDIA_TYPE_EXTRA, mediaType);
+ context.startService(intent);
+ }
+
+ /**
+ * Clear any previous media notifications.
+ */
+ public static void clearMediaNotifications(Context context) {
+ SharedPreferences sharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ Set<String> notificationIds =
+ sharedPreferences.getStringSet(MEDIA_NOTIFICATION_IDS, null);
+ if (notificationIds == null || notificationIds.isEmpty()) return;
+
+ context.startService(new Intent(context, MediaNotificationService.class));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698