Bug 1267639 - Use ContentNotificationsDelegate as single point for handling content notifications intents. r=grisha a=lizzard
authorSebastian Kaspari <s.kaspari@gmail.com>
Mon, 09 May 2016 16:55:23 +0200
changeset 332853 ccd48b5382d1afb2a0084a53cc3ef6115b5ba9c0
parent 332852 495ad891feb1cd911d504d003dfa7345c818423b
child 332854 8e724faf0734aabdb05020be65798a68f46ac354
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgrisha, lizzard
bugs1267639
milestone48.0a2
Bug 1267639 - Use ContentNotificationsDelegate as single point for handling content notifications intents. r=grisha a=lizzard
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/feeds/ContentNotificationsDelegate.java
mobile/android/base/java/org/mozilla/gecko/feeds/action/CheckForUpdatesAction.java
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -25,16 +25,17 @@ import org.mozilla.gecko.db.BrowserContr
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.SuggestedSites;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.distribution.DistributionStoreCallback;
 import org.mozilla.gecko.dlc.DownloadContentService;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.favicons.decoders.IconDirectoryEntry;
+import org.mozilla.gecko.feeds.ContentNotificationsDelegate;
 import org.mozilla.gecko.feeds.FeedService;
 import org.mozilla.gecko.feeds.action.CheckForUpdatesAction;
 import org.mozilla.gecko.firstrun.FirstrunAnimationContainer;
 import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
 import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.home.BrowserSearch;
@@ -239,16 +240,18 @@ public class BrowserApp extends GeckoApp
     private TabHistoryController tabHistoryController;
     private ZoomedView mZoomedView;
     private AddToHomeScreenPromotion mAddToHomeScreenPromotion;
 
     private static final int GECKO_TOOLS_MENU = -1;
     private static final int ADDON_MENU_OFFSET = 1000;
     public static final String TAB_HISTORY_FRAGMENT_TAG = "tabHistoryFragment";
 
+    private ContentNotificationsDelegate contentNotificationsDelegate = new ContentNotificationsDelegate();
+
     private static class MenuItemInfo {
         public int id;
         public String label;
         public boolean checkable;
         public boolean checked;
         public boolean enabled = true;
         public boolean visible = true;
         public int parent;
@@ -848,16 +851,18 @@ public class BrowserApp extends GeckoApp
                                showUpdaterPermissionSnackbar();
                            }
                        })
                       .run();
         }
 
         mAddToHomeScreenPromotion = new AddToHomeScreenPromotion(this);
         AudioFocusAgent.getInstance().attachToContext(this);
+
+        contentNotificationsDelegate.onCreate(this, savedInstanceState);
     }
 
     /**
      * Initializes the default Switchboard URLs the first time.
      * @param intent
      */
     private void initSwitchboard(Intent intent) {
         if (Experiments.isDisabled(new SafeIntent(intent)) || !AppConstants.MOZ_SWITCHBOARD) {
@@ -1063,26 +1068,16 @@ public class BrowserApp extends GeckoApp
         }
     }
 
     private void openMultipleTabsFromIntent(final Intent intent) {
         final List<String> urls = intent.getStringArrayListExtra("urls");
         if (urls != null) {
             openUrls(urls);
         }
-
-        // Launched from a "content notification"
-        if (intent.hasExtra(CheckForUpdatesAction.EXTRA_CONTENT_NOTIFICATION)) {
-            Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this));
-
-            Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.NOTIFICATION, "content_update");
-            Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "content_update");
-
-            Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this));
-        }
     }
 
     @Override
     public void onResume() {
         super.onResume();
 
         // Needed for Adjust to get accurate session measurements
         AdjustConstants.getAdjustHelper().onResume();
@@ -3829,16 +3824,18 @@ public class BrowserApp extends GeckoApp
             });
         }
 
         // Custom intent action for opening multiple URLs at once
         if (isViewMultipleAction) {
             openMultipleTabsFromIntent(intent);
         }
 
+        contentNotificationsDelegate.onNewIntent(this, intent);
+
         if (!mInitialized || !Intent.ACTION_MAIN.equals(action)) {
             return;
         }
 
         // Check to see how many times the app has been launched.
         final String keyName = getPackageName() + ".feedback_launch_count";
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
 
@@ -3856,17 +3853,17 @@ public class BrowserApp extends GeckoApp
                     GeckoAppShell.notifyObservers("Feedback:Show", null);
                 }
             }
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
     }
 
