Bug 1450447 - Start using notification channels. r?jchen draft
authorAndrei Lazar <andrei.a.lazar@softvision.ro>
Fri, 06 Jul 2018 17:57:22 +0300
changeset 815005 7167f164d41e23b499a02a6477a95575683e1fd7
parent 814904 fa376bf17cc95539f5e37186977d760296fb5093
push id115401
push userbmo:andrei.a.lazar@softvision.ro
push dateFri, 06 Jul 2018 14:59:32 +0000
reviewersjchen
bugs1450447
milestone63.0a1
Bug 1450447 - Start using notification channels. r?jchen Made all the notifications within the app to use notification channel for devices with API26 and higher. MozReview-Commit-ID: CVmpitNsS66
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/DataReportingNotification.java
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/java/org/mozilla/gecko/GuestSession.java
mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java
mobile/android/base/java/org/mozilla/gecko/notifications/WhatsNewReceiver.java
mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueHelper.java
mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueService.java
mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
mobile/android/base/java/org/mozilla/gecko/updater/UpdateService.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountNotificationManager.java
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -230,17 +230,16 @@ public class BrowserApp extends GeckoApp
     public static final int ACTIVITY_REQUEST_TRIPLE_READERVIEW = 4001;
     public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK = 4002;
     public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE = 4003;
 
     public static final String ACTION_VIEW_MULTIPLE = AppConstants.ANDROID_PACKAGE_NAME + ".action.VIEW_MULTIPLE";
 
     @RobocopTarget
     public static final String EXTRA_SKIP_STARTPANE = "skipstartpane";
-    private static final String EOL_NOTIFIED = "eol_notified";
 
     /**
      * Be aware of {@link org.mozilla.gecko.fxa.EnvironmentUtils.GECKO_PREFS_FIRSTRUN_UUID}.
      */
     private static final String FIRSTRUN_UUID = "firstrun_uuid";
 
     private BrowserSearch mBrowserSearch;
     private View mBrowserSearchContainer;
@@ -1045,55 +1044,16 @@ public class BrowserApp extends GeckoApp
         SnackbarBuilder.builder(this)
                 .message(R.string.updater_permission_text)
                 .duration(Snackbar.LENGTH_INDEFINITE)
                 .action(R.string.updater_permission_allow)
                 .callback(allowCallback)
                 .buildAndShow();
     }
 
-    private void conditionallyNotifyEOL() {
-        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
-        try {
-            final SharedPreferences prefs = GeckoSharedPrefs.forProfile(this);
-            if (!prefs.contains(EOL_NOTIFIED)) {
-
-                // Launch main App to load SUMO url on EOL notification.
-                final String link = getString(R.string.eol_notification_url,
-                                              AppConstants.MOZ_APP_VERSION,
-                                              AppConstants.OS_TARGET,
-                                              Locales.getLanguageTag(Locale.getDefault()));
-
-                final Intent intent = new Intent(Intent.ACTION_VIEW);
-                intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
-                intent.setData(Uri.parse(link));
-                final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
-                final Notification notification = new NotificationCompat.Builder(this)
-                        .setContentTitle(getString(R.string.eol_notification_title))
-                        .setContentText(getString(R.string.eol_notification_summary))
-                        .setSmallIcon(R.drawable.ic_status_logo)
-                        .setAutoCancel(true)
-                        .setContentIntent(pendingIntent)
-                        .build();
-
-                final NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-                final int notificationID = EOL_NOTIFIED.hashCode();
-                notificationManager.notify(notificationID, notification);
-
-                GeckoSharedPrefs.forProfile(this)
-                                .edit()
-                                .putBoolean(EOL_NOTIFIED, true)
-                                .apply();
-            }
-        } finally {
-            StrictMode.setThreadPolicy(savedPolicy);
-        }
-    }
-
     /**
      * Code to actually show the first run pager, separated
      * for distribution purposes.
      */
     @UiThread
     private void checkFirstrunInternal() {
         showFirstrunPager();
 
--- a/mobile/android/base/java/org/mozilla/gecko/DataReportingNotification.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DataReportingNotification.java
@@ -1,32 +1,31 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.AppConstants.Versions;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Typeface;
 import android.support.v4.app.NotificationCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
 import android.text.style.StyleSpan;
 
+import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.preferences.GeckoPreferences;
+
 public class DataReportingNotification {
 
     private static final String LOGTAG = "DataReportNotification";
 
     public static final String ALERT_NAME_DATAREPORTING_NOTIFICATION = "datareporting-notification";
 
     private static final String PREFS_POLICY_NOTIFIED_TIME = "datareporting.policy.dataSubmissionPolicyNotifiedTime";
     private static final String PREFS_POLICY_VERSION = "datareporting.policy.dataSubmissionPolicyVersion";
@@ -61,16 +60,17 @@ public class DataReportingNotification {
             }
             return;
         }
     }
 
     /**
      * Launch a notification of the data policy, and record notification time and version.
      */
