Bug 1465102 - Updated NotificationService for Oreo. r?sdaswani
Modified NotificationClient to use new start/stop intents for NotificationService for
Android O. We are keeping a reference to the notification the service was first
started with in order to comply with the mandatory startForeground call for Oreo.
MozReview-Commit-ID: 4CzM4pvANJt
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
@@ -8,16 +8,17 @@ package org.mozilla.gecko.notifications;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.GeckoActivityMonitor;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoApplication;
import org.mozilla.gecko.GeckoService;
@@ -303,23 +304,45 @@ public final class NotificationClient im
*/
public boolean isOngoing(final Notification notification) {
if (notification != null && (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0) {
return true;
}
return false;
}
- private void setForegroundNotificationLocked(final String name,
- final Notification notification) {
+ private void setForegroundNotificationLocked(@NonNull final String name,
+ @NonNull final Notification notification) {
mForegroundNotification = name;
final Intent intent = new Intent(mContext, NotificationService.class);
intent.putExtra(NotificationService.EXTRA_NOTIFICATION, notification);
- mContext.startService(intent);
+ toggleForegroundService(intent);
+ }
+
+ private void removeForegroundNotificationLocked() {
+ mForegroundNotification = null;
+
+ final Intent intent = new Intent(mContext, NotificationService.class);
+ intent.putExtra(NotificationService.EXTRA_ACTION_STOP, true);
+ toggleForegroundService(intent);
+ }
+
+ /**
+ * Method used to toggle the NotificationService.
+ * When the intent is passed with {@link NotificationService#EXTRA_ACTION_STOP} we are queueing a stopSelf action.
+ * @param intent
+ */
+ @SuppressLint("NewApi")
+ private void toggleForegroundService(Intent intent) {
+ if (AppConstants.Versions.preO) {
+ mContext.startService(intent);
+ } else {
+ mContext.startForegroundService(intent);
+ }
}
private void updateForegroundNotificationLocked(final String oldName) {
if (mForegroundNotification == null || !mForegroundNotification.equals(oldName)) {
return;
}
// If we're removing the notification associated with the
@@ -332,11 +355,11 @@ public final class NotificationClient im
// uses a special ID, so we need to close its old instantiation and then
// re-add it with the new ID through the NotificationService.
onNotificationClose(name);
setForegroundNotificationLocked(name, notification);
return;
}
}
- setForegroundNotificationLocked(null, null);
+ removeForegroundNotificationLocked();
}
}
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationService.java
@@ -5,33 +5,57 @@
package org.mozilla.gecko.notifications;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.R;
public final class NotificationService extends Service {
+ /**
+ * Start Intent of the service must contain a notification extra.
+ */
public static final String EXTRA_NOTIFICATION = "notification";
+ /**
+ * Stop Intent of the service must contain the stop action extra.
+ */
+ public static final String EXTRA_ACTION_STOP = "action_stop";
+
+ /**
+ * We are holding a reference to the notification this service was started with in order to use it
+ * again when we queue the stop action thus satisfying the Oreo limitations.
+ */
+ private Notification currentNotification;
@Override // Service
public int onStartCommand(final Intent intent, final int flags, final int startId) {
- final Notification notification = intent.getParcelableExtra(EXTRA_NOTIFICATION);
- if (notification != null) {
- // Start foreground notification.
- startForeground(R.id.foregroundNotification, notification);
- return START_NOT_STICKY;
- }
-
- // Stop foreground notification
- stopForeground(true);
- stopSelfResult(startId);
+ handleIntent(intent, startId);
return START_NOT_STICKY;
}
@Override // Service
public IBinder onBind(final Intent intent) {
return null;
}
+
+ private void handleIntent(Intent intent, int startId) {
+ //Start Intent
+ if (intent.hasExtra(EXTRA_NOTIFICATION)) {
+ currentNotification = intent.getParcelableExtra(EXTRA_NOTIFICATION);
+ startForeground(R.id.foregroundNotification, currentNotification);
+ }
+
+ //Stop Intent
+ if (intent.hasExtra(NotificationService.EXTRA_ACTION_STOP)) {
+ //Call necessary for Oreo+ only
+ if (!AppConstants.Versions.preO) {
+ startForeground(R.id.foregroundNotification, currentNotification);
+ }
+
+ stopForeground(true);
+ stopSelfResult(startId);
+ }
+ }
}