-    private void openUrls(List<String> urls) {
+    public void openUrls(List<String> urls) {
         try {
             JSONArray array = new JSONArray();
             for (String url : urls) {
                 array.put(url);
             }
 
             JSONObject object = new JSONObject();
             object.put("urls", array);
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/feeds/ContentNotificationsDelegate.java
@@ -0,0 +1,62 @@
+/* -*- 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.feeds;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.BrowserApp;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
+
+import java.util.List;
+
+/**
+ * BrowserAppDelegate implementation that takes care of handling intents from content notifications.
+ */
+public class ContentNotificationsDelegate {
+    // The application is opened from a content notification
+    public static final String ACTION_CONTENT_NOTIFICATION = AppConstants.ANDROID_PACKAGE_NAME + ".action.CONTENT_NOTIFICATION";
+
+    public static final String EXTRA_URLS = "urls";
+
+    private static final String TELEMETRY_EXTRA_CONTENT_UPDATE = "content_update";
+
+    public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
+        final Intent intent = browserApp.getIntent();
+
+        if (savedInstanceState != null) {
+            // This activity is getting restored: We do not want to handle the URLs in the Intent again. The browser
+            // will take care of restoring the tabs we already created.
+            return;
+        }
+
+        if (intent != null && ACTION_CONTENT_NOTIFICATION.equals(intent.getAction())) {
+            openURLsFromIntent(browserApp, intent);
+        }
+    }
+
+    public void onNewIntent(BrowserApp browserApp, Intent intent) {
+        if (intent != null && ACTION_CONTENT_NOTIFICATION.equals(intent.getAction())) {
+            openURLsFromIntent(browserApp, intent);
+        }
+    }
+
+    private void openURLsFromIntent(BrowserApp browserApp, final Intent intent) {
+        final List<String> urls = intent.getStringArrayListExtra(EXTRA_URLS);
+        if (urls != null) {
+            browserApp.openUrls(urls);
+        }
+
+        Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(browserApp));
+
+        Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.NOTIFICATION, TELEMETRY_EXTRA_CONTENT_UPDATE);
+        Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, TELEMETRY_EXTRA_CONTENT_UPDATE);
+
+        Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(browserApp));
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/CheckForUpdatesAction.java
+++ b/mobile/android/base/java/org/mozilla/gecko/feeds/action/CheckForUpdatesAction.java
@@ -23,16 +23,17 @@ import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.UrlAnnotations;
+import org.mozilla.gecko.feeds.ContentNotificationsDelegate;
 import org.mozilla.gecko.feeds.FeedFetcher;
 import org.mozilla.gecko.feeds.FeedService;
 import org.mozilla.gecko.feeds.parser.Feed;
 import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.util.StringUtils;
 
 import java.util.ArrayList;