+    @SuppressWarnings("NewApi")
     public static void notifyDataPolicy(Context context, SharedPreferences sharedPrefs) {
         boolean result = false;
         try {
             // Launch main App to launch Data choices when notification is clicked.
             Intent prefIntent = new Intent(GeckoApp.ACTION_LAUNCH_SETTINGS);
             prefIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
 
             GeckoPreferences.setResourceToOpen(prefIntent, "preferences_privacy");
@@ -92,31 +92,34 @@ public class DataReportingNotification {
             String notificationBigSummary = resources.getString(R.string.datareporting_notification_summary);
 
             // Make styled ticker text for display in notification bar.
             String tickerString = resources.getString(R.string.datareporting_notification_ticker_text);
             SpannableString tickerText = new SpannableString(tickerString);
             // Bold the notification title of the ticker text, which is the same string as notificationTitle.
             tickerText.setSpan(new StyleSpan(Typeface.BOLD), 0, notificationTitle.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
 
-            Notification notification = new NotificationCompat.Builder(context)
+            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
                                         .setContentTitle(notificationTitle)
                                         .setContentText(notificationSummary)
                                         .setSmallIcon(R.drawable.ic_status_logo)
                                         .setAutoCancel(true)
                                         .setContentIntent(contentIntent)
                                         .setStyle(new NotificationCompat.BigTextStyle()
                                                                         .bigText(notificationBigSummary))
                                         .addAction(R.drawable.firefox_settings_alert, notificationAction, contentIntent)
-                                        .setTicker(tickerText)
-                                        .build();
+                                        .setTicker(tickerText);
+
+            if (!AppConstants.Versions.preO) {
+                notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+            }
 
             NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
             int notificationID = ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode();
-            notificationManager.notify(notificationID, notification);
+            notificationManager.notify(notificationID, notificationBuilder.build());
 
             // Record version and notification time.
             SharedPreferences.Editor editor = sharedPrefs.edit();
             long now = System.currentTimeMillis();
             editor.putLong(PREFS_POLICY_NOTIFIED_TIME, now);
             editor.putInt(PREFS_POLICY_VERSION, DATA_REPORTING_VERSION);
             editor.apply();
             result = true;
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -1,17 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import android.Manifest;
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.Application;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
@@ -68,16 +71,18 @@ import java.net.URL;
 import java.util.UUID;
 
 public class GeckoApplication extends Application
                               implements HapticFeedbackDelegate {
     private static final String LOG_TAG = "GeckoApplication";
     public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
     private static final String MEDIA_DECODING_PROCESS_CRASH = "MEDIA_DECODING_PROCESS_CRASH";
 
+    private static NotificationChannel defaultNotificationChannel = null;
+
     private boolean mInBackground;
     private boolean mPausedGecko;
     private boolean mIsInitialResume;
 
     private LightweightTheme mLightweightTheme;
 
     private RefWatcher mRefWatcher;
 
@@ -344,16 +349,20 @@ public class GeckoApplication extends Ap
         NotificationHelper.getInstance(context).init();
 
         MulticastDNSManager.getInstance(context).init();
 
         GeckoService.register();
 
         IntentHelper.init();
 
+        if (!AppConstants.Versions.preO) {
+            createDefaultNotificationChannel();
+        }
+
         EventDispatcher.getInstance().registerGeckoThreadListener(mListener,
                 "Distribution:GetDirectories",
                 null);
         EventDispatcher.getInstance().registerUiThreadListener(mListener,
                 "Gecko:Exited",
                 "RuntimePermissions:Check",
                 "Snackbar:Show",
                 "Share:Text",
@@ -401,16 +410,30 @@ public class GeckoApplication extends Ap
             final Method onCreate = clazz.getMethod("onCreate", Context.class);
             return (Boolean) onCreate.invoke(null, getApplicationContext()); // Method is static.
         } catch (Exception e) {
             Log.e(LOG_TAG, "Got exception during startup; ignoring.", e);
             return false;
         }
     }
 
+    @TargetApi(26)
+    private void createDefaultNotificationChannel() {
+        final String DEFAULT_CHANNEL = AppConstants.MOZ_APP_DISPLAYNAME;
+        final String DEFAULT_NAME = AppConstants.MOZ_APP_DISPLAYNAME;
+        final int DEFAULT_IMPORTANCE = NotificationManager.IMPORTANCE_HIGH;
+
+        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+        defaultNotificationChannel = notificationManager.getNotificationChannel(DEFAULT_CHANNEL);
+        if (defaultNotificationChannel == null) {
+            defaultNotificationChannel = new NotificationChannel(DEFAULT_CHANNEL, DEFAULT_NAME, DEFAULT_IMPORTANCE);
+            notificationManager.createNotificationChannel(defaultNotificationChannel);
+        }
+    }
+
     public void onDelayedStartup() {
         if (AppConstants.MOZ_ANDROID_GCM) {
             // TODO: only run in main process.
             ThreadUtils.postToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
                     initPushService();
                 }
@@ -596,16 +619,20 @@ public class GeckoApplication extends Ap
                 // Init push service and redirect the event to it.
                 if (initPushService()) {
                     EventDispatcher.getInstance().dispatch(event, message, callback);
                 }
             }
         }
     }
 
+    public static NotificationChannel getDefaultNotificationChannel() {
+        return defaultNotificationChannel;
+    }
+
     public boolean isApplicationInBackground() {
         return mInBackground;
     }
 
     public LightweightTheme getLightweightTheme() {
         return mLightweightTheme;
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/GuestSession.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GuestSession.java
@@ -1,45 +1,47 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mozilla.gecko;
 
-import android.app.KeyguardManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
-import android.support.v4.app.NotificationCompat;
-import android.view.Window;
-import android.view.WindowManager;
+import android.support.v7.app.NotificationCompat;
 
 // Utility methods for entering/exiting guest mode.
 public final class GuestSession {
     private static final String LOGTAG = "GeckoGuestSession";
 
     public static final String NOTIFICATION_INTENT = "org.mozilla.gecko.GUEST_SESSION_INPROGRESS";
 
     private static PendingIntent getNotificationIntent(Context context) {
         Intent intent = new Intent(NOTIFICATION_INTENT);
         intent.setClassName(context, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
         return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
+    @SuppressWarnings("NewApi")
     public static void showNotification(Context context) {
         final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
         final Resources res = context.getResources();
         builder.setContentTitle(res.getString(R.string.guest_browsing_notification_title))
                .setContentText(res.getString(R.string.guest_browsing_notification_text))
                .setSmallIcon(R.drawable.alert_guest)
                .setOngoing(true)
                .setContentIntent(getNotificationIntent(context));
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         final NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         manager.notify(R.id.guestNotification, builder.build());
     }
 
     public static void hideNotification(Context context) {
         final NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         manager.cancel(R.id.guestNotification);
     }
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaControlService.java
@@ -18,19 +18,22 @@ import android.media.session.MediaContro
 import android.media.session.MediaSession;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.annotation.CheckResult;
 import android.support.annotation.NonNull;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.app.NotificationManagerCompat;
+import android.support.v7.app.NotificationCompat;
 import android.util.Log;
 
+import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.IntentHelper;
 import org.mozilla.gecko.PrefsHelper;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.util.ThreadUtils;
 
 public class MediaControlService extends Service {
     private static final String LOGTAG = "MediaControlService";
@@ -360,40 +363,46 @@ public class MediaControlService extends
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 updateNotification(tab);
             }
         });
     }
 
+    @SuppressWarnings("NewApi")
     protected void updateNotification(Tab tab) {
         ThreadUtils.assertNotOnUiThread();
 
         final Notification.MediaStyle style = new Notification.MediaStyle();
         style.setShowActionsInCompactView(0);
 
         final boolean isPlaying = isMediaPlaying();
         final int visibility = tab.isPrivate() ?
             Notification.VISIBILITY_PRIVATE : Notification.VISIBILITY_PUBLIC;
 
-        final Notification notification = new Notification.Builder(this)
+        final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
             .setSmallIcon(R.drawable.ic_status_logo)
             .setLargeIcon(generateCoverArt(tab))
             .setContentTitle(tab.getTitle())
             .setContentText(tab.getURL())
             .setContentIntent(createContentIntent(tab))
             .setDeleteIntent(createDeleteIntent())
             .setStyle(style)
             .addAction(createNotificationAction())
             .setOngoing(isPlaying)
             .setShowWhen(false)
             .setWhen(0)
-            .setVisibility(visibility)
-            .build();
+            .setVisibility(visibility);
+
+        if (!AppConstants.Versions.preO) {
+            notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
+        final Notification notification = notificationBuilder.build();
 
         if (isPlaying) {
             startForeground(R.id.mediaControlNotification, notification);
         } else {
             stopForeground(false);
             NotificationManagerCompat.from(this)
                 .notify(R.id.mediaControlNotification, notification);
         }
--- a/mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/mma/MmaLeanplumImp.java
@@ -1,38 +1,37 @@
 //#filter substitution
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.mma;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Notification;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.NonNull;
 import android.support.v4.app.NotificationCompat;
 
 import com.leanplum.Leanplum;
 import com.leanplum.LeanplumActivityHelper;
 import com.leanplum.LeanplumPushNotificationCustomizer;
 import com.leanplum.LeanplumPushService;
 import com.leanplum.internal.Constants;
 import com.leanplum.internal.LeanplumInternal;
-import com.leanplum.internal.VarCache;
 
 import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.MmaConstants;
 
 import java.util.Map;
-import java.util.UUID;
 
 
 public class MmaLeanplumImp implements MmaInterface {
 
 
     @Override
     public void init(final Activity activity, Map<String, ?> attributes) {
         if (activity == null) {
@@ -73,25 +72,28 @@ public class MmaLeanplumImp implements M
         activity.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 LeanplumActivityHelper.onResume(activity);
             }
         });
     }
 
+    @SuppressLint("NewApi")
     @Override
     public void setCustomIcon(@DrawableRes final int iconResId) {
         LeanplumPushService.setCustomizer(new LeanplumPushNotificationCustomizer() {
             @Override
             public void customize(NotificationCompat.Builder builder, Bundle notificationPayload) {
                 builder.setSmallIcon(iconResId);
                 builder.setDefaults(Notification.DEFAULT_SOUND);
+                if (!AppConstants.Versions.preO) {
+                    builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+                }
             }
-
         });
     }
 
     @Override
     public void start(Context context) {
 
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java
@@ -1,38 +1,37 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.notifications;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.Notification;
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
-import android.util.Log;
-
-import java.util.HashMap;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoActivityMonitor;
-import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.GeckoService;
 import org.mozilla.gecko.NotificationListener;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.util.BitmapUtils;
 
+import java.util.HashMap;
+
 /**
  * Client for posting notifications.
  */
 public final class NotificationClient implements NotificationListener {
     private static final String LOGTAG = "GeckoNotificationClient";
     /* package */ static final String CLICK_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".NOTIFICATION_CLICK";
     /* package */ static final String CLOSE_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".NOTIFICATION_CLOSE";
     /* package */ static final String PERSISTENT_INTENT_EXTRA = "persistentIntent";
@@ -134,31 +133,36 @@ public final class NotificationClient im
      *
      * @param name           the unique name of the notification
      * @param imageUrl       URL of the image to use
      * @param alertTitle     title of the notification
      * @param alertText      text of the notification
      * @param contentIntent  Intent used when the notification is clicked
      * @param deleteIntent   Intent used when the notification is closed
      */
+    @SuppressLint("NewApi")
     private void add(final String name, final String imageUrl, final String host,
                      final String alertTitle, final String alertText,
                      final PendingIntent contentIntent, final PendingIntent deleteIntent) {
         final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
                 .setContentTitle(alertTitle)
                 .setContentText(alertText)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setContentIntent(contentIntent)
                 .setDeleteIntent(deleteIntent)
                 .setAutoCancel(true)
                 .setDefaults(Notification.DEFAULT_SOUND)
                 .setStyle(new NotificationCompat.BigTextStyle()
                         .bigText(alertText)
                         .setSummaryText(host));
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         // Fetch icon.
         if (!imageUrl.isEmpty()) {
             final Bitmap image = BitmapUtils.decodeUrl(imageUrl);
             builder.setLargeIcon(image);
         }
 
         builder.setWhen(System.currentTimeMillis());
         final Notification notification = builder.build();
@@ -208,34 +212,39 @@ public final class NotificationClient im
     /**
      * Updates a notification.
      *
      * @param name          Name of existing notification
      * @param progress      progress of item being updated
      * @param progressMax   max progress of item being updated
      * @param alertText     text of the notification
      */
+    @SuppressLint("NewApi")
     public void update(final String name, final long progress,
                        final long progressMax, final String alertText) {
         Notification notification;
         synchronized (this) {
             notification = mNotifications.get(name);
         }
         if (notification == null) {
             return;
         }
 
-        notification = new NotificationCompat.Builder(mContext)
+        final Notification.Builder notificationBuilder = new Notification.Builder(mContext)
                 .setContentText(alertText)
                 .setSmallIcon(notification.icon)
                 .setWhen(notification.when)
                 .setContentIntent(notification.contentIntent)
-                .setProgress((int) progressMax, (int) progress, false)
-                .build();
+                .setProgress((int) progressMax, (int) progress, false);
 
+        if (!AppConstants.Versions.preO) {
+            notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
+        notification = notificationBuilder.build();
         add(name, notification);
     }
 
     /* package */ synchronized Notification onNotificationClose(final String name) {
         mNotificationManager.cancel(name, 0);
 
         final Notification notification = mNotifications.remove(name);
         if (notification != null) {
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java
@@ -1,47 +1,47 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.notifications;
 
-import java.io.File;
-import java.io.UnsupportedEncodingException;
-import java.net.URLConnection;
-import java.net.URLDecoder;
-import java.util.List;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoActivityMonitor;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.mozglue.SafeIntent;
-import org.mozilla.gecko.util.BitmapUtils;
-import org.mozilla.gecko.util.BundleEventListener;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.GeckoBundle;
-import org.mozilla.gecko.util.ThreadUtils;
-
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.StrictMode;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.util.SimpleArrayMap;
 import android.util.Log;
 
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.GeckoActivityMonitor;
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.mozglue.SafeIntent;
+import org.mozilla.gecko.util.BitmapUtils;
+import org.mozilla.gecko.util.BundleEventListener;
+import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.GeckoBundle;
+import org.mozilla.gecko.util.ThreadUtils;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.List;
+
 public final class NotificationHelper implements BundleEventListener {
     public static final String HELPER_BROADCAST_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".helperBroadcastAction";
 
     public static final String NOTIFICATION_ID = "NotificationHelper_ID";
     private static final String LOGTAG = "GeckoNotificationHelper";
     private static final String HELPER_NOTIFICATION = "helperNotif";
 
     // Attributes mandatory to be used while sending a notification from js.
@@ -226,16 +226,17 @@ public final class NotificationHelper im
         }
 
         final Intent notificationIntent = buildNotificationIntent(message, builder);
         PendingIntent res = PendingIntent.getBroadcast(
                 mContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
         return res;
     }
 
+    @SuppressWarnings("NewApi")
     private void showNotification(final GeckoBundle message) {
         ThreadUtils.assertOnUiThread();
 
         final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
 
         // These attributes are required
         final String id = message.getString(ID_ATTR);
         builder.setContentTitle(message.getString(TITLE_ATTR));
@@ -244,16 +245,20 @@ public final class NotificationHelper im
         final Uri imageUri = Uri.parse(message.getString(SMALLICON_ATTR, ""));
         builder.setSmallIcon(BitmapUtils.getResource(mContext, imageUri));
 
         final int[] light = message.getIntArray(LIGHT_ATTR);
         if (light != null && light.length == 3) {
             builder.setLights(light[0], light[1], light[2]);
         }
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         final boolean ongoing = message.getBoolean(ONGOING_ATTR);
         builder.setOngoing(ongoing);
 
         if (message.containsKey(WHEN_ATTR)) {
             final long when = (long) message.getDouble(WHEN_ATTR);
             builder.setWhen(when);
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/notifications/WhatsNewReceiver.java
+++ b/mobile/android/base/java/org/mozilla/gecko/notifications/WhatsNewReceiver.java
@@ -10,16 +10,17 @@ import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.support.v4.app.NotificationCompat;
 import android.text.TextUtils;
 
+import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.switchboard.SwitchBoard;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.GeckoSharedPrefs;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.preferences.GeckoPreferences;
@@ -54,29 +55,33 @@ public class WhatsNewReceiver extends Br
 
         showWhatsNewNotification(context);
     }
 
     private boolean isPreferenceEnabled(Context context) {
         return GeckoSharedPrefs.forApp(context).getBoolean(GeckoPreferences.PREFS_NOTIFICATIONS_WHATS_NEW, true);
     }
 
+    @SuppressWarnings("NewApi")
     private void showWhatsNewNotification(Context context) {
-        final Notification notification = new NotificationCompat.Builder(context)
+        final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
                 .setContentTitle(context.getString(R.string.whatsnew_notification_title))
                 .setContentText(context.getString(R.string.whatsnew_notification_summary))
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setAutoCancel(true)
                 .setContentIntent(getContentIntent(context))
-                .setDeleteIntent(getDeleteIntent(context))
-                .build();
+                .setDeleteIntent(getDeleteIntent(context));
 
-        final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        if (!AppConstants.Versions.preO) {
+            notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         final int notificationID = EXTRA_WHATSNEW_NOTIFICATION.hashCode();
-        notificationManager.notify(notificationID, notification);
+        final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.notify(notificationID, notificationBuilder.build());
 
         Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.NOTIFICATION, EXTRA_WHATSNEW_NOTIFICATION);
     }
 
     private PendingIntent getContentIntent(Context context) {
         final String link = context.getString(R.string.whatsnew_notification_url,
             AppConstants.MOZ_APP_VERSION,
             AppConstants.OS_TARGET,
--- a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueHelper.java
@@ -1,41 +1,40 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.tabqueue;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-import org.mozilla.gecko.util.GeckoBundle;
-import org.mozilla.gecko.util.ThreadUtils;
-
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
-import android.os.Build;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.content.ContextCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
 
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.preferences.GeckoPreferences;
+import org.mozilla.gecko.util.GeckoBundle;
+import org.mozilla.gecko.util.ThreadUtils;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class TabQueueHelper {
     private static final String LOGTAG = "Gecko" + TabQueueHelper.class.getSimpleName();
 
     // Disable Tab Queue for API level 10 (GB) - Bug 1206055
@@ -216,16 +215,17 @@ public class TabQueueHelper {
 
     /**
      * Displays a notification showing the total number of tabs queue.  If there is already a notification displayed, it
      * will be replaced.
      *
      * @param context
      * @param tabsQueued
      */
+    @SuppressWarnings("NewApi")
     public static void showNotification(final Context context, final int tabsQueued, final List<String> urls) {
         ThreadUtils.assertNotOnUiThread();
 
         Intent resultIntent = new Intent();
         resultIntent.setClassName(context, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
         resultIntent.setAction(TabQueueHelper.LOAD_URLS_ACTION);
 
         PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_CANCEL_CURRENT);
@@ -249,16 +249,20 @@ public class TabQueueHelper {
                                                      .setSmallIcon(R.drawable.ic_status_logo)
                                                      .setContentTitle(text)
                                                      .setContentText(resources.getString(R.string.tab_queue_notification_title))
                                                      .setStyle(inboxStyle)
                                                      .setColor(ContextCompat.getColor(context, R.color.fennec_ui_accent))
                                                      .setNumber(tabsQueued)
                                                      .setContentIntent(pendingIntent);
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         notificationManager.notify(TabQueueHelper.TAB_QUEUE_NOTIFICATION_ID, builder.build());
     }
 
     public static boolean shouldOpenTabQueueUrls(final Context context) {
         ThreadUtils.assertNotOnUiThread();
 
         // TODO: Use profile shared prefs when bug 1147925 gets fixed.
--- a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueService.java
@@ -1,25 +1,19 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.tabqueue;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-
+import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 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.content.res.Resources;
 import android.graphics.PixelFormat;
 import android.net.Uri;
@@ -34,17 +28,26 @@ import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.Button;
 import android.widget.TextView;
 import android.widget.Toast;
+
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.mozglue.SafeIntent;
+import org.mozilla.gecko.preferences.GeckoPreferences;
 
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 
 /**
  * On launch this Service displays a View over the currently running process with an action to open the url in Fennec
@@ -228,44 +231,49 @@ public class TabQueueService extends Ser
             public void run() {
                 int queuedTabCount = TabQueueHelper.getTabQueueLength(TabQueueService.this);
                 Telemetry.addToHistogram("FENNEC_TABQUEUE_QUEUESIZE", queuedTabCount);
             }
         });
 
     }
 
+    @SuppressLint("NewApi")
     @TargetApi(Build.VERSION_CODES.M)
     private void showSettingsNotification() {
         if (AppConstants.Versions.preMarshmallow) {
             return;
         }
 
         final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
         intent.setData(Uri.parse("package:" + getPackageName()));
         PendingIntent pendingIntent = PendingIntent.getActivity(this, intent.hashCode(), intent, 0);
 
         final String text = getString(R.string.tab_queue_notification_settings);
 
         final NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle()
                 .bigText(text);
 
-        final Notification notification = new NotificationCompat.Builder(this)
+        final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                 .setContentTitle(getString(R.string.pref_tab_queue_title))
                 .setContentText(text)
                 .setCategory(NotificationCompat.CATEGORY_ERROR)
                 .setStyle(style)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setContentIntent(pendingIntent)
                 .setPriority(NotificationCompat.PRIORITY_MAX)
                 .setAutoCancel(true)
-                .addAction(R.drawable.ic_action_settings, getString(R.string.tab_queue_prompt_settings_button), pendingIntent)
-                .build();
+                .addAction(R.drawable.ic_action_settings, getString(R.string.tab_queue_prompt_settings_button), pendingIntent);
 
-        NotificationManagerCompat.from(this).notify(R.id.tabQueueSettingsNotification, notification);
+        if (!AppConstants.Versions.preO) {
+            notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
+        NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
+        notificationManager.notify(R.id.tabQueueSettingsNotification, notificationBuilder.build());
     }
 
     private void removeView() {
         try {
             windowManager.removeView(toastLayout);
         } catch (IllegalArgumentException | IllegalStateException e) {
             // This can happen if the Service is killed by the system.  If this happens the View will have already
             // been removed but the runnable will have been kept alive.
--- a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabReceivedService.java
@@ -1,34 +1,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.tabqueue;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.BrowserLocaleManager;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.db.BrowserContract;
-
 import android.app.IntentService;
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
 import android.util.Log;
 
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.BrowserLocaleManager;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.db.BrowserContract;
+
 /**
  * An IntentService that displays a notification for a tab sent to this device.
  *
  * The expected Intent should contain:
  *   * Data: URI to open in the notification
  *   * EXTRA_TITLE: Page title of the URI to open
  */
 public class TabReceivedService extends IntentService {
@@ -38,16 +39,17 @@ public class TabReceivedService extends 
 
     private static final int MAX_NOTIFICATION_COUNT = 1000;
 
     public TabReceivedService() {
         super(LOGTAG);
         setIntentRedelivery(true);
     }
 
+    @SuppressWarnings("NewApi")
     @Override
     protected void onHandleIntent(final Intent intent) {
         // IntentServices don't keep the process alive so
         // we need to do this every time. Ideally, we wouldn't.
         final Resources res = getResources();
         BrowserLocaleManager.getInstance().correctLocale(this, res, res.getConfiguration());
 
         final String uri = intent.getDataString();
@@ -64,16 +66,20 @@ public class TabReceivedService extends 
         final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
         builder.setSmallIcon(R.drawable.ic_status_logo);
         builder.setContentTitle(notificationTitle);
         builder.setWhen(System.currentTimeMillis());
         builder.setAutoCancel(true);
         builder.setContentText(uri);
         builder.setContentIntent(contentIntent);
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         // Trigger "heads-up" notification mode on supported Android versions.
         builder.setPriority(NotificationCompat.PRIORITY_HIGH);
         final Uri notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
         if (notificationSoundUri != null) {
             builder.setSound(notificationSoundUri);
         }
 
         final SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
--- a/mobile/android/base/java/org/mozilla/gecko/updater/UpdateService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/updater/UpdateService.java
@@ -1,52 +1,50 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.updater;
 
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.CrashHandler;
-import org.mozilla.gecko.R;
-
-import org.mozilla.apache.commons.codec.binary.Hex;
-
-import org.mozilla.gecko.permissions.Permissions;
-import org.mozilla.gecko.util.IOUtils;
-import org.mozilla.gecko.util.ProxySelector;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
 import android.Manifest;
 import android.app.AlarmManager;
 import android.app.IntentService;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 import android.os.Environment;
 import android.provider.Settings;
+import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.content.FileProvider;
 import android.support.v4.net.ConnectivityManagerCompat;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationCompat.Builder;
 import android.util.Log;
 
+import org.mozilla.apache.commons.codec.binary.Hex;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.CrashHandler;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.permissions.Permissions;
+import org.mozilla.gecko.util.IOUtils;
+import org.mozilla.gecko.util.ProxySelector;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
@@ -79,17 +77,17 @@ public class UpdateService extends Inten
     private static final String KEY_LAST_ATTEMPT_DATE = "UpdateService.lastAttemptDate";
     private static final String KEY_AUTODOWNLOAD_POLICY = "UpdateService.autoDownloadPolicy";
     private static final String KEY_UPDATE_URL = "UpdateService.updateUrl";
 
     private SharedPreferences mPrefs;
 
     private NotificationManagerCompat mNotificationManager;
     private ConnectivityManager mConnectivityManager;
-    private Builder mBuilder;
+    private NotificationCompat.Builder mBuilder;
 
     private volatile WifiLock mWifiLock;
 
     private boolean mDownloading;
     private boolean mCancelDownload;
     private boolean mApplyImmediately;
 
     private CrashHandler mCrashHandler;
@@ -300,16 +298,17 @@ public class UpdateService extends Inten
                 .run(new Runnable() {
                     @Override
                     public void run() {
                         startDownload(info, flags);
                     }
                 });
     }
 
+    @SuppressWarnings("NewApi")
     private void startDownload(UpdateInfo info, int flags) {
         AutoDownloadPolicy policy = getAutoDownloadPolicy();
 
         // We only start a download automatically if one of following criteria are met:
         //
         // - We have a FORCE_DOWNLOAD flag passed in
         // - The preference is set to 'always'
         // - The preference is set to 'wifi' and we are using a non-metered network (i.e. the user
@@ -331,16 +330,20 @@ public class UpdateService extends Inten
             NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
             builder.setSmallIcon(R.drawable.ic_status_logo);
             builder.setWhen(System.currentTimeMillis());
             builder.setAutoCancel(true);
             builder.setContentTitle(getString(R.string.updater_start_title));
             builder.setContentText(getString(R.string.updater_start_select));
             builder.setContentIntent(contentIntent);
 
+            if (!AppConstants.Versions.preO) {
+                builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+            }
+
             mNotificationManager.notify(NOTIFICATION_ID, builder.build());
 
             return;
         }
 
         File pkg = downloadUpdatePackage(info, hasFlag(flags, UpdateServiceHelper.FLAG_OVERWRITE_EXISTING));
         if (pkg == null) {
             sendCheckUpdateResult(CheckUpdateResult.NOT_AVAILABLE);
@@ -357,25 +360,28 @@ public class UpdateService extends Inten
         } else {
             // Prompt to apply the update
 
             Intent notificationIntent = new Intent(UpdateServiceHelper.ACTION_APPLY_UPDATE);
             notificationIntent.setClass(this, UpdateService.class);
             notificationIntent.putExtra(UpdateServiceHelper.EXTRA_PACKAGE_PATH_NAME, pkg.getAbsolutePath());
             PendingIntent contentIntent = PendingIntent.getService(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
-
             NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
             builder.setSmallIcon(R.drawable.ic_status_logo);
             builder.setWhen(System.currentTimeMillis());
             builder.setAutoCancel(true);
             builder.setContentTitle(getString(R.string.updater_apply_title));
             builder.setContentText(getString(R.string.updater_apply_select));
             builder.setContentIntent(contentIntent);
 
+            if (!AppConstants.Versions.preO) {
+                builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+            }
+
             mNotificationManager.notify(NOTIFICATION_ID, builder.build());
         }
     }
 
     private UpdateInfo findUpdate(boolean force) {
         URLConnection conn = null;
         try {
             URI uri = getUpdateURI(force);
@@ -486,32 +492,40 @@ public class UpdateService extends Inten
 
         mBuilder = new NotificationCompat.Builder(this);
         mBuilder.setContentTitle(getResources().getString(R.string.updater_downloading_title))
                 .setContentText(mApplyImmediately ? "" : getResources().getString(R.string.updater_downloading_select))
                 .setSmallIcon(android.R.drawable.stat_sys_download)
                 .setContentIntent(contentIntent)
                 .setDeleteIntent(deleteIntent);
 
+        if (!AppConstants.Versions.preO) {
+            mBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         mBuilder.setProgress(100, 0, true);
         mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
     }
 
     private void showDownloadFailure() {
         Intent notificationIntent = new Intent(UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE);
         notificationIntent.setClass(this, UpdateService.class);
         PendingIntent contentIntent = PendingIntent.getService(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
         NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
         builder.setSmallIcon(R.drawable.ic_status_logo);
         builder.setWhen(System.currentTimeMillis());
         builder.setContentTitle(getString(R.string.updater_downloading_title_failed));
         builder.setContentText(getString(R.string.updater_downloading_retry));
         builder.setContentIntent(contentIntent);
 
+        if (!AppConstants.Versions.preO) {
+            builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
+
         mNotificationManager.notify(NOTIFICATION_ID, builder.build());
     }
 
     private boolean deleteUpdatePackage(String path) {
         if (path == null) {
             return false;
         }
 
@@ -713,28 +727,31 @@ public class UpdateService extends Inten
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                 Uri.fromParts("package", getPackageName(), null));
 
         PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
 
         NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle()
                 .bigText(getString(R.string.updater_permission_text));
 
-        Notification notification = new NotificationCompat.Builder(this)
+        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                 .setContentTitle(getString(R.string.updater_permission_title))
                 .setContentText(getString(R.string.updater_permission_text))
                 .setStyle(bigTextStyle)
                 .setAutoCancel(true)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setColor(ContextCompat.getColor(this, R.color.rejection_red))
-                .setContentIntent(pendingIntent)
-                .build();
+                .setContentIntent(pendingIntent);
+
+        if (!AppConstants.Versions.preO) {
+            notificationBuilder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+        }
 
         NotificationManagerCompat.from(this)
-                .notify(R.id.updateServicePermissionNotification, notification);
+                .notify(R.id.updateServicePermissionNotification, notificationBuilder.build());
     }
 
     private String getLastBuildID() {
         return mPrefs.getString(KEY_LAST_BUILDID, null);
     }
 
     private String getLastHashFunction() {
         return mPrefs.getString(KEY_LAST_HASH_FUNCTION, null);
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -819,19 +819,16 @@ just addresses the organization to follo
 <!-- LOCALIZATION NOTE (unsupported_sdk_version): The user installed a build of this app that does not support
      the Android version of this device. the formatS1 is replaced by the CPU ABI (e.g., ARMv7); the formatS2 is
      replaced by the Android OS version (e.g., 14)-->
 <!ENTITY unsupported_sdk_version "Sorry! This &brandShortName; won\'t work on this device (&formatS1;, &formatS2;). Please download the correct version.">
 
 <!-- LOCALIZATION NOTE(corrupt_apk): This notification is shown if corruption has been detected on startup and the user has to reinstall Firefox -->
 <!ENTITY corrupt_apk "Unable to open &brandShortName;. Please reinstall and try again.">
 
-<!ENTITY eol_notification_title2 "&brandShortName; will no longer update">
-<!ENTITY eol_notification_summary "Tap to learn more">
-
 <!-- LOCALIZATION NOTE (whatsnew_notification_title, whatsnew_notification_summary): These strings
      are used for a system notification that's shown to users after the app updates. -->
 <!ENTITY whatsnew_notification_title "&brandShortName; is up to date">
 <!ENTITY whatsnew_notification_summary "Find out what\'s new in this version">
 
 <!ENTITY promotion_add_page_shortcut "Add page shortcut">
 
 <!ENTITY helper_first_offline_bookmark_title "Read offline">
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -594,20 +594,17 @@
 
   <string name="intent_uri_private_browsing_prompt">&intent_uri_private_browsing_prompt;</string>
   <string name="intent_uri_private_browsing_multiple_match_title">&intent_uri_private_browsing_multiple_match_title;</string>
 
   <string name="devtools_auth_scan_header">&devtools_auth_scan_header;</string>
 
   <string name="unsupported_sdk_version">&unsupported_sdk_version;</string>
   <string name="corrupt_apk">&corrupt_apk;</string>
-  <string name="eol_notification_title">&eol_notification_title2;</string>
-  <string name="eol_notification_summary">&eol_notification_summary;</string>
   <!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/honeycomb -->
-  <string name="eol_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/unsupported-version</string>
 
   <string name="whatsnew_notification_title">&whatsnew_notification_title;</string>
   <string name="whatsnew_notification_summary">&whatsnew_notification_summary;</string>
   <!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/new-android -->
   <string name="whatsnew_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/new-android</string>
 
   <string name="promotion_add_page_shortcut">&promotion_add_page_shortcut;</string>
 
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountNotificationManager.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/sync/FxAccountNotificationManager.java
@@ -1,20 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.sync;
 
+import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationCompat.Builder;
+import android.support.v7.app.NotificationCompat;
+
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.GeckoApplication;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.State;
@@ -57,16 +60,17 @@ public class FxAccountNotificationManage
    * Reflect new Firefox Account state to the notification manager: show or hide
    * notifications reflecting the state of a Firefox Account.
    *
    * @param context
    *          Android context.
    * @param fxAccount
    *          Firefox Account to reflect to the notification manager.
    */
+  @SuppressWarnings("NewApi")
   public void update(Context context, AndroidFxAccount fxAccount) {
     final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 
     final State state = fxAccount.getState();
     final Action action = state.getNeededAction();
     if (action == Action.None) {
       Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs no action; cancelling any existing notification.");
       notificationManager.cancel(notificationId);
@@ -95,18 +99,23 @@ public class FxAccountNotificationManage
 
     notificationIntent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_NOTIFICATION);
 
     Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs action; offering notification with title: " + title);
     FxAccountUtils.pii(LOG_TAG, "And text: " + text);
 
     final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
 
-    final Builder builder = new NotificationCompat.Builder(context);
+    final NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
     builder
     .setContentTitle(title)
     .setContentText(text)
     .setSmallIcon(R.drawable.ic_status_logo)
     .setAutoCancel(true)
     .setContentIntent(pendingIntent);
+
+    if (!AppConstants.Versions.preO) {
+      builder.setChannelId(GeckoApplication.getDefaultNotificationChannel().getId());
+    }
+
     notificationManager.notify(notificationId, builder.build());
   }
 }