From 8f7e30d7c5af7a20c84445b0820204daf9850260 Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Sat, 18 Oct 2014 02:45:34 -0400 Subject: [PATCH] Bug 1078355 - Move reader mode code out of BrowserApp, r=margaret --- mobile/android/base/BrowserApp.java | 119 +------------ mobile/android/base/ReadingListHelper.java | 195 +++++++++++++++++++++ mobile/android/base/moz.build | 1 + 3 files changed, 205 insertions(+), 110 deletions(-) create mode 100644 mobile/android/base/ReadingListHelper.java diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index bfe9e6eebe8..92418186975 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -21,10 +21,10 @@ import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.DynamicToolbar.PinReason; import org.mozilla.gecko.DynamicToolbar.VisibilityTransition; import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException; +import org.mozilla.gecko.ReadingListHelper; import org.mozilla.gecko.animation.PropertyAnimator; import org.mozilla.gecko.animation.ViewHelper; import org.mozilla.gecko.db.BrowserContract.Combined; -import org.mozilla.gecko.db.BrowserContract.ReadingListItems; import org.mozilla.gecko.db.BrowserContract.SearchHistory; import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.SuggestedSites; @@ -146,10 +146,6 @@ public class BrowserApp extends GeckoApp private static final int TABS_ANIMATION_DURATION = 450; - private static final int READER_ADD_SUCCESS = 0; - private static final int READER_ADD_FAILED = 1; - private static final int READER_ADD_DUPLICATE = 2; - private static final String ADD_SHORTCUT_TOAST = "add_shortcut_toast"; public static final String GUEST_BROWSING_ARG = "--guest"; @@ -229,6 +225,8 @@ public class BrowserApp extends GeckoApp private BrowserHealthReporter mBrowserHealthReporter; + private ReadingListHelper mReadingListHelper; + private SystemBarTintManager mTintManager; // The tab to be selected on editing mode exit. @@ -433,90 +431,6 @@ public class BrowserApp extends GeckoApp return super.onKeyUp(keyCode, event); } - void handleReaderListStatusRequest(final String url) { - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - final int inReadingList = BrowserDB.isReadingListItem(getContentResolver(), url) ? 1 : 0; - - final JSONObject json = new JSONObject(); - try { - json.put("url", url); - json.put("inReadingList", inReadingList); - } catch (JSONException e) { - Log.e(LOGTAG, "JSON error - failed to return inReadingList status", e); - return; - } - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:ListStatusReturn", json.toString())); - } - }); - } - - private void handleReaderAdded(int result, final ContentValues values) { - if (result != READER_ADD_SUCCESS) { - if (result == READER_ADD_FAILED) { - showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT); - } else if (result == READER_ADD_DUPLICATE) { - showToast(R.string.reading_list_duplicate, Toast.LENGTH_SHORT); - } - - return; - } - - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - BrowserDB.addReadingListItem(getContentResolver(), values); - showToast(R.string.reading_list_added, Toast.LENGTH_SHORT); - } - }); - } - - private ContentValues messageToReadingListContentValues(JSONObject message) { - final ContentValues values = new ContentValues(); - values.put(ReadingListItems.URL, message.optString("url")); - values.put(ReadingListItems.TITLE, message.optString("title")); - values.put(ReadingListItems.LENGTH, message.optInt("length")); - values.put(ReadingListItems.EXCERPT, message.optString("excerpt")); - return values; - } - - void handleReaderRemoved(final String url) { - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - BrowserDB.removeReadingListItemWithURL(getContentResolver(), url); - showToast(R.string.page_removed, Toast.LENGTH_SHORT); - } - }); - } - - private void handleReaderFaviconRequest(final String url) { - (new UIAsyncTask.WithoutParams(ThreadUtils.getBackgroundHandler()) { - @Override - public String doInBackground() { - return Favicons.getFaviconURLForPageURL(getContext(), url); - } - - @Override - public void onPostExecute(String faviconUrl) { - JSONObject args = new JSONObject(); - - if (faviconUrl != null) { - try { - args.put("url", url); - args.put("faviconUrl", faviconUrl); - } catch (JSONException e) { - Log.w(LOGTAG, "Error building JSON favicon arguments.", e); - } - } - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString())); - } - }).execute(); - } - @Override public void onCreate(Bundle savedInstanceState) { mAboutHomeStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_ABOUTHOME"); @@ -600,8 +514,6 @@ public class BrowserApp extends GeckoApp EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this, "Menu:Update", - "Reader:Added", - "Reader:FaviconRequest", "Search:Keyword", "Prompt:ShowTop", "Accounts:Exist"); @@ -615,8 +527,6 @@ public class BrowserApp extends GeckoApp "Feedback:OpenPlayStore", "Menu:Add", "Menu:Remove", - "Reader:ListStatusRequest", - "Reader:Removed", "Reader:Share", "Settings:Show", "Telemetry:Gather", @@ -633,6 +543,7 @@ public class BrowserApp extends GeckoApp mSharedPreferencesHelper = new SharedPreferencesHelper(appContext); mOrderedBroadcastHelper = new OrderedBroadcastHelper(appContext); mBrowserHealthReporter = new BrowserHealthReporter(); + mReadingListHelper = new ReadingListHelper(appContext); if (AppConstants.MOZ_ANDROID_BEAM) { NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this); @@ -1142,10 +1053,13 @@ public class BrowserApp extends GeckoApp mBrowserHealthReporter = null; } + if (mReadingListHelper != null) { + mReadingListHelper.uninit(); + mReadingListHelper = null; + } + EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this, "Menu:Update", - "Reader:Added", - "Reader:FaviconRequest", "Search:Keyword", "Prompt:ShowTop", "Accounts:Exist"); @@ -1159,8 +1073,6 @@ public class BrowserApp extends GeckoApp "Feedback:OpenPlayStore", "Menu:Add", "Menu:Remove", - "Reader:ListStatusRequest", - "Reader:Removed", "Reader:Share", "Settings:Show", "Telemetry:Gather", @@ -1519,13 +1431,6 @@ public class BrowserApp extends GeckoApp } }); - } else if ("Reader:ListStatusRequest".equals(event)) { - handleReaderListStatusRequest(message.getString("url")); - - } else if ("Reader:Removed".equals(event)) { - final String url = message.getString("url"); - handleReaderRemoved(url); - } else if ("Reader:Share".equals(event)) { final String title = message.getString("title"); final String url = message.getString("url"); @@ -1640,12 +1545,6 @@ public class BrowserApp extends GeckoApp DataReportingNotification.checkAndNotifyPolicy(GeckoAppShell.getContext()); } - } else if (event.equals("Reader:Added")) { - final int result = message.getInt("result"); - handleReaderAdded(result, messageToReadingListContentValues(message)); - } else if (event.equals("Reader:FaviconRequest")) { - final String url = message.getString("url"); - handleReaderFaviconRequest(url); } else if (event.equals("Search:Keyword")) { storeSearchQuery(message.getString("query")); } else if (event.equals("Prompt:ShowTop")) { diff --git a/mobile/android/base/ReadingListHelper.java b/mobile/android/base/ReadingListHelper.java new file mode 100644 index 00000000000..36dbc0319df --- /dev/null +++ b/mobile/android/base/ReadingListHelper.java @@ -0,0 +1,195 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.db.BrowserContract.ReadingListItems; +import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.favicons.Favicons; +import org.mozilla.gecko.util.EventCallback; +import org.mozilla.gecko.util.GeckoEventListener; +import org.mozilla.gecko.util.NativeEventListener; +import org.mozilla.gecko.util.NativeJSObject; +import org.mozilla.gecko.util.ThreadUtils; +import org.mozilla.gecko.util.UIAsyncTask; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.net.Uri; +import android.util.Log; +import android.widget.Toast; + +public final class ReadingListHelper implements GeckoEventListener, NativeEventListener { + private static final String LOGTAG = "ReadingListHelper"; + + private static final int READER_ADD_SUCCESS = 0; + private static final int READER_ADD_FAILED = 1; + private static final int READER_ADD_DUPLICATE = 2; + + protected final Context context; + + + public ReadingListHelper(Context context) { + this.context = context; + + EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener) this, + "Reader:Added", "Reader:FaviconRequest"); + EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener) this, + "Reader:ListStatusRequest", "Reader:Removed"); + } + + public void uninit() { + EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener) this, + "Reader:Added", "Reader:FaviconRequest"); + EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener) this, + "Reader:ListStatusRequest", "Reader:Removed"); + } + + @Override + public void handleMessage(String event, JSONObject message) { + switch(event) { + case "Reader:Added": { + handleReadingListAdded(message); + break; + } + + case "Reader:FaviconRequest": { + handleReaderModeFaviconRequest(message.optString("url")); + break; + } + } + } + + @Override + public void handleMessage(final String event, final NativeJSObject message, + final EventCallback callback) { + switch(event) { + case "Reader:Removed": { + handleReadingListRemoved(message.getString("url")); + break; + } + + case "Reader:ListStatusRequest": { + handleReadingListStatusRequest(message.getString("url")); + break; + } + } + } + + /** + * A page can be added to the ReadingList by long-tap of the page-action + * icon, or by tapping the readinglist-add icon in the ReaderMode banner. + */ + private void handleReadingListAdded(JSONObject message) { + final int result = message.optInt("result", READER_ADD_FAILED); + if (result != READER_ADD_SUCCESS) { + if (result == READER_ADD_FAILED) { + showToast(R.string.reading_list_failed, Toast.LENGTH_SHORT); + } else if (result == READER_ADD_DUPLICATE) { + showToast(R.string.reading_list_duplicate, Toast.LENGTH_SHORT); + } + return; + } + + final ContentValues values = new ContentValues(); + values.put(ReadingListItems.URL, message.optString("url")); + values.put(ReadingListItems.TITLE, message.optString("title")); + values.put(ReadingListItems.LENGTH, message.optInt("length")); + values.put(ReadingListItems.EXCERPT, message.optString("excerpt")); + + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + BrowserDB.addReadingListItem(context.getContentResolver(), values); + showToast(R.string.reading_list_added, Toast.LENGTH_SHORT); + } + }); + } + + /** + * Gecko (ReaderMode) requests the page favicon to append to the + * document head for display. + */ + private void handleReaderModeFaviconRequest(final String url) { + (new UIAsyncTask.WithoutParams(ThreadUtils.getBackgroundHandler()) { + @Override + public String doInBackground() { + return Favicons.getFaviconURLForPageURL(context, url); + } + + @Override + public void onPostExecute(String faviconUrl) { + JSONObject args = new JSONObject(); + + if (faviconUrl != null) { + try { + args.put("url", url); + args.put("faviconUrl", faviconUrl); + } catch (JSONException e) { + Log.w(LOGTAG, "Error building JSON favicon arguments.", e); + } + } + + GeckoAppShell.sendEventToGecko( + GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString())); + } + }).execute(); + } + + /** + * A page can be removed from the ReadingList by panel context menu, + * or by tapping the readinglist-remove icon in the ReaderMode banner. + */ + private void handleReadingListRemoved(final String url) { + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + BrowserDB.removeReadingListItemWithURL(context.getContentResolver(), url); + showToast(R.string.page_removed, Toast.LENGTH_SHORT); + } + }); + } + + /** + * Gecko (ReaderMode) requests the page ReadingList status, to display + * the proper ReaderMode banner icon (readinglist-add / readinglist-remove). + */ + private void handleReadingListStatusRequest(final String url) { + ThreadUtils.postToBackgroundThread(new Runnable() { + @Override + public void run() { + final int inReadingList = + BrowserDB.isReadingListItem(context.getContentResolver(), url) ? 1 : 0; + + final JSONObject json = new JSONObject(); + try { + json.put("url", url); + json.put("inReadingList", inReadingList); + } catch (JSONException e) { + Log.e(LOGTAG, "JSON error - failed to return inReadingList status", e); + return; + } + + GeckoAppShell.sendEventToGecko( + GeckoEvent.createBroadcastEvent("Reader:ListStatusReturn", json.toString())); + } + }); + } + + /** + * Show various status toasts. + */ + private void showToast(final int resId, final int duration) { + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(context, resId, duration).show(); + } + }); + } +} diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index c2d7bf21f96..9d3cecc498e 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -368,6 +368,7 @@ gbjar.sources += [ 'prompts/PromptService.java', 'prompts/TabInput.java', 'ReaderModeUtils.java', + 'ReadingListHelper.java', 'RemoteClientsDialogFragment.java', 'RemoteTabsExpandableListAdapter.java', 'Restarter.java',