@@ -43,18 +44,16 @@ import java.util.List;
  * CheckForUpdatesAction: Check if feeds we subscribed to have new content available.
  */
 public class CheckForUpdatesAction extends FeedAction {
     /**
      * This extra will be added to Intents fired by the notification.
      */
     public static final String EXTRA_CONTENT_NOTIFICATION = "content-notification";
 
-    private static final String LOGTAG = "FeedCheckAction";
-
     private Context context;
 
     public CheckForUpdatesAction(Context context) {
         this.context = context;
     }
 
     @Override
     public void perform(BrowserDB browserDB, Intent intent) {
@@ -158,76 +157,82 @@ public class CheckForUpdatesAction exten
         Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
         Telemetry.sendUIEvent(TelemetryContract.Event.SHOW, TelemetryContract.Method.NOTIFICATION, "content_update");
         Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
     }
 
     private void showNotificationForSingleUpdate(Feed feed) {
         final String date = DateFormat.getMediumDateFormat(context).format(new Date(feed.getLastItem().getTimestamp()));
 
-        NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle()
+        final NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle()
                 .bigText(feed.getLastItem().getTitle())
                 .setBigContentTitle(feed.getTitle())
                 .setSummaryText(context.getString(R.string.content_notification_updated_on, date));
 
-        Intent intent = new Intent(Intent.ACTION_VIEW);
-        intent.setComponent(new ComponentName(context, BrowserApp.class));
-        intent.setData(Uri.parse(feed.getLastItem().getURL()));
-        intent.putExtra(EXTRA_CONTENT_NOTIFICATION, true);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, createOpenIntent(feed), PendingIntent.FLAG_UPDATE_CURRENT);
 
-        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
-
-        Notification notification = new NotificationCompat.Builder(context)
+        final Notification notification = new NotificationCompat.Builder(context)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setContentTitle(feed.getTitle())
                 .setContentText(feed.getLastItem().getTitle())
                 .setStyle(style)
                 .setColor(ContextCompat.getColor(context, R.color.fennec_ui_orange))
                 .setContentIntent(pendingIntent)
                 .setAutoCancel(true)
                 .addAction(createNotificationSettingsAction())
                 .build();
 
         NotificationManagerCompat.from(context).notify(R.id.websiteContentNotification, notification);
     }
 
     private void showNotificationForMultipleUpdates(List<Feed> feeds) {
-        final ArrayList<String> urls = new ArrayList<>();
-
         final NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
         for (Feed feed : feeds) {
-            final String url = feed.getLastItem().getURL();
-
-            inboxStyle.addLine(StringUtils.stripScheme(url, StringUtils.UrlFlags.STRIP_HTTPS));
-            urls.add(url);
+            inboxStyle.addLine(StringUtils.stripScheme(feed.getLastItem().getURL(), StringUtils.UrlFlags.STRIP_HTTPS));
         }
         inboxStyle.setSummaryText(context.getString(R.string.content_notification_summary));
 
-        Intent intent = new Intent(context, BrowserApp.class);
-        intent.setAction(BrowserApp.ACTION_VIEW_MULTIPLE);
-        intent.putStringArrayListExtra("urls", urls);
-        intent.putExtra(EXTRA_CONTENT_NOTIFICATION, true);
-
-        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+        final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, createOpenIntent(feeds), PendingIntent.FLAG_UPDATE_CURRENT);
 
         Notification notification = new NotificationCompat.Builder(context)
                 .setSmallIcon(R.drawable.ic_status_logo)
                 .setContentTitle(context.getString(R.string.content_notification_title_plural, feeds.size()))
                 .setContentText(context.getString(R.string.content_notification_summary))
                 .setStyle(inboxStyle)
                 .setColor(ContextCompat.getColor(context, R.color.fennec_ui_orange))
                 .setContentIntent(pendingIntent)
                 .setAutoCancel(true)
                 .setNumber(feeds.size())
                 .addAction(createNotificationSettingsAction())
                 .build();
 
         NotificationManagerCompat.from(context).notify(R.id.websiteContentNotification, notification);
     }
 
+    private Intent createOpenIntent(Feed feed) {
+        final List<Feed> feeds = new ArrayList<>();
+        feeds.add(feed);
+
+        return createOpenIntent(feeds);
+    }
+
+    private Intent createOpenIntent(List<Feed> feeds) {
+        final ArrayList<String> urls = new ArrayList<>();
+        for (Feed feed : feeds) {
+            urls.add(feed.getLastItem().getURL());
+        }
+
+        final Intent intent = new Intent(context, BrowserApp.class);
+        intent.setAction(ContentNotificationsDelegate.ACTION_CONTENT_NOTIFICATION);
+        intent.putStringArrayListExtra(ContentNotificationsDelegate.EXTRA_URLS, urls);
+
+        return intent;
+    }
+
+
     private NotificationCompat.Action createNotificationSettingsAction() {
         final Intent intent = new Intent(GeckoApp.ACTION_LAUNCH_SETTINGS);
         intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
         intent.putExtra(EXTRA_CONTENT_NOTIFICATION, true);
 
         GeckoPreferences.setResourceToOpen(intent, "preferences_notifications");
 
         PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -278,16 +278,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'favicons/OnFaviconLoadedListener.java',
     'favicons/RemoteFavicon.java',
     'feeds/action/CheckForUpdatesAction.java',
     'feeds/action/EnrollSubscriptionsAction.java',
     'feeds/action/FeedAction.java',
     'feeds/action/SetupAlarmsAction.java',
     'feeds/action/SubscribeToFeedAction.java',
     'feeds/action/WithdrawSubscriptionsAction.java',
+    'feeds/ContentNotificationsDelegate.java',
     'feeds/FeedAlarmReceiver.java',
     'feeds/FeedFetcher.java',
     'feeds/FeedService.java',
     'feeds/knownsites/KnownSite.java',
     'feeds/knownsites/KnownSiteBlogger.java',
     'feeds/knownsites/KnownSiteMedium.java',
     'feeds/knownsites/KnownSiteTumblr.java',
     'feeds/knownsites/KnownSiteWordpress.java',