--- a/mobile/android/app/src/main/res/values/ids.xml
+++ b/mobile/android/app/src/main/res/values/ids.xml
@@ -12,15 +12,14 @@
<item type="id" name="menu_items"/>
<item type="id" name="menu_margin"/>
<item type="id" name="recycler_view_click_support" />
<item type="id" name="range_list"/>
<item type="id" name="pref_header_general"/>
<item type="id" name="pref_header_privacy"/>
<item type="id" name="pref_header_search"/>
<item type="id" name="updateServicePermissionNotification" />
- <item type="id" name="websiteContentNotification" />
<item type="id" name="foregroundNotification" />
<item type="id" name="actionbar"/>
<item type="id" name="action_button"/>
<item type="id" name="page_progress"/>
<item type="id" name="mediaControlNotification"/>
</resources>
--- a/mobile/android/app/src/main/res/xml/preferences_notifications.xml
+++ b/mobile/android/app/src/main/res/xml/preferences_notifications.xml
@@ -1,16 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
- <SwitchPreference android:key="android.not_a_preference.notifications.content"
- android:title="@string/pref_content_notifications"
- android:summary="@string/pref_content_notifications_summary"
- android:defaultValue="true" />
- <org.mozilla.gecko.preferences.AlignRightLinkPreference
- android:key="android.not_a_preference.notifications.content.learn_more"
- android:title="@string/pref_learn_more"
- android:persistent="false"
- url="https://support.mozilla.org/kb/notifications-firefox-android?utm_source=inproduct&utm_medium=notifications&utm_campaign=mobileandroid" />
<SwitchPreference android:key="android.not_a_preference.notifications.whats_new"
android:title="@string/pref_whats_new_notification"
android:summary="@string/pref_whats_new_notification_summary"
android:defaultValue="true" />
</PreferenceScreen>
\ No newline at end of file
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -381,40 +381,27 @@
android:name="org.mozilla.gecko.notifications.NotificationService">
</service>
<service
android:exported="false"
android:name="org.mozilla.gecko.dlc.DownloadContentService">
</service>
- <service
- android:exported="false"
- android:name="org.mozilla.gecko.feeds.FeedService">
- </service>
-
<!-- DON'T EXPORT THIS, please! An attacker could delete arbitrary files. -->
<service
android:exported="false"
android:name="org.mozilla.gecko.cleanup.FileCleanupService">
</service>
<receiver
android:name="org.mozilla.gecko.feeds.FeedAlarmReceiver"
android:exported="false" />
<receiver
- android:name="org.mozilla.gecko.BootReceiver"
- android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"></action>
- </intent-filter>
- </receiver>
-
- <receiver
android:name="org.mozilla.gecko.PackageReplacedReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"></action>
</intent-filter>
</receiver>
<service
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/BootReceiver.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- 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.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-import org.mozilla.gecko.feeds.FeedService;
-
-/**
- * This broadcast receiver receives ACTION_BOOT_COMPLETED broadcasts and starts components that should
- * run after the device has booted.
- */
-public class BootReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null || !intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
- return; // This is not the broadcast you are looking for.
- }
-
- FeedService.setup(context);
- }
-}
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -2,128 +2,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;
import android.Manifest;
import android.annotation.TargetApi;
-import android.app.DownloadManager;
-import android.content.ContentProviderClient;
-import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
-
-import org.mozilla.gecko.activitystream.ActivityStream;
-import org.mozilla.gecko.adjust.AdjustBrowserAppDelegate;
-import org.mozilla.gecko.annotation.RobocopTarget;
-import org.mozilla.gecko.AppConstants.Versions;
-import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
-import org.mozilla.gecko.Tabs.TabEvents;
-import org.mozilla.gecko.animation.PropertyAnimator;
-import org.mozilla.gecko.bookmarks.BookmarkEditFragment;
-import org.mozilla.gecko.bookmarks.BookmarkUtils;
-import org.mozilla.gecko.bookmarks.EditBookmarkTask;
-import org.mozilla.gecko.cleanup.FileCleanupController;
-import org.mozilla.gecko.dawn.DawnHelper;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.SuggestedSites;
-import org.mozilla.gecko.delegates.BrowserAppDelegate;
-import org.mozilla.gecko.delegates.OfflineTabStatusDelegate;
-import org.mozilla.gecko.delegates.ScreenshotDelegate;
-import org.mozilla.gecko.distribution.Distribution;
-import org.mozilla.gecko.distribution.DistributionStoreCallback;
-import org.mozilla.gecko.dlc.DownloadContentService;
-import org.mozilla.gecko.icons.IconsHelper;
-import org.mozilla.gecko.icons.decoders.IconDirectoryEntry;
-import org.mozilla.gecko.icons.decoders.FaviconDecoder;
-import org.mozilla.gecko.icons.decoders.LoadFaviconResult;
-import org.mozilla.gecko.feeds.ContentNotificationsDelegate;
-import org.mozilla.gecko.feeds.FeedService;
-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.home.BrowserSearch;
-import org.mozilla.gecko.home.HomeBanner;
-import org.mozilla.gecko.home.HomeConfig;
-import org.mozilla.gecko.home.HomeConfig.PanelType;
-import org.mozilla.gecko.home.HomeConfigPrefsBackend;
-import org.mozilla.gecko.home.HomeFragment;
-import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
-import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
-import org.mozilla.gecko.home.HomePanelsManager;
-import org.mozilla.gecko.home.HomeScreen;
-import org.mozilla.gecko.home.SearchEngine;
-import org.mozilla.gecko.icons.Icons;
-import org.mozilla.gecko.media.VideoPlayer;
-import org.mozilla.gecko.menu.GeckoMenu;
-import org.mozilla.gecko.menu.GeckoMenuItem;
-import org.mozilla.gecko.mma.MmaDelegate;
-import org.mozilla.gecko.mozglue.GeckoLoader;
-import org.mozilla.gecko.mozglue.SafeIntent;
-import org.mozilla.gecko.notifications.NotificationHelper;
-import org.mozilla.gecko.overlays.ui.ShareDialog;
-import org.mozilla.gecko.permissions.Permissions;
-import org.mozilla.gecko.preferences.ClearOnShutdownPref;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-import org.mozilla.gecko.promotion.AddToHomeScreenPromotion;
-import org.mozilla.gecko.delegates.BookmarkStateChangeDelegate;
-import org.mozilla.gecko.promotion.ReaderViewBookmarkPromotion;
-import org.mozilla.gecko.prompts.Prompt;
-import org.mozilla.gecko.reader.SavedReaderViewHelper;
-import org.mozilla.gecko.reader.ReaderModeUtils;
-import org.mozilla.gecko.reader.ReadingListHelper;
-import org.mozilla.gecko.restrictions.Restrictable;
-import org.mozilla.gecko.restrictions.Restrictions;
-import org.mozilla.gecko.search.SearchEngineManager;
-import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
-import org.mozilla.gecko.tabqueue.TabQueueHelper;
-import org.mozilla.gecko.tabqueue.TabQueuePrompt;
-import org.mozilla.gecko.tabs.TabHistoryController;
-import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
-import org.mozilla.gecko.tabs.TabHistoryFragment;
-import org.mozilla.gecko.tabs.TabHistoryPage;
-import org.mozilla.gecko.tabs.TabsPanel;
-import org.mozilla.gecko.telemetry.TelemetryUploadService;
-import org.mozilla.gecko.telemetry.TelemetryCorePingDelegate;
-import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
-import org.mozilla.gecko.toolbar.AutocompleteHandler;
-import org.mozilla.gecko.toolbar.BrowserToolbar;
-import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
-import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
-import org.mozilla.gecko.updater.PostUpdateHandler;
-import org.mozilla.gecko.updater.UpdateServiceHelper;
-import org.mozilla.gecko.util.ActivityUtils;
-import org.mozilla.gecko.util.Clipboard;
-import org.mozilla.gecko.util.ContextUtils;
-import org.mozilla.gecko.util.DrawableUtil;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.GeckoBundle;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.IntentUtils;
-import org.mozilla.gecko.util.MenuUtils;
-import org.mozilla.gecko.util.PrefUtils;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.WindowUtil;
-import org.mozilla.gecko.widget.ActionModePresenter;
-import org.mozilla.gecko.widget.AnchoredPopup;
-import org.mozilla.gecko.widget.AnimatedProgressBar;
-import org.mozilla.gecko.widget.GeckoActionProvider;
-
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.DownloadManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -134,17 +29,21 @@ import android.graphics.drawable.BitmapD
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.StrictMode;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.MenuItemCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -162,27 +61,125 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ViewFlipper;
+
+import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.DynamicToolbar.VisibilityTransition;
+import org.mozilla.gecko.Tabs.TabEvents;
+import org.mozilla.gecko.activitystream.ActivityStream;
+import org.mozilla.gecko.adjust.AdjustBrowserAppDelegate;
+import org.mozilla.gecko.animation.PropertyAnimator;
+import org.mozilla.gecko.annotation.RobocopTarget;
+import org.mozilla.gecko.bookmarks.BookmarkEditFragment;
+import org.mozilla.gecko.bookmarks.BookmarkUtils;
+import org.mozilla.gecko.bookmarks.EditBookmarkTask;
+import org.mozilla.gecko.cleanup.FileCleanupController;
+import org.mozilla.gecko.dawn.DawnHelper;
+import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.db.BrowserDB;
+import org.mozilla.gecko.db.SuggestedSites;
+import org.mozilla.gecko.delegates.BookmarkStateChangeDelegate;
+import org.mozilla.gecko.delegates.BrowserAppDelegate;
+import org.mozilla.gecko.delegates.OfflineTabStatusDelegate;
+import org.mozilla.gecko.delegates.ScreenshotDelegate;
+import org.mozilla.gecko.distribution.Distribution;
+import org.mozilla.gecko.distribution.DistributionStoreCallback;
+import org.mozilla.gecko.dlc.DownloadContentService;
+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.home.BrowserSearch;
+import org.mozilla.gecko.home.HomeBanner;
+import org.mozilla.gecko.home.HomeConfig;
+import org.mozilla.gecko.home.HomeConfig.PanelType;
+import org.mozilla.gecko.home.HomeConfigPrefsBackend;
+import org.mozilla.gecko.home.HomeFragment;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenInBackgroundListener;
+import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+import org.mozilla.gecko.home.HomePanelsManager;
+import org.mozilla.gecko.home.HomeScreen;
+import org.mozilla.gecko.home.SearchEngine;
+import org.mozilla.gecko.icons.Icons;
+import org.mozilla.gecko.icons.IconsHelper;
+import org.mozilla.gecko.icons.decoders.FaviconDecoder;
+import org.mozilla.gecko.icons.decoders.IconDirectoryEntry;
+import org.mozilla.gecko.icons.decoders.LoadFaviconResult;
+import org.mozilla.gecko.media.VideoPlayer;
+import org.mozilla.gecko.menu.GeckoMenu;
+import org.mozilla.gecko.menu.GeckoMenuItem;
+import org.mozilla.gecko.mma.MmaDelegate;
+import org.mozilla.gecko.mozglue.GeckoLoader;
+import org.mozilla.gecko.mozglue.SafeIntent;
+import org.mozilla.gecko.notifications.NotificationHelper;
+import org.mozilla.gecko.overlays.ui.ShareDialog;
+import org.mozilla.gecko.permissions.Permissions;
+import org.mozilla.gecko.preferences.ClearOnShutdownPref;
+import org.mozilla.gecko.preferences.GeckoPreferences;
+import org.mozilla.gecko.promotion.AddToHomeScreenPromotion;
+import org.mozilla.gecko.promotion.ReaderViewBookmarkPromotion;
+import org.mozilla.gecko.prompts.Prompt;
+import org.mozilla.gecko.reader.ReaderModeUtils;
+import org.mozilla.gecko.reader.ReadingListHelper;
+import org.mozilla.gecko.reader.SavedReaderViewHelper;
+import org.mozilla.gecko.restrictions.Restrictable;
+import org.mozilla.gecko.restrictions.Restrictions;
+import org.mozilla.gecko.search.SearchEngineManager;
import org.mozilla.gecko.switchboard.AsyncConfigLoader;
import org.mozilla.gecko.switchboard.SwitchBoard;
+import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
+import org.mozilla.gecko.tabqueue.TabQueueHelper;
+import org.mozilla.gecko.tabqueue.TabQueuePrompt;
+import org.mozilla.gecko.tabs.TabHistoryController;
+import org.mozilla.gecko.tabs.TabHistoryController.OnShowTabHistory;
+import org.mozilla.gecko.tabs.TabHistoryFragment;
+import org.mozilla.gecko.tabs.TabHistoryPage;
+import org.mozilla.gecko.tabs.TabsPanel;
+import org.mozilla.gecko.telemetry.TelemetryCorePingDelegate;
+import org.mozilla.gecko.telemetry.TelemetryUploadService;
+import org.mozilla.gecko.telemetry.measurements.SearchCountMeasurements;
+import org.mozilla.gecko.toolbar.AutocompleteHandler;
+import org.mozilla.gecko.toolbar.BrowserToolbar;
+import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
+import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
+import org.mozilla.gecko.updater.PostUpdateHandler;
+import org.mozilla.gecko.updater.UpdateServiceHelper;
+import org.mozilla.gecko.util.ActivityUtils;
+import org.mozilla.gecko.util.Clipboard;
+import org.mozilla.gecko.util.ContextUtils;
+import org.mozilla.gecko.util.DrawableUtil;
+import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.GamepadUtils;
+import org.mozilla.gecko.util.GeckoBundle;
+import org.mozilla.gecko.util.HardwareUtils;
+import org.mozilla.gecko.util.IntentUtils;
+import org.mozilla.gecko.util.MenuUtils;
+import org.mozilla.gecko.util.PrefUtils;
+import org.mozilla.gecko.util.StringUtils;
+import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.util.WindowUtil;
+import org.mozilla.gecko.widget.ActionModePresenter;
+import org.mozilla.gecko.widget.AnchoredPopup;
+import org.mozilla.gecko.widget.AnimatedProgressBar;
+import org.mozilla.gecko.widget.GeckoActionProvider;
import org.mozilla.gecko.widget.SplashScreen;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import static org.mozilla.gecko.mma.MmaDelegate.NEW_TAB;
@@ -333,17 +330,16 @@ public class BrowserApp extends GeckoApp
private final TelemetryCorePingDelegate mTelemetryCorePingDelegate = new TelemetryCorePingDelegate();
private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
new AddToHomeScreenPromotion(),
new ScreenshotDelegate(),
new BookmarkStateChangeDelegate(),
new ReaderViewBookmarkPromotion(),
- new ContentNotificationsDelegate(),
new PostUpdateHandler(),
mTelemetryCorePingDelegate,
new OfflineTabStatusDelegate(),
new AdjustBrowserAppDelegate(mTelemetryCorePingDelegate)
));
@NonNull
private SearchEngineManager mSearchEngineManager; // Contains reference to Context - DO NOT LEAK!
@@ -1814,17 +1810,16 @@ public class BrowserApp extends GeckoApp
if (AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE &&
!IntentUtils.getIsInAutomationFromEnvironment(new SafeIntent(getIntent()))) {
// TODO: Better scheduling of DLC actions (Bug 1257492)
DownloadContentService.startSync(this);
DownloadContentService.startVerification(this);
}
- FeedService.setup(this);
break;
case "Accessibility:Enabled":
mDynamicToolbar.setAccessibilityEnabled(message.getBoolean("enabled"));
break;
case "Menu:Open":
if (mBrowserToolbar.isEditing()) {
--- a/mobile/android/base/java/org/mozilla/gecko/Experiments.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Experiments.java
@@ -20,21 +20,16 @@ import java.util.List;
* https://github.com/mozilla-services/switchboard-experiments
*/
public class Experiments {
private static final String LOGTAG = "GeckoExperiments";
// Show a system notification linking to a "What's New" page on app update.
public static final String WHATSNEW_NOTIFICATION = "whatsnew-notification";
- // Subscribe to known, bookmarked sites and show a notification if new content is available.
- public static final String CONTENT_NOTIFICATIONS_12HRS = "content-notifications-12hrs";
- public static final String CONTENT_NOTIFICATIONS_8AM = "content-notifications-8am";
- public static final String CONTENT_NOTIFICATIONS_5PM = "content-notifications-5pm";
-
// Onboarding: "Features and Story". These experiments are determined
// on the client, they are not part of the server config.
public static final String ONBOARDING3_A = "onboarding3-a"; // Control: No first run
public static final String ONBOARDING3_B = "onboarding3-b"; // 4 static Feature + 1 dynamic slides
public static final String ONBOARDING3_C = "onboarding3-c"; // Differentiating features slides
// Synchronizing the catalog of downloadable content from Kinto
public static final String DOWNLOAD_CONTENT_CATALOG_SYNC = "download-content-catalog-sync";
--- a/mobile/android/base/java/org/mozilla/gecko/db/LocalUrlAnnotations.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/LocalUrlAnnotations.java
@@ -5,22 +5,19 @@
package org.mozilla.gecko.db;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.util.Log;
-import org.json.JSONException;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.db.BrowserContract.UrlAnnotations.Key;
-import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
public class LocalUrlAnnotations implements UrlAnnotations {
private static final String LOGTAG = "LocalUrlAnnotations";
private Uri urlAnnotationsTableWithProfile;
public LocalUrlAnnotations(final String profile) {
urlAnnotationsTableWithProfile = DBUtils.appendProfile(profile, BrowserContract.UrlAnnotations.CONTENT_URI);
@@ -92,75 +89,22 @@ public class LocalUrlAnnotations impleme
public Cursor getWebsitesWithFeedUrl(ContentResolver cr) {
return cr.query(urlAnnotationsTableWithProfile,
new String[] { BrowserContract.UrlAnnotations.URL },
BrowserContract.UrlAnnotations.KEY + " = ?",
new String[] { Key.FEED.getDbValue() },
null);
}
- /**
- * Returns true if there's a subscription for this feed URL. False otherwise.
- */
- @Override
- public boolean hasFeedSubscription(ContentResolver cr, String feedUrl) {
- return hasResultsForSelection(cr,
- BrowserContract.UrlAnnotations.URL + " = ? AND " + BrowserContract.UrlAnnotations.KEY + " = ?",
- new String[]{feedUrl, Key.FEED_SUBSCRIPTION.getDbValue()});
- }
-
- /**
- * Insert the given feed subscription (Mapping from feed URL to the subscription object).
- */
- @Override
- public void insertFeedSubscription(ContentResolver cr, FeedSubscription subscription) {
- try {
- insertAnnotation(cr, subscription.getFeedUrl(), Key.FEED_SUBSCRIPTION, subscription.toJSON().toString());
- } catch (JSONException e) {
- Log.w(LOGTAG, "Could not serialize subscription");
- }
- }
-
- /**
- * Update the feed subscription with new values.
- */
- @Override
- public void updateFeedSubscription(ContentResolver cr, FeedSubscription subscription) {
- try {
- updateAnnotation(cr, subscription.getFeedUrl(), Key.FEED_SUBSCRIPTION, subscription.toJSON().toString());
- } catch (JSONException e) {
- Log.w(LOGTAG, "Could not serialize subscription");
- }
- }
-
- /**
- * Delete the subscription for the feed URL.
- */
- @Override
- public void deleteFeedSubscription(ContentResolver cr, FeedSubscription subscription) {
- deleteAnnotation(cr, subscription.getFeedUrl(), Key.FEED_SUBSCRIPTION);
- }
-
private int deleteAnnotation(final ContentResolver cr, final String url, final Key key) {
return cr.delete(urlAnnotationsTableWithProfile,
BrowserContract.UrlAnnotations.KEY + " = ? AND " + BrowserContract.UrlAnnotations.URL + " = ?",
new String[] { key.getDbValue(), url });
}
- private int updateAnnotation(final ContentResolver cr, final String url, final Key key, final String value) {
- ContentValues values = new ContentValues();
- values.put(BrowserContract.UrlAnnotations.VALUE, value);
- values.put(BrowserContract.UrlAnnotations.DATE_MODIFIED, System.currentTimeMillis());
-
- return cr.update(urlAnnotationsTableWithProfile,
- values,
- BrowserContract.UrlAnnotations.KEY + " = ? AND " + BrowserContract.UrlAnnotations.URL + " = ?",
- new String[]{key.getDbValue(), url});
- }
-
private void insertAnnotation(final ContentResolver cr, final String url, final Key key, final String value) {
insertAnnotation(cr, url, key.getDbValue(), value);
}
@RobocopTarget
@Override
public void insertAnnotation(final ContentResolver cr, final String url, final String key, final String value) {
final long creationTime = System.currentTimeMillis();
--- a/mobile/android/base/java/org/mozilla/gecko/db/UrlAnnotations.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/UrlAnnotations.java
@@ -1,33 +1,29 @@
/* 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.db;
import android.content.ContentResolver;
import android.database.Cursor;
+
import org.mozilla.gecko.annotation.RobocopTarget;
-import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
public interface UrlAnnotations {
@RobocopTarget void insertAnnotation(ContentResolver cr, String url, String key, String value);
Cursor getScreenshots(ContentResolver cr);
void insertScreenshot(ContentResolver cr, String pageUrl, String screenshotPath);
Cursor getFeedSubscriptions(ContentResolver cr);
Cursor getWebsitesWithFeedUrl(ContentResolver cr);
void deleteFeedUrl(ContentResolver cr, String websiteUrl);
boolean hasWebsiteForFeedUrl(ContentResolver cr, String feedUrl);
- void deleteFeedSubscription(ContentResolver cr, FeedSubscription subscription);
- void updateFeedSubscription(ContentResolver cr, FeedSubscription subscription);
- boolean hasFeedSubscription(ContentResolver cr, String feedUrl);
- void insertFeedSubscription(ContentResolver cr, FeedSubscription subscription);
boolean hasFeedUrlForWebsite(ContentResolver cr, String websiteUrl);
void insertFeedUrl(ContentResolver cr, String originUrl, String feedUrl);
void insertReaderViewUrl(ContentResolver cr, String pageURL);
void deleteReaderViewUrl(ContentResolver cr, String pageURL);
/**
* Did the user ever interact with this URL in regards to home screen shortcuts?
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/ContentNotificationsDelegate.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- 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 android.support.annotation.NonNull;
-import android.support.v4.app.NotificationManagerCompat;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.BrowserApp;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.delegates.BrowserAppDelegate;
-import org.mozilla.gecko.mozglue.SafeIntent;
-
-import java.util.List;
-
-/**
- * BrowserAppDelegate implementation that takes care of handling intents from content notifications.
- */
-public class ContentNotificationsDelegate extends BrowserAppDelegate {
- // 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_READ_BUTTON = "read_button";
- public static final String EXTRA_URLS = "urls";
-
- private static final String TELEMETRY_EXTRA_CONTENT_UPDATE = "content_update";
- private static final String TELEMETRY_EXTRA_READ_NOW_BUTTON = TELEMETRY_EXTRA_CONTENT_UPDATE + "_read_now";
-
- @Override
- public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
- 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;
- }
-
-
- final Intent unsafeIntent = browserApp.getIntent();
-
- // Nothing to do.
- if (unsafeIntent == null) {
- return;
- }
-
- final SafeIntent intent = new SafeIntent(unsafeIntent);
-
- if (ACTION_CONTENT_NOTIFICATION.equals(intent.getAction())) {
- openURLsFromIntent(browserApp, intent);
- }
- }
-
- @Override
- public void onNewIntent(BrowserApp browserApp, @NonNull final SafeIntent intent) {
- if (ACTION_CONTENT_NOTIFICATION.equals(intent.getAction())) {
- openURLsFromIntent(browserApp, intent);
- }
- }
-
- private void openURLsFromIntent(BrowserApp browserApp, @NonNull final SafeIntent 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.LOAD_URL, TelemetryContract.Method.INTENT, TELEMETRY_EXTRA_CONTENT_UPDATE);
-
- if (intent.getBooleanExtra(EXTRA_READ_BUTTON, false)) {
- // "READ NOW" button in notification was clicked
- Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.NOTIFICATION, TELEMETRY_EXTRA_READ_NOW_BUTTON);
-
- // Android's "auto cancel" won't remove the notification when an action button is pressed. So we do it ourselves here.
- NotificationManagerCompat.from(browserApp).cancel(R.id.websiteContentNotification);
- } else {
- // Notification was clicked
- Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.NOTIFICATION, TELEMETRY_EXTRA_CONTENT_UPDATE);
- }
-
- Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(browserApp));
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/FeedAlarmReceiver.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- 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.Context;
-import android.content.Intent;
-import android.support.v4.content.WakefulBroadcastReceiver;
-import android.util.Log;
-
-/**
- * Broadcast receiver that will receive broadcasts from the AlarmManager and start the FeedService
- * with the given action.
- */
-public class FeedAlarmReceiver extends WakefulBroadcastReceiver {
- private static final String LOGTAG = "FeedCheckAction";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
-
- Log.d(LOGTAG, "Received alarm with action: " + action);
-
- final Intent serviceIntent = new Intent(context, FeedService.class);
- serviceIntent.setAction(action);
-
- startWakefulService(context, serviceIntent);
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/FeedFetcher.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/* -*- 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.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import org.mozilla.gecko.feeds.parser.Feed;
-import org.mozilla.gecko.feeds.parser.SimpleFeedParser;
-import org.mozilla.gecko.util.IOUtils;
-import org.mozilla.gecko.util.ProxySelector;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import ch.boye.httpclientandroidlib.util.TextUtils;
-
-/**
- * Helper class for fetching and parsing a feed.
- */
-public class FeedFetcher {
- private static final int CONNECT_TIMEOUT = 15000;
- private static final int READ_TIMEOUT = 15000;
-
- public static class FeedResponse {
- public final Feed feed;
- public final String etag;
- public final String lastModified;
-
- public FeedResponse(Feed feed, String etag, String lastModified) {
- this.feed = feed;
- this.etag = etag;
- this.lastModified = lastModified;
- }
- }
-
- /**
- * Fetch and parse a feed from the given URL. Will return null if fetching or parsing failed.
- */
- public static FeedResponse fetchAndParseFeed(String url) {
- return fetchAndParseFeedIfModified(url, null, null);
- }
-
- /**
- * Fetch and parse a feed from the given URL using the given ETag and "Last modified" value.
- *
- * Will return null if fetching or parsing failed. Will also return null if the feed has not
- * changed (ETag / Last-Modified-Since).
- *
- * @param eTag The ETag from the last fetch or null if no ETag is available (will always fetch feed)
- * @param lastModified The "Last modified" header from the last time the feed has been fetch or
- * null if no value is available (will always fetch feed)
- * @return A FeedResponse or null if no feed could be fetched (error or no new version available)
- */
- @Nullable
- public static FeedResponse fetchAndParseFeedIfModified(@NonNull String url, @Nullable String eTag, @Nullable String lastModified) {
- HttpURLConnection connection = null;
- InputStream stream = null;
-
- try {
- connection = (HttpURLConnection) ProxySelector.openConnectionWithProxy(new URI(url));
- connection.setInstanceFollowRedirects(true);
- connection.setConnectTimeout(CONNECT_TIMEOUT);
- connection.setReadTimeout(READ_TIMEOUT);
-
- if (!TextUtils.isEmpty(eTag)) {
- connection.setRequestProperty("If-None-Match", eTag);
- }
-
- if (!TextUtils.isEmpty(lastModified)) {
- connection.setRequestProperty("If-Modified-Since", lastModified);
- }
-
- final int statusCode = connection.getResponseCode();
-
- if (statusCode != HttpURLConnection.HTTP_OK) {
- return null;
- }
-
- String responseEtag = connection.getHeaderField("ETag");
- if (!TextUtils.isEmpty(responseEtag) && responseEtag.startsWith("W/")) {
- // Weak ETag, get actual ETag value
- responseEtag = responseEtag.substring(2);
- }
-
- final String updatedLastModified = connection.getHeaderField("Last-Modified");
-
- stream = new BufferedInputStream(connection.getInputStream());
-
- final SimpleFeedParser parser = new SimpleFeedParser();
- final Feed feed = parser.parse(stream);
-
- return new FeedResponse(feed, responseEtag, updatedLastModified);
- } catch (IOException e) {
- return null;
- } catch (SimpleFeedParser.ParserException e) {
- return null;
- } catch (URISyntaxException e) {
- return null;
- } finally {
- if (connection != null) {
- connection.disconnect();
- }
- IOUtils.safeStreamClose(stream);
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/FeedService.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/* -*- 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.app.IntentService;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.support.annotation.Nullable;
-import android.support.v4.net.ConnectivityManagerCompat;
-import android.util.Log;
-
-import org.mozilla.gecko.switchboard.SwitchBoard;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.feeds.action.FeedAction;
-import org.mozilla.gecko.feeds.action.CheckForUpdatesAction;
-import org.mozilla.gecko.feeds.action.EnrollSubscriptionsAction;
-import org.mozilla.gecko.feeds.action.SetupAlarmsAction;
-import org.mozilla.gecko.feeds.action.SubscribeToFeedAction;
-import org.mozilla.gecko.feeds.action.WithdrawSubscriptionsAction;
-import org.mozilla.gecko.preferences.GeckoPreferences;
-import org.mozilla.gecko.Experiments;
-
-/**
- * Background service for subscribing to and checking website feeds to notify the user about updates.
- */
-public class FeedService extends IntentService {
- private static final String LOGTAG = "GeckoFeedService";
-
- public static final String ACTION_SETUP = AppConstants.ANDROID_PACKAGE_NAME + ".FEEDS.SETUP";
- public static final String ACTION_SUBSCRIBE = AppConstants.ANDROID_PACKAGE_NAME + ".FEEDS.SUBSCRIBE";
- public static final String ACTION_CHECK = AppConstants.ANDROID_PACKAGE_NAME + ".FEEDS.CHECK";
- public static final String ACTION_ENROLL = AppConstants.ANDROID_PACKAGE_NAME + ".FEEDS.ENROLL";
- public static final String ACTION_WITHDRAW = AppConstants.ANDROID_PACKAGE_NAME + ".FEEDS.WITHDRAW";
-
- public static void setup(Context context) {
- Intent intent = new Intent(context, FeedService.class);
- intent.setAction(ACTION_SETUP);
- context.startService(intent);
- }
-
- public static void subscribe(Context context, String feedUrl) {
- Intent intent = new Intent(context, FeedService.class);
- intent.setAction(ACTION_SUBSCRIBE);
- intent.putExtra(SubscribeToFeedAction.EXTRA_FEED_URL, feedUrl);
- context.startService(intent);
- }
-
- public FeedService() {
- super(LOGTAG);
- }
-
- private BrowserDB browserDB;
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- browserDB = BrowserDB.from(this);
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- try {
- if (intent == null) {
- return;
- }
-
- Log.d(LOGTAG, "Service started with action: " + intent.getAction());
-
- if (!isInExperiment(this)) {
- Log.d(LOGTAG, "Not in content notifications experiment. Skipping.");
- return;
- }
-
- FeedAction action = createActionForIntent(intent);
- if (action == null) {
- Log.d(LOGTAG, "No action to process");
- return;
- }
-
- if (action.requiresPreferenceEnabled() && !isPreferenceEnabled()) {
- Log.d(LOGTAG, "Preference is disabled. Skipping.");
- return;
- }
-
- if (action.requiresNetwork() && !isConnectedToUnmeteredNetwork()) {
- // For now just skip if we are not connected or the network is metered. We do not want
- // to use precious mobile traffic.
- Log.d(LOGTAG, "Not connected to a network or network is metered. Skipping.");
- return;
- }
-
- action.perform(browserDB, intent);
- } finally {
- FeedAlarmReceiver.completeWakefulIntent(intent);
- }
-
- Log.d(LOGTAG, "Done.");
- }
-
- @Nullable
- private FeedAction createActionForIntent(Intent intent) {
- final Context context = getApplicationContext();
-
- switch (intent.getAction()) {
- case ACTION_SETUP:
- return new SetupAlarmsAction(context);
-
- case ACTION_SUBSCRIBE:
- return new SubscribeToFeedAction(context);
-
- case ACTION_CHECK:
- return new CheckForUpdatesAction(context);
-
- case ACTION_ENROLL:
- return new EnrollSubscriptionsAction(context);
-
- case ACTION_WITHDRAW:
- return new WithdrawSubscriptionsAction(context);
-
- default:
- throw new AssertionError("Unknown action: " + intent.getAction());
- }
- }
-
- private boolean isConnectedToUnmeteredNetwork() {
- ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo networkInfo = manager.getActiveNetworkInfo();
- if (networkInfo == null || !networkInfo.isConnected()) {
- return false;
- }
-
- return !ConnectivityManagerCompat.isActiveNetworkMetered(manager);
- }
-
- public static boolean isInExperiment(Context context) {
- return SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_12HRS) ||
- SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_5PM) ||
- SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_8AM);
- }
-
- public static String getEnabledExperiment(Context context) {
- String experiment = null;
-
- if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_12HRS)) {
- experiment = Experiments.CONTENT_NOTIFICATIONS_12HRS;
- } else if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_8AM)) {
- experiment = Experiments.CONTENT_NOTIFICATIONS_8AM;
- } else if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_5PM)) {
- experiment = Experiments.CONTENT_NOTIFICATIONS_5PM;
- }
-
- return experiment;
- }
-
- private boolean isPreferenceEnabled() {
- return GeckoSharedPrefs.forApp(this).getBoolean(GeckoPreferences.PREFS_NOTIFICATIONS_CONTENT, true);
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/CheckForUpdatesAction.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/* -*- 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.action;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
-import android.support.v4.content.ContextCompat;
-import android.text.format.DateFormat;
-
-import org.json.JSONException;
-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;
-import java.util.Date;
-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 final Context context;
-
- public CheckForUpdatesAction(Context context) {
- this.context = context;
- }
-
- @Override
- public void perform(BrowserDB browserDB, Intent intent) {
- final UrlAnnotations urlAnnotations = browserDB.getUrlAnnotations();
- final ContentResolver resolver = context.getContentResolver();
- final List<Feed> updatedFeeds = new ArrayList<>();
-
- log("Checking feeds for updates..");
-
- Cursor cursor = urlAnnotations.getFeedSubscriptions(resolver);
- if (cursor == null) {
- return;
- }
-
- try {
- while (cursor.moveToNext()) {
- FeedSubscription subscription = FeedSubscription.fromCursor(cursor);
-
- FeedFetcher.FeedResponse response = checkFeedForUpdates(subscription);
- if (response != null) {
- final Feed feed = response.feed;
-
- if (!hasBeenVisited(browserDB, feed.getLastItem().getURL())) {
- // Only notify about this update if the last item hasn't been visited yet.
- updatedFeeds.add(feed);
- } else {
- Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- Telemetry.sendUIEvent(TelemetryContract.Event.CANCEL,
- TelemetryContract.Method.SERVICE,
- "content_update");
- Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- }
-
- urlAnnotations.updateFeedSubscription(resolver, subscription);
- }
- }
- } catch (JSONException e) {
- log("Could not deserialize subscription", e);
- } finally {
- cursor.close();
- }
-
- showNotification(updatedFeeds);
- }
-
- private FeedFetcher.FeedResponse checkFeedForUpdates(FeedSubscription subscription) {
- log("Checking feed: " + subscription.getFeedTitle());
-
- FeedFetcher.FeedResponse response = fetchFeed(subscription);
- if (response == null) {
- return null;
- }
-
- if (subscription.hasBeenUpdated(response)) {
- log("* Feed has changed. New item: " + response.feed.getLastItem().getTitle());
-
- subscription.update(response);
-
- return response;
-
- }
-
- return null;
- }
-
- /**
- * Returns true if this URL has been visited before.
- *
- * We do an exact match. So this can fail if the feed uses a different URL and redirects to
- * content. But it's better than no checks at all.
- */
- private boolean hasBeenVisited(final BrowserDB browserDB, final String url) {
- final Cursor cursor = browserDB.getHistoryForURL(context.getContentResolver(), url);
- if (cursor == null) {
- return false;
- }
-
- try {
- if (cursor.moveToFirst()) {
- return cursor.getInt(cursor.getColumnIndex(BrowserContract.History.VISITS)) > 0;
- }
- } finally {
- cursor.close();
- }
-
- return false;
- }
-
- private void showNotification(List<Feed> updatedFeeds) {
- final int feedCount = updatedFeeds.size();
- if (feedCount == 0) {
- return;
- }
-
- if (feedCount == 1) {
- showNotificationForSingleUpdate(updatedFeeds.get(0));
- } else {
- showNotificationForMultipleUpdates(updatedFeeds);
- }
-
- 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()));
-
- final NotificationCompat.BigTextStyle style = new NotificationCompat.BigTextStyle()
- .bigText(feed.getLastItem().getTitle())
- .setBigContentTitle(feed.getTitle())
- .setSummaryText(context.getString(R.string.content_notification_updated_on, date));
-
- final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, createOpenIntent(feed), PendingIntent.FLAG_UPDATE_CURRENT);
-
- 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_accent))
- .setContentIntent(pendingIntent)
- .setAutoCancel(true)
- .addAction(createOpenAction(feed))
- .addAction(createNotificationSettingsAction())
- .build();
-
- NotificationManagerCompat.from(context).notify(R.id.websiteContentNotification, notification);
- }
-
- private void showNotificationForMultipleUpdates(List<Feed> feeds) {
- final NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
- for (Feed feed : feeds) {
- inboxStyle.addLine(StringUtils.stripScheme(feed.getLastItem().getURL(), StringUtils.UrlFlags.STRIP_HTTPS));
- }
- inboxStyle.setSummaryText(context.getString(R.string.content_notification_summary));
-
- 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_accent))
- .setContentIntent(pendingIntent)
- .setAutoCancel(true)
- .addAction(createOpenAction(feeds))
- .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 createOpenAction(Feed feed) {
- final List<Feed> feeds = new ArrayList<>();
- feeds.add(feed);
-
- return createOpenAction(feeds);
- }
-
- private NotificationCompat.Action createOpenAction(List<Feed> feeds) {
- Intent intent = createOpenIntent(feeds);
- intent.putExtra(ContentNotificationsDelegate.EXTRA_READ_BUTTON, true);
-
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- return new NotificationCompat.Action(
- R.drawable.open_in_browser,
- context.getString(R.string.content_notification_action_read_now),
- pendingIntent);
- }
-
- 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);
-
- return new NotificationCompat.Action(
- R.drawable.settings_notifications,
- context.getString(R.string.content_notification_action_settings),
- settingsIntent);
- }
-
- private FeedFetcher.FeedResponse fetchFeed(FeedSubscription subscription) {
- return FeedFetcher.fetchAndParseFeedIfModified(
- subscription.getFeedUrl(),
- subscription.getETag(),
- subscription.getLastModified()
- );
- }
-
- @Override
- public boolean requiresNetwork() {
- return true;
- }
-
- @Override
- public boolean requiresPreferenceEnabled() {
- return true;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/EnrollSubscriptionsAction.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- 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.action;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.text.TextUtils;
-
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.UrlAnnotations;
-import org.mozilla.gecko.feeds.FeedService;
-import org.mozilla.gecko.feeds.knownsites.KnownSiteBlogger;
-import org.mozilla.gecko.feeds.knownsites.KnownSite;
-import org.mozilla.gecko.feeds.knownsites.KnownSiteMedium;
-import org.mozilla.gecko.feeds.knownsites.KnownSiteTumblr;
-import org.mozilla.gecko.feeds.knownsites.KnownSiteWordpress;
-
-/**
- * EnrollSubscriptionsAction: Search for bookmarks of known sites we can subscribe to.
- */
-public class EnrollSubscriptionsAction extends FeedAction {
- private static final String LOGTAG = "FeedEnrollAction";
-
- private static final KnownSite[] knownSites = {
- new KnownSiteMedium(),
- new KnownSiteBlogger(),
- new KnownSiteWordpress(),
- new KnownSiteTumblr(),
- };
-
- private Context context;
-
- public EnrollSubscriptionsAction(Context context) {
- this.context = context;
- }
-
- @Override
- public void perform(BrowserDB db, Intent intent) {
- log("Searching for bookmarks to enroll in updates");
-
- final ContentResolver contentResolver = context.getContentResolver();
-
- for (KnownSite knownSite : knownSites) {
- searchFor(db, contentResolver, knownSite);
- }
- }
-
- @Override
- public boolean requiresNetwork() {
- return false;
- }
-
- @Override
- public boolean requiresPreferenceEnabled() {
- return true;
- }
-
- private void searchFor(BrowserDB db, ContentResolver contentResolver, KnownSite knownSite) {
- final UrlAnnotations urlAnnotations = db.getUrlAnnotations();
-
- final Cursor cursor = db.getBookmarksForPartialUrl(contentResolver, knownSite.getURLSearchString());
- if (cursor == null) {
- log("Nothing found (" + knownSite.getClass().getSimpleName() + ")");
- return;
- }
-
- try {
- log("Found " + cursor.getCount() + " websites");
-
- while (cursor.moveToNext()) {
-
- final String url = cursor.getString(cursor.getColumnIndex(BrowserContract.Bookmarks.URL));
-
- log(" URL: " + url);
-
- String feedUrl = knownSite.getFeedFromURL(url);
- if (TextUtils.isEmpty(feedUrl)) {
- log("Could not determine feed for URL: " + url);
- return;
- }
-
- if (!urlAnnotations.hasFeedUrlForWebsite(contentResolver, url)) {
- urlAnnotations.insertFeedUrl(contentResolver, url, feedUrl);
- }
-
- if (!urlAnnotations.hasFeedSubscription(contentResolver, feedUrl)) {
- FeedService.subscribe(context, feedUrl);
- }
- }
- } finally {
- cursor.close();
- }
- }
-
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/FeedAction.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- 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.action;
-
-import android.content.Intent;
-import android.util.Log;
-
-import org.mozilla.gecko.db.BrowserDB;
-
-/**
- * Interface for actions run by FeedService.
- */
-public abstract class FeedAction {
- public static final boolean DEBUG_LOG = false;
-
- /**
- * Perform this action.
- *
- * @param browserDB database instance to perform the action.
- * @param intent used to start the service.
- */
- public abstract void perform(BrowserDB browserDB, Intent intent);
-
- /**
- * Does this action require an active network connection?
- */
- public abstract boolean requiresNetwork();
-
- /**
- * Should this action only run if the preference is enabled?
- */
- public abstract boolean requiresPreferenceEnabled();
-
- /**
- * This method will swallow all log messages to avoid logging potential personal information.
- *
- * For debugging purposes set {@code DEBUG_LOG} to true.
- */
- public void log(String message) {
- if (DEBUG_LOG) {
- Log.d("Gecko" + getClass().getSimpleName(), message);
- }
- }
-
- /**
- * This method will swallow all log messages to avoid logging potential personal information.
- *
- * For debugging purposes set {@code DEBUG_LOG} to true.
- */
- public void log(String message, Throwable throwable) {
- if (DEBUG_LOG) {
- Log.d("Gecko" + getClass().getSimpleName(), message, throwable);
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/SetupAlarmsAction.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/* -*- 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.action;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-
-import org.mozilla.gecko.switchboard.SwitchBoard;
-
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.feeds.FeedAlarmReceiver;
-import org.mozilla.gecko.feeds.FeedService;
-import org.mozilla.gecko.Experiments;
-
-import java.text.DateFormat;
-import java.util.Calendar;
-
-/**
- * SetupAlarmsAction: Set up alarms to run various actions every now and then.
- */
-public class SetupAlarmsAction extends FeedAction {
- private static final String LOGTAG = "FeedSetupAction";
-
- private Context context;
-
- public SetupAlarmsAction(Context context) {
- this.context = context;
- }
-
- @Override
- public void perform(BrowserDB browserDB, Intent intent) {
- final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-
- cancelPreviousAlarms(alarmManager);
- scheduleAlarms(alarmManager);
- }
-
- @Override
- public boolean requiresNetwork() {
- return false;
- }
-
- @Override
- public boolean requiresPreferenceEnabled() {
- return false;
- }
-
- private void cancelPreviousAlarms(AlarmManager alarmManager) {
- final PendingIntent withdrawIntent = getWithdrawPendingIntent();
- alarmManager.cancel(withdrawIntent);
-
- final PendingIntent enrollIntent = getEnrollPendingIntent();
- alarmManager.cancel(enrollIntent);
-
- final PendingIntent checkIntent = getCheckPendingIntent();
- alarmManager.cancel(checkIntent);
-
- log("Cancelled previous alarms");
- }
-
- private void scheduleAlarms(AlarmManager alarmManager) {
- alarmManager.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_FIFTEEN_MINUTES,
- AlarmManager.INTERVAL_DAY,
- getWithdrawPendingIntent());
-
- alarmManager.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
- AlarmManager.INTERVAL_DAY,
- getEnrollPendingIntent()
- );
-
- if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_12HRS)) {
- scheduleUpdateCheckEvery12Hours(alarmManager);
- }
-
- if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_8AM)) {
- scheduleUpdateAtFullHour(alarmManager, 8);
- }
-
- if (SwitchBoard.isInExperiment(context, Experiments.CONTENT_NOTIFICATIONS_5PM)) {
- scheduleUpdateAtFullHour(alarmManager, 17);
- }
-
-
- log("Scheduled alarms");
- }
-
- private void scheduleUpdateCheckEvery12Hours(AlarmManager alarmManager) {
- alarmManager.setInexactRepeating(
- AlarmManager.ELAPSED_REALTIME,
- SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HOUR,
- AlarmManager.INTERVAL_HALF_DAY,
- getCheckPendingIntent()
- );
- }
-
- private void scheduleUpdateAtFullHour(AlarmManager alarmManager, int hourOfDay) {
- final Calendar calendar = Calendar.getInstance();
-
- if (calendar.get(Calendar.HOUR_OF_DAY) >= hourOfDay) {
- // This time has already passed today. Try again tomorrow.
- calendar.add(Calendar.DAY_OF_MONTH, 1);
- }
-
- calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
- calendar.set(Calendar.MINUTE, 0);
- calendar.set(Calendar.SECOND, 0);
- calendar.set(Calendar.MILLISECOND, 0);
-
- alarmManager.setInexactRepeating(
- AlarmManager.RTC,
- calendar.getTimeInMillis(),
- AlarmManager.INTERVAL_DAY,
- getCheckPendingIntent()
- );
-
- log("Scheduled update alarm at " + DateFormat.getDateTimeInstance().format(calendar.getTime()));
- }
-
- private PendingIntent getWithdrawPendingIntent() {
- Intent intent = new Intent(context, FeedAlarmReceiver.class);
- intent.setAction(FeedService.ACTION_WITHDRAW);
- return PendingIntent.getBroadcast(context, 0, intent, 0);
- }
-
- private PendingIntent getEnrollPendingIntent() {
- Intent intent = new Intent(context, FeedAlarmReceiver.class);
- intent.setAction(FeedService.ACTION_ENROLL);
- return PendingIntent.getBroadcast(context, 0, intent, 0);
- }
-
- private PendingIntent getCheckPendingIntent() {
- Intent intent = new Intent(context, FeedAlarmReceiver.class);
- intent.setAction(FeedService.ACTION_CHECK);
- return PendingIntent.getBroadcast(context, 0, intent, 0);
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/SubscribeToFeedAction.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- 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.action;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.UrlAnnotations;
-import org.mozilla.gecko.feeds.FeedFetcher;
-import org.mozilla.gecko.feeds.FeedService;
-import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
-
-/**
- * SubscribeToFeedAction: Try to fetch a feed and create a subscription if successful.
- */
-public class SubscribeToFeedAction extends FeedAction {
- private static final String LOGTAG = "FeedSubscribeAction";
-
- public static final String EXTRA_FEED_URL = "feed_url";
-
- private Context context;
-
- public SubscribeToFeedAction(Context context) {
- this.context = context;
- }
-
- @Override
- public void perform(BrowserDB browserDB, Intent intent) {
- final UrlAnnotations urlAnnotations = browserDB.getUrlAnnotations();
-
- final Bundle extras = intent.getExtras();
- final String feedUrl = extras.getString(EXTRA_FEED_URL);
-
- if (urlAnnotations.hasFeedSubscription(context.getContentResolver(), feedUrl)) {
- log("Already subscribed to " + feedUrl + ". Skipping.");
- return;
- }
-
- log("Subscribing to feed: " + feedUrl);
-
- subscribe(urlAnnotations, feedUrl);
- }
-
- @Override
- public boolean requiresNetwork() {
- return true;
- }
-
- @Override
- public boolean requiresPreferenceEnabled() {
- return true;
- }
-
- private void subscribe(UrlAnnotations urlAnnotations, String feedUrl) {
- FeedFetcher.FeedResponse response = FeedFetcher.fetchAndParseFeed(feedUrl);
- if (response == null) {
- log(String.format("Could not fetch feed (%s). Not subscribing for now.", feedUrl));
- return;
- }
-
- log("Subscribing to feed: " + response.feed.getTitle());
- log(" Last item: " + response.feed.getLastItem().getTitle());
-
- final FeedSubscription subscription = FeedSubscription.create(feedUrl, response);
-
- urlAnnotations.insertFeedSubscription(context.getContentResolver(), subscription);
-
- Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.SERVICE, "content_update");
- Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/action/WithdrawSubscriptionsAction.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- 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.action;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-
-import org.json.JSONException;
-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.FeedService;
-import org.mozilla.gecko.feeds.subscriptions.FeedSubscription;
-
-/**
- * WithdrawSubscriptionsAction: Look for feeds to unsubscribe from.
- */
-public class WithdrawSubscriptionsAction extends FeedAction {
- private static final String LOGTAG = "FeedWithdrawAction";
-
- private Context context;
-
- public WithdrawSubscriptionsAction(Context context) {
- this.context = context;
- }
-
- @Override
- public void perform(BrowserDB browserDB, Intent intent) {
- log("Searching for subscriptions to remove..");
-
- final UrlAnnotations urlAnnotations = browserDB.getUrlAnnotations();
- final ContentResolver resolver = context.getContentResolver();
-
- removeFeedsOfUnknownUrls(browserDB, urlAnnotations, resolver);
- removeSubscriptionsOfRemovedFeeds(urlAnnotations, resolver);
- }
-
- /**
- * Search for website URLs with a feed assigned. Remove entry if website URL is not known anymore:
- * For now this means the website is not bookmarked.
- */
- private void removeFeedsOfUnknownUrls(BrowserDB browserDB, UrlAnnotations urlAnnotations, ContentResolver resolver) {
- Cursor cursor = urlAnnotations.getWebsitesWithFeedUrl(resolver);
- if (cursor == null) {
- return;
- }
-
- try {
- while (cursor.moveToNext()) {
- final String url = cursor.getString(cursor.getColumnIndex(BrowserContract.UrlAnnotations.URL));
-
- if (!browserDB.isBookmark(resolver, url)) {
- log("Removing feed for unknown URL: " + url);
-
- urlAnnotations.deleteFeedUrl(resolver, url);
- }
- }
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Remove subscriptions of feed URLs that are not assigned to a website URL (anymore).
- */
- private void removeSubscriptionsOfRemovedFeeds(UrlAnnotations urlAnnotations, ContentResolver resolver) {
- Cursor cursor = urlAnnotations.getFeedSubscriptions(resolver);
- if (cursor == null) {
- return;
- }
-
- try {
- while (cursor.moveToNext()) {
- final FeedSubscription subscription = FeedSubscription.fromCursor(cursor);
-
- if (!urlAnnotations.hasWebsiteForFeedUrl(resolver, subscription.getFeedUrl())) {
- log("Removing subscription for feed: " + subscription.getFeedUrl());
-
- urlAnnotations.deleteFeedSubscription(resolver, subscription);
-
- Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.SERVICE, "content_update");
- Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(context));
- }
- }
- } catch (JSONException e) {
- log("Could not deserialize subscription", e);
- } finally {
- cursor.close();
- }
- }
-
- @Override
- public boolean requiresNetwork() {
- return false;
- }
-
- @Override
- public boolean requiresPreferenceEnabled() {
- return true;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/knownsites/KnownSite.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- 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.knownsites;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-/**
- * A site we know and for which we can guess the feed URL from an arbitrary URL.
- */
-public interface KnownSite {
- /**
- * Get a search string to find URLs of this site in our database. This search string is usually
- * a partial domain / URL.
- *
- * For example we could return "medium.com" to find all URLs that contain this string. This could
- * obviously find URLs that are not actually medium.com sites. This is acceptable as long as
- * getFeedFromURL() can handle these inputs and either returns a feed for valid URLs or null for
- * other matches that are not related to this site.
- */
- @NonNull String getURLSearchString();
-
- /**
- * Get the Feed URL for this URL. For a known site we can "guess" the feed URL from an URL
- * pointing to any page. The input URL will be a result from the database found with the value
- * returned by getURLSearchString().
- *
- * Example:
- * - Input: https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8
- * - Output: https://medium.com/feed/@antlam
- *
- * @return the url representing a feed, or null if a feed could not be determined.
- */
- @Nullable String getFeedFromURL(String url);
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/knownsites/KnownSiteBlogger.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- 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.knownsites;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Blogger.com
- */
-public class KnownSiteBlogger implements KnownSite {
- @Override
- public String getURLSearchString() {
- return ".blogspot.com";
- }
-
- @Override
- public String getFeedFromURL(String url) {
- Pattern pattern = Pattern.compile("https?://(www\\.)?(.*?)\\.blogspot\\.com(/.*)?");
- Matcher matcher = pattern.matcher(url);
- if (matcher.matches()) {
- return String.format("https://%s.blogspot.com/feeds/posts/default", matcher.group(2));
- }
- return null;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/knownsites/KnownSiteMedium.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- 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.knownsites;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Medium.com
- */
-public class KnownSiteMedium implements KnownSite {
- @Override
- public String getURLSearchString() {
- return "://medium.com/";
- }
-
- @Override
- public String getFeedFromURL(String url) {
- Pattern pattern = Pattern.compile("https?://medium.com/([^/]+)(/.*)?");
- Matcher matcher = pattern.matcher(url);
- if (matcher.matches()) {
- return String.format("https://medium.com/feed/%s", matcher.group(1));
- }
- return null;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/knownsites/KnownSiteTumblr.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- 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.knownsites;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Tumblr.com
- */
-public class KnownSiteTumblr implements KnownSite {
- @Override
- public String getURLSearchString() {
- return ".tumblr.com";
- }
-
- @Override
- public String getFeedFromURL(String url) {
- final Pattern pattern = Pattern.compile("https?://(.*?).tumblr.com(/.*)?");
- final Matcher matcher = pattern.matcher(url);
- if (matcher.matches()) {
- final String username = matcher.group(1);
- if (username.equals("www")) {
- return null;
- }
- return "http://" + username + ".tumblr.com/rss";
- }
- return null;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/knownsites/KnownSiteWordpress.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.mozilla.gecko.feeds.knownsites;
-
-import android.support.annotation.NonNull;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Wordpress.com
- */
-public class KnownSiteWordpress implements KnownSite {
- @Override
- public String getURLSearchString() {
- return ".wordpress.com";
- }
-
- @Override
- public String getFeedFromURL(String url) {
- Pattern pattern = Pattern.compile("https?://(.*?).wordpress.com(/.*)?");
- Matcher matcher = pattern.matcher(url);
- if (matcher.matches()) {
- return "https://" + matcher.group(1) + ".wordpress.com/feed/";
- }
- return null;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/parser/Feed.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- 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.parser;
-
-import ch.boye.httpclientandroidlib.util.TextUtils;
-
-public class Feed {
- private String title;
- private String websiteURL;
- private String feedURL;
- private Item lastItem;
-
- public static Feed create(String title, String websiteURL, String feedURL, Item lastItem) {
- Feed feed = new Feed();
-
- feed.setTitle(title);
- feed.setWebsiteURL(websiteURL);
- feed.setFeedURL(feedURL);
- feed.setLastItem(lastItem);
-
- return feed;
- }
-
- /* package-private */ Feed() {}
-
- /* package-private */ void setTitle(String title) {
- this.title = title;
- }
-
- /* package-private */ void setWebsiteURL(String websiteURL) {
- this.websiteURL = websiteURL;
- }
-
- /* package-private */ void setFeedURL(String feedURL) {
- this.feedURL = feedURL;
- }
-
- /* package-private */ void setLastItem(Item lastItem) {
- this.lastItem = lastItem;
- }
-
- /**
- * Is this feed object sufficiently complete so that we can use it?
- */
- /* package-private */ boolean isSufficientlyComplete() {
- return !TextUtils.isEmpty(title) &&
- lastItem != null &&
- !TextUtils.isEmpty(lastItem.getURL()) &&
- !TextUtils.isEmpty(lastItem.getTitle());
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getWebsiteURL() {
- return websiteURL;
- }
-
- public String getFeedURL() {
- return feedURL;
- }
-
- public Item getLastItem() {
- return lastItem;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/parser/Item.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- 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.parser;
-
-public class Item {
- private String title;
- private String url;
- private long timestamp;
-
- public static Item create(String title, String url, long timestamp) {
- Item item = new Item();
-
- item.setTitle(title);
- item.setURL(url);
- item.setTimestamp(timestamp);
-
- return item;
- }
-
- /* package-private */ void setTitle(String title) {
- this.title = title;
- }
-
- /* package-private */ void setURL(String url) {
- this.url = url;
- }
-
- /* package-private */ void setTimestamp(long timestamp) {
- this.timestamp = timestamp;
- }
-
- public String getTitle() {
- return title;
- }
-
- public String getURL() {
- return url;
- }
-
- /**
- * @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
- */
- public long getTimestamp() {
- return timestamp;
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/parser/SimpleFeedParser.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/* -*- 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.parser;
-
-import android.util.Log;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import ch.boye.httpclientandroidlib.util.TextUtils;
-
-/**
- * A super simple feed parser written for implementing "content notifications". This XML Pull Parser
- * can read ATOM and RSS feeds and returns an object describing the feed and the latest entry.
- */
-public class SimpleFeedParser {
- /**
- * Generic exception that's thrown by the parser whenever a stream cannot be parsed.
- */
- public static class ParserException extends Exception {
- private static final long serialVersionUID = -6119538440219805603L;
-
- public ParserException(Throwable cause) {
- super(cause);
- }
-
- public ParserException(String message) {
- super(message);
- }
- }
-
- private static final String LOGTAG = "Gecko/FeedParser";
-
- private static final String TAG_RSS = "rss";
- private static final String TAG_FEED = "feed";
- private static final String TAG_RDF = "RDF";
- private static final String TAG_TITLE = "title";
- private static final String TAG_ITEM = "item";
- private static final String TAG_LINK = "link";
- private static final String TAG_ENTRY = "entry";
- private static final String TAG_PUBDATE = "pubDate";
- private static final String TAG_UPDATED = "updated";
- private static final String TAG_DATE = "date";
- private static final String TAG_SOURCE = "source";
- private static final String TAG_IMAGE = "image";
- private static final String TAG_CONTENT = "content";
-
- private class ParserState {
- public Feed feed;
- public Item currentItem;
- public boolean isRSS;
- public boolean isATOM;
- public boolean inSource;
- public boolean inImage;
- public boolean inContent;
- }
-
- public Feed parse(InputStream in) throws ParserException, IOException {
- final ParserState state = new ParserState();
-
- try {
- final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- factory.setNamespaceAware(true);
-
- XmlPullParser parser = factory.newPullParser();
- parser.setInput(in, null);
-
- int eventType = parser.getEventType();
-
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case XmlPullParser.START_DOCUMENT:
- handleStartDocument(state);
- break;
-
- case XmlPullParser.START_TAG:
- handleStartTag(parser, state);
- break;
-
- case XmlPullParser.END_TAG:
- handleEndTag(parser, state);
- break;
- }
-
- eventType = parser.next();
- }
- } catch (XmlPullParserException e) {
- throw new ParserException(e);
- }
-
- if (!state.feed.isSufficientlyComplete()) {
- throw new ParserException("Feed is not sufficiently complete");
- }
-
- return state.feed;
- }
-
- private void handleStartDocument(ParserState state) {
- state.feed = new Feed();
- }
-
- private void handleStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- switch (parser.getName()) {
- case TAG_RSS:
- state.isRSS = true;
- break;
-
- case TAG_FEED:
- state.isATOM = true;
- break;
-
- case TAG_RDF:
- // This is a RSS 1.0 feed
- state.isRSS = true;
- break;
-
- case TAG_ITEM:
- case TAG_ENTRY:
- state.currentItem = new Item();
- break;
-
- case TAG_TITLE:
- handleTitleStartTag(parser, state);
- break;
-
- case TAG_LINK:
- handleLinkStartTag(parser, state);
- break;
-
- case TAG_PUBDATE:
- handlePubDateStartTag(parser, state);
- break;
-
- case TAG_UPDATED:
- handleUpdatedStartTag(parser, state);
- break;
-
- case TAG_DATE:
- handleDateStartTag(parser, state);
- break;
-
- case TAG_SOURCE:
- state.inSource = true;
- break;
-
- case TAG_IMAGE:
- state.inImage = true;
- break;
-
- case TAG_CONTENT:
- state.inContent = true;
- break;
- }
- }
-
- private void handleEndTag(XmlPullParser parser, ParserState state) {
- switch (parser.getName()) {
- case TAG_ITEM:
- case TAG_ENTRY:
- handleItemOrEntryREndTag(state);
- break;
-
- case TAG_SOURCE:
- state.inSource = false;
- break;
-
- case TAG_IMAGE:
- state.inImage = false;
- break;
-
- case TAG_CONTENT:
- state.inContent = false;
- break;
- }
- }
-
- private void handleTitleStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- if (state.inSource || state.inImage || state.inContent) {
- // We do not care about titles in <source>, <image> or <media> tags.
- return;
- }
-
- String title = getTextUntilEndTag(parser, TAG_TITLE);
-
- title = title.replaceAll("[\r\n]", " ");
- title = title.replaceAll(" +", " ");
-
- if (state.currentItem != null) {
- state.currentItem.setTitle(title);
- } else {
- state.feed.setTitle(title);
- }
- }
-
- private void handleLinkStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- if (state.inSource || state.inImage) {
- // We do not care about links in <source> or <image> tags.
- return;
- }
-
- Map<String, String> attributes = fetchAttributes(parser);
-
- if (attributes.size() > 0) {
- String rel = attributes.get("rel");
-
- if (state.currentItem == null && "self".equals(rel)) {
- state.feed.setFeedURL(attributes.get("href"));
- return;
- }
-
- if (rel == null || "alternate".equals(rel)) {
- String type = attributes.get("type");
- if (type == null || type.equals("text/html")) {
- String link = attributes.get("href");
- if (TextUtils.isEmpty(link)) {
- return;
- }
-
- if (state.currentItem != null) {
- state.currentItem.setURL(link);
- } else {
- state.feed.setWebsiteURL(link);
- }
-
- return;
- }
- }
- }
-
- if (state.isRSS) {
- String link = getTextUntilEndTag(parser, TAG_LINK);
- if (TextUtils.isEmpty(link)) {
- return;
- }
-
- if (state.currentItem != null) {
- state.currentItem.setURL(link);
- } else {
- state.feed.setWebsiteURL(link);
- }
- }
- }
-
- private void handleItemOrEntryREndTag(ParserState state) {
- if (state.feed.getLastItem() == null || state.feed.getLastItem().getTimestamp() < state.currentItem.getTimestamp()) {
- // Only set this item as "last item" if we do not have an item yet or this item is newer.
- state.feed.setLastItem(state.currentItem);
- }
-
- state.currentItem = null;
- }
-
- private void handlePubDateStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- if (state.currentItem == null) {
- return;
- }
-
- String pubDate = getTextUntilEndTag(parser, TAG_PUBDATE);
- if (TextUtils.isEmpty(pubDate)) {
- return;
- }
-
- // RFC-822
- SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
-
- updateCurrentItemTimestamp(state, pubDate, format);
- }
-
- private void handleUpdatedStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- if (state.inSource) {
- // We do not care about stuff in <source> tags.
- return;
- }
-
- if (state.currentItem == null) {
- // We are only interested in <updated> values of feed items.
- return;
- }
-
- String updated = getTextUntilEndTag(parser, TAG_UPDATED);
- if (TextUtils.isEmpty(updated)) {
- return;
- }
-
- SimpleDateFormat[] formats = new SimpleDateFormat[] {
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US),
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US)
- };
-
- // Fix timezones SimpleDateFormat can't parse:
- // 2016-01-26T18:56:54Z -> 2016-01-26T18:56:54+0000 (Timezone: Z -> +0000)
- updated = updated.replaceFirst("Z$", "+0000");
- // 2016-01-26T18:56:54+01:00 -> 2016-01-26T18:56:54+0100 (Timezone: +01:00 -> +0100)
- updated = updated.replaceFirst("([0-9]{2})([\\+\\-])([0-9]{2}):([0-9]{2})$", "$1$2$3$4");
-
- updateCurrentItemTimestamp(state, updated, formats);
- }
-
- private void handleDateStartTag(XmlPullParser parser, ParserState state) throws IOException, XmlPullParserException {
- if (state.currentItem == null) {
- // We are only interested in <updated> values of feed items.
- return;
- }
-
- String text = getTextUntilEndTag(parser, TAG_DATE);
- if (TextUtils.isEmpty(text)) {
- return;
- }
-
- // Fix timezones SimpleDateFormat can't parse:
- // 2016-01-26T18:56:54+00:00 -> 2016-01-26T18:56:54+0000
- text = text.replaceFirst("([0-9]{2})([\\+\\-])([0-9]{2}):([0-9]{2})$", "$1$2$3$4");
-
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
-
- updateCurrentItemTimestamp(state, text, format);
- }
-
- private void updateCurrentItemTimestamp(ParserState state, String text, SimpleDateFormat... formats) {
- for (SimpleDateFormat format : formats) {
- try {
- Date date = format.parse(text);
- state.currentItem.setTimestamp(date.getTime());
- return;
- } catch (ParseException e) {
- Log.w(LOGTAG, "Could not parse 'updated': " + text);
- }
- }
- }
-
- private Map<String, String> fetchAttributes(XmlPullParser parser) {
- Map<String, String> attributes = new HashMap<>();
-
- for (int i = 0; i < parser.getAttributeCount(); i++) {
- attributes.put(parser.getAttributeName(i), parser.getAttributeValue(i));
- }
-
- return attributes;
- }
-
- private String getTextUntilEndTag(XmlPullParser parser, String tag) throws IOException, XmlPullParserException {
- StringBuilder builder = new StringBuilder();
-
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- if (parser.getEventType() == XmlPullParser.TEXT) {
- builder.append(parser.getText());
- } else if (parser.getEventType() == XmlPullParser.END_TAG && tag.equals(parser.getName())) {
- break;
- }
- }
-
- return builder.toString().trim();
- }
-}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/feeds/subscriptions/FeedSubscription.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- 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.subscriptions;
-
-import android.database.Cursor;
-import android.text.TextUtils;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.feeds.FeedFetcher;
-import org.mozilla.gecko.feeds.parser.Item;
-
-/**
- * An object describing a subscription and containing some meta data about the last time we fetched
- * the feed.
- */
-public class FeedSubscription {
- private static final String JSON_KEY_FEED_TITLE = "feed_title";
- private static final String JSON_KEY_LAST_ITEM_TITLE = "last_item_title";
- private static final String JSON_KEY_LAST_ITEM_URL = "last_item_url";
- private static final String JSON_KEY_LAST_ITEM_TIMESTAMP = "last_item_timestamp";
- private static final String JSON_KEY_ETAG = "etag";
- private static final String JSON_KEY_LAST_MODIFIED = "last_modified";
-
- private String feedUrl;
- private String feedTitle;
- private String lastItemTitle;
- private String lastItemUrl;
- private long lastItemTimestamp;
- private String etag;
- private String lastModified;
-
- public static FeedSubscription create(String feedUrl, FeedFetcher.FeedResponse response) {
- FeedSubscription subscription = new FeedSubscription();
- subscription.feedUrl = feedUrl;
-
- subscription.update(response);
-
- return subscription;
- }
-
- public static FeedSubscription fromCursor(Cursor cursor) throws JSONException {
- final FeedSubscription subscription = new FeedSubscription();
- subscription.feedUrl = cursor.getString(cursor.getColumnIndex(BrowserContract.UrlAnnotations.URL));
-
- final String value = cursor.getString(cursor.getColumnIndex(BrowserContract.UrlAnnotations.VALUE));
- subscription.fromJSON(new JSONObject(value));
-
- return subscription;
- }
-
- private void fromJSON(JSONObject object) throws JSONException {
- feedTitle = object.getString(JSON_KEY_FEED_TITLE);
- lastItemTitle = object.getString(JSON_KEY_LAST_ITEM_TITLE);
- lastItemUrl = object.getString(JSON_KEY_LAST_ITEM_URL);
- lastItemTimestamp = object.getLong(JSON_KEY_LAST_ITEM_TIMESTAMP);
- etag = object.optString(JSON_KEY_ETAG);
- lastModified = object.optString(JSON_KEY_LAST_MODIFIED);
- }
-
- public void update(FeedFetcher.FeedResponse response) {
- feedTitle = response.feed.getTitle();
- lastItemTitle = response.feed.getLastItem().getTitle();
- lastItemUrl = response.feed.getLastItem().getURL();
- lastItemTimestamp = response.feed.getLastItem().getTimestamp();
- etag = response.etag;
- lastModified = response.lastModified;
- }
-
- /**
- * Guesstimate if this response is a newer representation of the feed.
- */
- public boolean hasBeenUpdated(FeedFetcher.FeedResponse response) {
- final Item responseItem = response.feed.getLastItem();
-
- if (responseItem.getTimestamp() > lastItemTimestamp) {
- // The timestamp is from a newer date so we expect that this item is a new item. But this
- // could also mean that the timestamp of an already existing item has been updated. We
- // accept that and assume that the content will have changed too in this case.
- return true;
- }
-
- if (responseItem.getTimestamp() == lastItemTimestamp && responseItem.getTimestamp() != 0) {
- // We have a timestamp that is not zero and this item has still the timestamp: It's very
- // likely that we are looking at the same item. We assume this is not new content.
- return false;
- }
-
- if (!responseItem.getURL().equals(lastItemUrl)) {
- // The URL changed: It is very likely that this is a new item. At least it has been updated
- // in a way that we just treat it as new content here.
- return true;
- }
-
- return false;
- }
-
- public String getFeedUrl() {
- return feedUrl;
- }
-
- public String getFeedTitle() {
- return feedTitle;
- }
-
- public String getETag() {
- return etag;
- }
-
- public String getLastModified() {
- return lastModified;
- }
-
- public JSONObject toJSON() throws JSONException {
- JSONObject object = new JSONObject();
-
- object.put(JSON_KEY_FEED_TITLE, feedTitle);
- object.put(JSON_KEY_LAST_ITEM_TITLE, lastItemTitle);
- object.put(JSON_KEY_LAST_ITEM_URL, lastItemUrl);
- object.put(JSON_KEY_LAST_ITEM_TIMESTAMP, lastItemTimestamp);
- object.put(JSON_KEY_ETAG, etag);
- object.put(JSON_KEY_LAST_MODIFIED, lastModified);
-
- return object;
- }
-}
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
@@ -121,17 +121,16 @@ public class GeckoPreferenceFragment ext
return getString(R.string.pref_category_privacy_short);
}
// We can launch this category from the the magnifying glass in the quick search bar.
if (res == R.xml.preferences_search) {
return getString(R.string.pref_category_search);
}
- // Launched as action from content notifications.
if (res == R.xml.preferences_notifications) {
return getString(R.string.pref_category_notifications);
}
return null;
}
/**
@@ -153,17 +152,16 @@ public class GeckoPreferenceFragment ext
return R.id.pref_header_privacy;
}
// We can launch this category from the the magnifying glass in the quick search bar.
if (res == R.xml.preferences_search) {
return R.id.pref_header_search;
}
- // Launched as action from content notifications.
if (res == R.xml.preferences_notifications) {
return R.id.pref_header_notifications;
}
return -1;
}
private void updateTitle() {
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -1,72 +1,29 @@
/* -*- 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.preferences;
-import org.json.JSONArray;
-import org.mozilla.gecko.AboutPages;
-import org.mozilla.gecko.AdjustConstants;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.BrowserApp;
-import org.mozilla.gecko.BrowserLocaleManager;
-import org.mozilla.gecko.DataReportingNotification;
-import org.mozilla.gecko.DynamicToolbar;
-import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.Experiments;
-import org.mozilla.gecko.GeckoApplication;
-import org.mozilla.gecko.GeckoProfile;
-import org.mozilla.gecko.GeckoSharedPrefs;
-import org.mozilla.gecko.LocaleManager;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.PrefsHelper;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.SnackbarBuilder;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.TelemetryContract.Method;
-import org.mozilla.gecko.activitystream.ActivityStream;
-import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
-import org.mozilla.gecko.feeds.FeedService;
-import org.mozilla.gecko.feeds.action.CheckForUpdatesAction;
-import org.mozilla.gecko.mma.MmaDelegate;
-import org.mozilla.gecko.permissions.Permissions;
-import org.mozilla.gecko.restrictions.Restrictable;
-import org.mozilla.gecko.restrictions.Restrictions;
-import org.mozilla.gecko.tabqueue.TabQueueHelper;
-import org.mozilla.gecko.tabqueue.TabQueuePrompt;
-import org.mozilla.gecko.updater.UpdateService;
-import org.mozilla.gecko.updater.UpdateServiceHelper;
-import org.mozilla.gecko.util.BundleEventListener;
-import org.mozilla.gecko.util.ContextUtils;
-import org.mozilla.gecko.util.EventCallback;
-import org.mozilla.gecko.util.GeckoBundle;
-import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.InputOptionsUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.ViewUtil;
-
+import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Configuration;
-import android.Manifest;
-import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
@@ -85,17 +42,53 @@ import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
-import org.mozilla.gecko.switchboard.SwitchBoard;
+import org.json.JSONArray;
+import org.mozilla.gecko.AboutPages;
+import org.mozilla.gecko.AdjustConstants;
+import org.mozilla.gecko.AppConstants;
+import org.mozilla.gecko.BrowserApp;
+import org.mozilla.gecko.BrowserLocaleManager;
+import org.mozilla.gecko.DataReportingNotification;
+import org.mozilla.gecko.DynamicToolbar;
+import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.GeckoApplication;
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.LocaleManager;
+import org.mozilla.gecko.Locales;
+import org.mozilla.gecko.PrefsHelper;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.SnackbarBuilder;
+import org.mozilla.gecko.Telemetry;
+import org.mozilla.gecko.TelemetryContract;
+import org.mozilla.gecko.TelemetryContract.Method;
+import org.mozilla.gecko.db.BrowserContract.SuggestedSites;
+import org.mozilla.gecko.mma.MmaDelegate;
+import org.mozilla.gecko.permissions.Permissions;
+import org.mozilla.gecko.restrictions.Restrictable;
+import org.mozilla.gecko.restrictions.Restrictions;
+import org.mozilla.gecko.tabqueue.TabQueueHelper;
+import org.mozilla.gecko.tabqueue.TabQueuePrompt;
+import org.mozilla.gecko.updater.UpdateService;
+import org.mozilla.gecko.updater.UpdateServiceHelper;
+import org.mozilla.gecko.util.BundleEventListener;
+import org.mozilla.gecko.util.ContextUtils;
+import org.mozilla.gecko.util.EventCallback;
+import org.mozilla.gecko.util.GeckoBundle;
+import org.mozilla.gecko.util.HardwareUtils;
+import org.mozilla.gecko.util.InputOptionsUtils;
+import org.mozilla.gecko.util.ThreadUtils;
+import org.mozilla.gecko.util.ViewUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -150,18 +143,16 @@ public class GeckoPreferences
private static final String PREFS_CLEAR_PRIVATE_DATA_EXIT = NON_PREF_PREFIX + "history.clear_on_exit";
private static final String PREFS_SCREEN_ADVANCED = NON_PREF_PREFIX + "advanced_screen";
public static final String PREFS_HOMEPAGE = NON_PREF_PREFIX + "homepage";
public static final String PREFS_HOMEPAGE_FOR_EVERY_NEW_TAB = NON_PREF_PREFIX + "newtab.load_homepage";
public static final String PREFS_HOMEPAGE_PARTNER_COPY = GeckoPreferences.PREFS_HOMEPAGE + ".partner";
public static final String PREFS_HISTORY_SAVED_SEARCH = NON_PREF_PREFIX + "search.search_history.enabled";
private static final String PREFS_FAQ_LINK = NON_PREF_PREFIX + "faq.link";
private static final String PREFS_FEEDBACK_LINK = NON_PREF_PREFIX + "feedback.link";
- public static final String PREFS_NOTIFICATIONS_CONTENT = NON_PREF_PREFIX + "notifications.content";
- public static final String PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE = NON_PREF_PREFIX + "notifications.content.learn_more";
public static final String PREFS_NOTIFICATIONS_WHATS_NEW = NON_PREF_PREFIX + "notifications.whats_new";
public static final String PREFS_APP_UPDATE_LAST_BUILD_ID = "app.update.last_build_id";
public static final String PREFS_READ_PARTNER_CUSTOMIZATIONS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_customizations_provider";
public static final String PREFS_READ_PARTNER_BOOKMARKS_PROVIDER = NON_PREF_PREFIX + "distribution.read_partner_bookmarks_provider";
public static final String PREFS_CUSTOM_TABS = NON_PREF_PREFIX + "customtabs";
public static final String PREFS_PWA = NON_PREF_PREFIX + "pwa";
public static final String PREFS_CATEGORY_EXPERIMENTAL_FEATURES = NON_PREF_PREFIX + "category_experimental";
public static final String PREFS_COMPACT_TABS = NON_PREF_PREFIX + "compact_tabs";
@@ -410,23 +401,16 @@ public class GeckoPreferences
// capture EXTRA_SHOW_FRAGMENT_TITLE from the intent and store the title ID.
// If launched from notification, explicitly cancel the notification.
if (intentExtras != null && intentExtras.containsKey(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION)) {
Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH, Method.NOTIFICATION, "settings-data-choices");
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(DataReportingNotification.ALERT_NAME_DATAREPORTING_NOTIFICATION.hashCode());
}
-
- // Launched from "Notifications settings" action button in a notification.
- if (intentExtras != null && intentExtras.containsKey(CheckForUpdatesAction.EXTRA_CONTENT_NOTIFICATION)) {
- Telemetry.startUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this));
- Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, Method.BUTTON, "notification-settings");
- Telemetry.stopUISession(TelemetryContract.Session.EXPERIMENT, FeedService.getEnabledExperiment(this));
- }
}
/**
* Set intent to display top-level settings fragment,
* and show the correct title.
*/
private void setupTopLevelFragmentIntent() {
Intent intent = getIntent();
@@ -844,23 +828,16 @@ public class GeckoPreferences
final String url = getResources().getString(R.string.feedback_link, AppConstants.MOZ_APP_VERSION, AppConstants.MOZ_UPDATE_CHANNEL);
((LinkPreference) pref).setUrl(url);
} else if (PREFS_DYNAMIC_TOOLBAR.equals(key)) {
if (DynamicToolbar.isForceDisabled()) {
preferences.removePreference(pref);
i--;
continue;
}
- } else if (PREFS_NOTIFICATIONS_CONTENT.equals(key) ||
- PREFS_NOTIFICATIONS_CONTENT_LEARN_MORE.equals(key)) {
- if (!FeedService.isInExperiment(this)) {
- preferences.removePreference(pref);
- i--;
- continue;
- }
} else if (PREFS_CUSTOM_TABS.equals(key) && !AppConstants.MOZ_ANDROID_CUSTOM_TABS) {
preferences.removePreference(pref);
i--;
continue;
} else if (PREFS_PWA.equals(key) && !AppConstants.MOZ_ANDROID_PWA) {
preferences.removePreference(pref);
i--;
continue;
@@ -1174,18 +1151,16 @@ public class GeckoPreferences
return true;
}
} else if (PREFS_TAB_QUEUE.equals(prefName)) {
if ((Boolean) newValue && !TabQueueHelper.canDrawOverlays(this)) {
Intent promptIntent = new Intent(this, TabQueuePrompt.class);
startActivityForResult(promptIntent, REQUEST_CODE_TAB_QUEUE);
return false;
}
- } else if (PREFS_NOTIFICATIONS_CONTENT.equals(prefName)) {
- FeedService.setup(this);
} else if (HANDLERS.containsKey(prefName)) {
PrefHandler handler = HANDLERS.get(prefName);
handler.onChange(this, preference, newValue);
} else if (PREFS_SEARCH_SUGGESTIONS_ENABLED.equals(prefName)) {
// Tell Gecko to transmit the current search engine data again, so
// BrowserSearch is notified immediately about the new enabled state.
EventDispatcher.getInstance().dispatch("SearchEngines:GetVisible", null);
}
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -201,18 +201,16 @@
<!ENTITY pref_search_hint2 "TIP: Add any website to your list of search providers by long-pressing on its search field and then touching the &formatI; icon.">
<!ENTITY pref_category_advanced "Advanced">
<!-- Localization note (pref_category_advanced_summary3): “data saver” in this
context means consuming less data, e.g. by not loading images, not
“storing data”. -->
<!ENTITY pref_category_advanced_summary3 "Restore tabs, data saver, developer tools">
<!ENTITY pref_category_notifications "Notifications">
<!ENTITY pref_category_notifications_summary "New features, website updates">
-<!ENTITY pref_content_notifications "Website updates">
-<!ENTITY pref_content_notifications_summary2 "Discover new content from supported sites">
<!ENTITY pref_developer_remotedebugging_usb "Remote debugging via USB">
<!ENTITY pref_developer_remotedebugging_wifi "Remote debugging via Wi-Fi">
<!ENTITY pref_developer_remotedebugging_wifi_disabled_summary "Wi-Fi debugging requires your device to have a QR code reader app installed.">
<!ENTITY pref_remember_signons2 "Remember logins">
<!ENTITY pref_manage_logins "Manage logins">
<!ENTITY pref_category_home "Home">
<!ENTITY pref_category_home_summary "Customize your homepage">
@@ -330,33 +328,16 @@
<!-- Localization note (tab_queue_notification_text_singular2) : This is the
text of a notification; we expect only one tab queued. -->
<!ENTITY tab_queue_notification_text_singular2 "1 tab waiting">
<!-- Localization note (tab_queue_notification_settings): This notification text is shown if a tab
has been queued but we are missing the system permission to show an overlay. -->
<!ENTITY tab_queue_notification_settings "To \"Open multiple links\", please enable the \'Draw over other apps\' permission for &brandShortName;">
-<!ENTITY content_notification_summary "&brandShortName;">
-<!-- Localization note (content_notification_title_plural): &formatD; will be replaced with the number of websites that
- have been updated (new content is available). The number of websites is always more than one (>= 2). For a single
- update the website title is used instead of this string.
- We can't use Android plural forms, sadly. See Bug #753859. -->
-<!ENTITY content_notification_title_plural "&formatD; websites updated">
-<!-- Localization note (content_notification_action_settings2): This label will be shown as an action in a content notification.
- Clicking the action will jump to the notification settings of the app. -->
-<!ENTITY content_notification_action_settings2 "Settings">
-<!-- Localization note(content_notification_action_read_now): This label will be shown as an action in a content notification.
- Clicking the action will open all new content in the browser. -->
-<!ENTITY content_notification_action_read_now "Read now">
-<!-- Localization note (content_notification_updated_on): &formatS; will be replaced with a medium sized version of the
- date, depending on locale. For en_US this is for example: Feb 24, 2016. For more details see the Android developer
- documentation for DateFormat.getMediumDateFormat(). -->
-<!ENTITY content_notification_updated_on "Updated on &formatS;">
-
<!ENTITY pref_char_encoding "Character encoding">
<!ENTITY pref_char_encoding_on "Show menu">
<!ENTITY pref_char_encoding_off "Don\'t show menu">
<!ENTITY pref_clear_private_data2 "Clear private data">
<!-- Localization note (pref_clear_private_data_now_tablet): This action to clear private data is only shown on tablets.
The action is shown below a header saying "Clear private data"; See pref_clear_private_data -->
<!ENTITY pref_clear_private_data_now_tablet "Clear now">
<!ENTITY pref_clear_on_exit_title3 "Clear private data on exit">
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -548,17 +548,16 @@ gbjar.sources += ['java/org/mozilla/geck
'ANRReporter.java',
'bookmarks/BookmarkEditFragment.java',
'bookmarks/BookmarkUtils.java',
'bookmarks/CreateFolderCallback.java',
'bookmarks/CreateFolderFragment.java',
'bookmarks/EditBookmarkTask.java',
'bookmarks/SelectFolderCallback.java',
'bookmarks/SelectFolderFragment.java',
- 'BootReceiver.java',
'BrowserApp.java',
'BrowserLocaleManager.java',
'cleanup/FileCleanupController.java',
'cleanup/FileCleanupService.java',
'CustomEditText.java',
'customtabs/ActionBarPresenter.java',
'customtabs/CustomTabsActivity.java',
'customtabs/CustomTabsSecurityPopup.java',
@@ -624,35 +623,16 @@ gbjar.sources += ['java/org/mozilla/geck
'dlc/VerifyAction.java',
'DoorHangerPopup.java',
'DownloadsIntegration.java',
'drawable/DrawableWrapper.java',
'drawable/ShiftDrawable.java',
'DynamicToolbar.java',
'EditBookmarkDialog.java',
'Experiments.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',
- 'feeds/parser/Feed.java',
- 'feeds/parser/Item.java',
- 'feeds/parser/SimpleFeedParser.java',
- 'feeds/subscriptions/FeedSubscription.java',
'FilePicker.java',
'FilePickerResultHandler.java',
'FindInPageBar.java',
'firstrun/DataPanel.java',
'firstrun/FirstrunAnimationContainer.java',
'firstrun/FirstrunPager.java',
'firstrun/FirstrunPagerConfig.java',
'firstrun/FirstrunPanel.java',
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -164,18 +164,16 @@
<string name="pref_category_advanced">&pref_category_advanced;</string>
<string name="pref_category_advanced_summary">&pref_category_advanced_summary3;</string>
<string name="pref_developer_remotedebugging_usb">&pref_developer_remotedebugging_usb;</string>
<string name="pref_developer_remotedebugging_wifi">&pref_developer_remotedebugging_wifi;</string>
<string name="pref_developer_remotedebugging_wifi_disabled_summary">&pref_developer_remotedebugging_wifi_disabled_summary;</string>
<string name="pref_category_notifications">&pref_category_notifications;</string>
<string name="pref_category_notifications_summary">&pref_category_notifications_summary;</string>
- <string name="pref_content_notifications">&pref_content_notifications;</string>
- <string name="pref_content_notifications_summary">&pref_content_notifications_summary2;</string>
<string name="pref_category_home">&pref_category_home;</string>
<string name="pref_category_home_summary">&pref_category_home_summary;</string>
<string name="pref_category_home_panels">&pref_category_home_panels;</string>
<string name="pref_home_updates_wifi">&pref_home_updates_wifi;</string>
<string name="pref_category_home_add_ons">&pref_category_home_add_ons;</string>
<string name="pref_home_updates">&pref_home_updates2;</string>
<string name="pref_home_updates_enabled">&pref_home_updates_enabled;</string>
@@ -299,22 +297,16 @@
<string name="tab_queue_prompt_settings_button">&tab_queue_prompt_settings_button;</string>
<string name="tab_queue_toast_message">&tab_queue_toast_message3;</string>
<string name="tab_queue_toast_action">&tab_queue_toast_action;</string>
<string name="tab_queue_notification_text_singular">&tab_queue_notification_text_singular2;</string>
<string name="tab_queue_notification_text_plural">&tab_queue_notification_text_plural2;</string>
<string name="tab_queue_notification_title">&tab_queue_notification_title;</string>
<string name="tab_queue_notification_settings">&tab_queue_notification_settings;</string>
- <string name="content_notification_summary">&content_notification_summary;</string>
- <string name="content_notification_title_plural">&content_notification_title_plural;</string>
- <string name="content_notification_action_settings">&content_notification_action_settings2;</string>
- <string name="content_notification_action_read_now">&content_notification_action_read_now;</string>
- <string name="content_notification_updated_on">&content_notification_updated_on;</string>
-
<string name="pref_default_browser">&pref_default_browser;</string>
<string name="pref_default_browser_mozilla_support_tablet">&pref_default_browser_mozilla_support_tablet;</string>
<string name="pref_about_firefox">&pref_about_firefox;</string>
<string name="pref_vendor_faqs">&pref_vendor_faqs;</string>
<!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/faq -->
<string name="faq_link">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/faq</string>
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteBlogger.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- 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.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteBlogger {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite blogger = new KnownSiteBlogger();
- final String searchString = blogger.getURLSearchString();
-
- AssertUtil.assertContains(
- "http://mykzilla.blogspot.com/",
- searchString);
-
- AssertUtil.assertContains(
- "http://example.blogspot.com",
- searchString);
-
- AssertUtil.assertContains(
- "https://mykzilla.blogspot.com/2015/06/introducing-pluotsorbet.html",
- searchString);
-
- AssertUtil.assertContains(
- "http://android-developers.blogspot.com/2016/02/android-support-library-232.html",
- searchString);
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Blogger URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite blogger = new KnownSiteBlogger();
-
- Assert.assertEquals(
- "https://mykzilla.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://mykzilla.blogspot.com/"));
-
- Assert.assertEquals(
- "https://example.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://example.blogspot.com"));
-
- Assert.assertEquals(
- "https://mykzilla.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("https://mykzilla.blogspot.com/2015/06/introducing-pluotsorbet.html"));
-
- Assert.assertEquals(
- "https://android-developers.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://android-developers.blogspot.com/2016/02/android-support-library-232.html"));
-
- Assert.assertEquals(
- "https://example.blogspot.com/feeds/posts/default",
- blogger.getFeedFromURL("http://example.blogspot.com/2016/03/i-moved-to-example.blogspot.com"));
-
- Assert.assertNull(blogger.getFeedFromURL("http://www.mozilla.org"));
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteMedium.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- 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.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteMedium {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite medium = new KnownSiteMedium();
- final String searchString = medium.getURLSearchString();
-
- AssertUtil.assertContains(
- "https://medium.com/@Antlam/",
- searchString);
-
- AssertUtil.assertContains(
- "https://medium.com/google-developers",
- searchString);
-
- AssertUtil.assertContains(
- "http://medium.com/@brandonshin/how-slackbot-forced-us-to-workout-7b4741a2de73",
- searchString
- );
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Medium URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite medium = new KnownSiteMedium();
-
- Assert.assertEquals(
- "https://medium.com/feed/@Antlam",
- medium.getFeedFromURL("https://medium.com/@Antlam/")
- );
-
- Assert.assertEquals(
- "https://medium.com/feed/google-developers",
- medium.getFeedFromURL("https://medium.com/google-developers")
- );
-
- Assert.assertEquals(
- "https://medium.com/feed/@brandonshin",
- medium.getFeedFromURL("http://medium.com/@brandonshin/how-slackbot-forced-us-to-workout-7b4741a2de73")
- );
-
- Assert.assertNull(medium.getFeedFromURL("http://www.mozilla.org"));
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/knownsites/TestKnownSiteTumblr.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- 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.knownsites;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.helpers.AssertUtil;
-
-@RunWith(TestRunner.class)
-public class TestKnownSiteTumblr {
- /**
- * Test that the search string is a substring of some known URLs.
- */
- @Test
- public void testURLSearchString() {
- final KnownSite tumblr = new KnownSiteTumblr();
- final String searchString = tumblr.getURLSearchString();
-
- AssertUtil.assertContains(
- "http://contentnotifications.tumblr.com/",
- searchString);
-
- AssertUtil.assertContains(
- "https://contentnotifications.tumblr.com",
- searchString);
-
- AssertUtil.assertContains(
- "http://contentnotifications.tumblr.com/post/142684202402/content-notification-firefox-for-android-480",
- searchString);
-
- AssertUtil.assertContainsNot(
- "http://www.mozilla.org",
- searchString);
- }
-
- /**
- * Test that we get a feed URL for valid Medium URLs.
- */
- @Test
- public void testGettingFeedFromURL() {
- final KnownSite tumblr = new KnownSiteTumblr();
-
- Assert.assertEquals(
- "http://contentnotifications.tumblr.com/rss",
- tumblr.getFeedFromURL("http://contentnotifications.tumblr.com/")
- );
-
- Assert.assertEquals(
- "http://staff.tumblr.com/rss",
- tumblr.getFeedFromURL("https://staff.tumblr.com/post/141928246566/replies-are-back-and-the-sun-is-shining-on-the")
- );
-
- Assert.assertNull(tumblr.getFeedFromURL("https://www.tumblr.com"));
-
- Assert.assertNull(tumblr.getFeedFromURL("http://www.mozilla.org"));
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/feeds/parser/TestSimpleFeedParser.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/* -*- 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.parser;
-
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-@RunWith(TestRunner.class)
-public class TestSimpleFeedParser {
- /**
- * Parse and verify the RSS example from Wikipedia:
- * https://en.wikipedia.org/wiki/RSS#Example
- */
- @Test
- public void testRSSExample() throws Exception {
- InputStream stream = openFeed("feed_rss_wikipedia.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("RSS Title", feed.getTitle());
- Assert.assertEquals("http://www.example.com/main.html", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Example entry", item.getTitle());
- Assert.assertEquals("http://www.example.com/blog/post/1", item.getURL());
- Assert.assertEquals(1252254000000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify the ATOM example from Wikipedia:
- * https://en.wikipedia.org/wiki/Atom_%28standard%29#Example_of_an_Atom_1.0_feed
- */
- @Test
- public void testATOMExample() throws Exception {
- InputStream stream = openFeed("feed_atom_wikipedia.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Example Feed", feed.getTitle());
- Assert.assertEquals("http://example.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://example.org/feed/", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Atom-Powered Robots Run Amok", item.getTitle());
- Assert.assertEquals("http://example.org/2003/12/13/atom03.html", item.getURL());
- Assert.assertEquals(1071340202000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Medium feed.
- */
- @Test
- public void testMediumFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_medium.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Anthony Lam on Medium", feed.getTitle());
- Assert.assertEquals("https://medium.com/@antlam?source=rss-59f49b9e4b19------2", feed.getWebsiteURL());
- Assert.assertEquals("https://medium.com/feed/@antlam", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("UX thoughts for 2016", item.getTitle());
- Assert.assertEquals("https://medium.com/@antlam/ux-thoughts-for-2016-1fc1d6e515e8?source=rss-59f49b9e4b19------2", item.getURL());
- Assert.assertEquals(1452537838000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org ATOM feed.
- */
- @Test
- public void testPlanetMozillaATOMFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/atom.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Firefox 45.0 Beta 3 Testday, February 5th", item.getTitle());
- Assert.assertEquals("https://quality.mozilla.org/2016/01/firefox-45-0-beta-3-testday-february-5th/", item.getURL());
- Assert.assertEquals(1453819255000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org RSS 2.0 feed.
- */
- @Test
- public void testPlanetMozillaRSS20Feed() throws Exception {
- InputStream stream = openFeed("feed_rss20_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/rss20.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Aaron Klotz: Announcing Mozdbgext", item.getTitle());
- Assert.assertEquals("http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/", item.getURL());
- Assert.assertEquals(1453837500000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of planet.mozilla.org RSS 1.0 feed.
- */
- @Test
- public void testPlanetMozillaRSS10Feed() throws Exception {
- InputStream stream = openFeed("feed_rss10_planetmozilla.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Planet Mozilla", feed.getTitle());
- Assert.assertEquals("http://planet.mozilla.org/", feed.getWebsiteURL());
- Assert.assertEquals("http://planet.mozilla.org/rss10.xml", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Aaron Klotz: Announcing Mozdbgext", item.getTitle());
- Assert.assertEquals("http://dblohm7.ca/blog/2016/01/26/announcing-mozdbgext/", item.getURL());
- Assert.assertEquals(1453837500000L, item.getTimestamp());
- }
-
- /**
- * Parse an verify a snapshot of a feedburner ATOM feed.
- */
- @Test
- public void testFeedburnerAtomFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_feedburner.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Android Zeitgeist", feed.getTitle());
- Assert.assertEquals("http://www.androidzeitgeist.com/", feed.getWebsiteURL());
- Assert.assertEquals("http://feeds.feedburner.com/AndroidZeitgeist", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Support for restricted profiles in Firefox 42", item.getTitle());
- Assert.assertEquals("http://feedproxy.google.com/~r/AndroidZeitgeist/~3/xaSicfGuwOU/support-restricted-profiles-firefox.html", item.getURL());
- Assert.assertEquals(1442511968239L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Tumblr RSS feed.
- */
- @Test
- public void testTumblrRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_tumblr.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("Tumblr Staff", feed.getTitle());
- Assert.assertEquals("http://staff.tumblr.com/", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("hardyboyscovers: Can Nancy Drew see things through and solve...", item.getTitle());
- Assert.assertEquals("http://staff.tumblr.com/post/138124026275", item.getURL());
- Assert.assertEquals(1453861812000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Spiegel (German news magazine) RSS feed.
- */
- @Test
- public void testSpiegelRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_spon.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("SPIEGEL ONLINE - Schlagzeilen", feed.getTitle());
- Assert.assertEquals("http://www.spiegel.de", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Angebliche Vergewaltigung einer 13-Jährigen: Steinmeier kanzelt russischen Minister Lawrow ab", item.getTitle());
- Assert.assertEquals("http://www.spiegel.de/politik/ausland/steinmeier-kanzelt-lawrow-ab-aerger-um-angebliche-vergewaltigung-a-1074292.html#ref=rss", item.getURL());
- Assert.assertEquals(1453914976000L, item.getTimestamp());
- }
-
- /**
- * Parse and verify a snapshot of a Heise (German tech news) RSS feed.
- */
- @Test
- public void testHeiseRssFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_heise.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("heise online News", feed.getTitle());
- Assert.assertEquals("http://www.heise.de/newsticker/", feed.getWebsiteURL());
- Assert.assertNull(feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Google: “Dramatische Verbesserungen” für Chrome in iOS", item.getTitle());
- Assert.assertEquals("http://www.heise.de/newsticker/meldung/Google-Dramatische-Verbesserungen-fuer-Chrome-in-iOS-3085808.html?wt_mc=rss.ho.beitrag.atom", item.getURL());
- Assert.assertEquals(1453915920000L, item.getTimestamp());
- }
-
- @Test
- public void testWordpressFeed() throws Exception {
- InputStream stream = openFeed("feed_rss_wordpress.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("justasimpletest2016", feed.getTitle());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com", feed.getWebsiteURL());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com/feed/", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("Hello World!", item.getTitle());
- Assert.assertEquals("https://justasimpletest2016.wordpress.com/2016/02/26/hello-world/", item.getURL());
- Assert.assertEquals(1456524466000L, item.getTimestamp());
- }
-
- /**
- * Parse and test a snapshot of mykzilla.blogspot.com
- */
- @Test
- public void testBloggerFeed() throws Exception {
- InputStream stream = openFeed("feed_atom_blogger.xml");
-
- SimpleFeedParser parser = new SimpleFeedParser();
- Feed feed = parser.parse(stream);
-
- Assert.assertNotNull(feed);
- Assert.assertEquals("mykzilla", feed.getTitle());
- Assert.assertEquals("http://mykzilla.blogspot.com/", feed.getWebsiteURL());
- Assert.assertEquals("http://www.blogger.com/feeds/18929277/posts/default", feed.getFeedURL());
- Assert.assertTrue(feed.isSufficientlyComplete());
-
- Item item = feed.getLastItem();
-
- Assert.assertNotNull(item);
- Assert.assertEquals("URL Has Been Changed", item.getTitle());
- Assert.assertEquals("http://mykzilla.blogspot.com/2016/01/url-has-been-changed.html", item.getURL());
- Assert.assertEquals(1452531451366L, item.getTimestamp());
- }
-
- private InputStream openFeed(String fileName) throws URISyntaxException, FileNotFoundException, UnsupportedEncodingException {
- URL url = getClass().getResource("/" + fileName);
- if (url == null) {
- throw new FileNotFoundException(fileName);
- }
-
- return new BufferedInputStream(new FileInputStream(url.getPath()));
- }
-}