From 79d619f82b9ebc60d74ec9b2614169f9c4b9ffae Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Sun, 7 Feb 2016 12:34:04 -0500 Subject: [PATCH] Support bookmark importing from chrome variants and stock browser, lint fixes --- .../lightning/activity/SettingsActivity.java | 2 +- .../lightning/browser/BrowserPresenter.java | 4 +- .../lightning/constant/BookmarkPage.java | 2 +- .../lightning/database/BookmarkLocalSync.java | 160 +++++++-------- .../lightning/database/BookmarkManager.java | 10 + .../fragment/BookmarkSettingsFragment.java | 194 +++++++++++++++--- .../lightning/object/SearchAdapter.java | 2 +- .../browser/lightning/react/Observable.java | 2 +- .../lightning/view/LightningWebClient.java | 2 +- app/src/main/res/values/strings.xml | 5 +- app/src/main/res/xml/preference_bookmarks.xml | 9 +- 11 files changed, 270 insertions(+), 122 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index b67411c..f9c82ce 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -21,7 +21,7 @@ import acr.browser.lightning.R; public class SettingsActivity extends ThemableSettingsActivity { - private static final List mFragments = new ArrayList<>(); + private static final List mFragments = new ArrayList<>(6); @Override protected void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java index 7d7eeec..2a9c0d1 100644 --- a/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java +++ b/app/src/main/java/acr/browser/lightning/browser/BrowserPresenter.java @@ -33,10 +33,10 @@ public class BrowserPresenter { @Inject PreferenceManager mPreferences; @Inject Bus mEventBus; - @NonNull private BrowserView mView; + @NonNull private final BrowserView mView; @Nullable private LightningView mCurrentTab; - private boolean mIsIncognito; + private final boolean mIsIncognito; private boolean mIsNewIntent; public BrowserPresenter(@NonNull BrowserView view, boolean isIncognito) { diff --git a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index e853ee7..da8ec96 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -63,7 +63,7 @@ public final class BookmarkPage extends AsyncTask { private File mFilesDir; private File mCacheDir; - private Application mApp; + private final Application mApp; private final BookmarkManager mManager; @NonNull private final WeakReference mTabReference; private final Bitmap mFolderIcon; diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index 7fc5e2d..827c099 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -11,6 +11,9 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; +import acr.browser.lightning.react.Action; +import acr.browser.lightning.react.Observable; +import acr.browser.lightning.react.Subscriber; import acr.browser.lightning.utils.Utils; public class BookmarkLocalSync { @@ -28,18 +31,20 @@ public class BookmarkLocalSync { @NonNull private final Context mContext; + public enum Source { + STOCK, + CHROME_STABLE, + CHROME_BETA, + CHROME_DEV + } + public BookmarkLocalSync(@NonNull Context context) { mContext = context; } - @NonNull - @WorkerThread - public List getBookmarksFromStockBrowser() { + public List getBookmarksFromContentUri(String contentUri) { List list = new ArrayList<>(); - if (!isStockSupported()) { - return list; - } - Cursor cursor = getStockCursor(); + Cursor cursor = getBrowserCursor(contentUri); try { if (cursor != null) { for (int n = 0; n < cursor.getColumnCount(); n++) { @@ -69,114 +74,109 @@ public class BookmarkLocalSync { return list; } - @NonNull + @Nullable @WorkerThread - public List getBookmarksFromChrome() { - List list = new ArrayList<>(); - if (!isChromeSupported()) { - return list; - } - Cursor cursor = getChromeCursor(); + private Cursor getBrowserCursor(String contentUri) { + Cursor cursor; + Uri uri = Uri.parse(contentUri); try { - if (cursor != null) { - for (int n = 0; n < cursor.getColumnCount(); n++) { - Log.d(TAG, cursor.getColumnName(n)); - } + cursor = mContext.getContentResolver().query(uri, + new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); + } catch (IllegalArgumentException e) { + return null; + } + return cursor; + } - while (cursor.moveToNext()) { - if (cursor.getInt(2) == 1) { - String url = cursor.getString(0); - String title = cursor.getString(1); - if (url.isEmpty()) { - continue; - } - if (title == null || title.isEmpty()) { - title = Utils.getDomainName(url); - } - if (title != null) { - list.add(new HistoryItem(url, title)); - } - } + @NonNull + public Observable> getSupportedBrowsers() { + return Observable.create(new Action>() { + @Override + public void onSubscribe(@NonNull Subscriber> subscriber) { + List sources = new ArrayList<>(1); + if (isBrowserSupported(STOCK_BOOKMARKS_CONTENT)) { + sources.add(Source.STOCK); + } + if (isBrowserSupported(CHROME_BOOKMARKS_CONTENT)) { + sources.add(Source.CHROME_STABLE); } + if (isBrowserSupported(CHROME_BETA_BOOKMARKS_CONTENT)) { + sources.add(Source.CHROME_BETA); + } + if (isBrowserSupported(CHROME_DEV_BOOKMARKS_CONTENT)) { + sources.add(Source.CHROME_DEV); + } + subscriber.onNext(sources); + subscriber.onComplete(); } - } catch (Exception e) { - e.printStackTrace(); - } + }); + } + + private boolean isBrowserSupported(String contentUri) { + Cursor cursor = getBrowserCursor(contentUri); + boolean supported = cursor != null; Utils.close(cursor); - return list; + return supported; + } + + @NonNull + @WorkerThread + public List getBookmarksFromStockBrowser() { + return getBookmarksFromContentUri(STOCK_BOOKMARKS_CONTENT); } + @NonNull @WorkerThread - public boolean isStockSupported() { - Cursor cursor = getStockCursor(); - Utils.close(cursor); - return cursor != null; + public List getBookmarksFromChrome() { + return getBookmarksFromContentUri(CHROME_BOOKMARKS_CONTENT); } + @NonNull @WorkerThread - public boolean isChromeSupported() { - Cursor cursor = getChromeCursor(); - Utils.close(cursor); + public List getBookmarksFromChromeBeta() { + return getBookmarksFromContentUri(CHROME_BETA_BOOKMARKS_CONTENT); + } + + @NonNull + @WorkerThread + public List getBookmarksFromChromeDev() { + return getBookmarksFromContentUri(CHROME_DEV_BOOKMARKS_CONTENT); + } + + @WorkerThread + public boolean isBrowserImportSupported() { + Cursor chrome = getChromeCursor(); + Utils.close(chrome); Cursor dev = getChromeDevCursor(); Utils.close(dev); Cursor beta = getChromeBetaCursor(); - return cursor != null || dev != null || beta != null; + Cursor stock = getStockCursor(); + Utils.close(stock); + return chrome != null || dev != null || beta != null || stock != null; } @Nullable @WorkerThread private Cursor getChromeBetaCursor() { - Cursor cursor; - Uri uri = Uri.parse(CHROME_BETA_BOOKMARKS_CONTENT); - try { - cursor = mContext.getContentResolver().query(uri, - new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); - } catch (IllegalArgumentException e) { - return null; - } - return cursor; + return getBrowserCursor(CHROME_BETA_BOOKMARKS_CONTENT); } @Nullable @WorkerThread private Cursor getChromeDevCursor() { - Cursor cursor; - Uri uri = Uri.parse(CHROME_DEV_BOOKMARKS_CONTENT); - try { - cursor = mContext.getContentResolver().query(uri, - new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); - } catch (IllegalArgumentException e) { - return null; - } - return cursor; + return getBrowserCursor(CHROME_DEV_BOOKMARKS_CONTENT); } @Nullable @WorkerThread private Cursor getChromeCursor() { - Cursor cursor; - Uri uri = Uri.parse(CHROME_BOOKMARKS_CONTENT); - try { - cursor = mContext.getContentResolver().query(uri, - new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); - } catch (IllegalArgumentException e) { - return null; - } - return cursor; + return getBrowserCursor(CHROME_BOOKMARKS_CONTENT); } @Nullable @WorkerThread private Cursor getStockCursor() { - Cursor cursor; - Uri uri = Uri.parse(STOCK_BOOKMARKS_CONTENT); - try { - cursor = mContext.getContentResolver().query(uri, - new String[]{COLUMN_URL, COLUMN_TITLE, COLUMN_BOOKMARK}, null, null, null); - } catch (IllegalArgumentException e) { - return null; - } - return cursor; + return getBrowserCursor(STOCK_BOOKMARKS_CONTENT); } public void printAllColumns() { diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java index fddf2bb..e06dd8a 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -282,6 +282,16 @@ public class BookmarkManager { mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } + /** + * This method deletes ALL bookmarks created + * by the user. Use this method carefully and + * do not use it without explicit user consent. + */ + public synchronized void deleteAllBookmarks() { + mBookmarksMap = new HashMap<>(); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); + } + /** * This method edits a particular bookmark in the bookmark database * diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index e901b37..4ee1818 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -6,6 +6,8 @@ package acr.browser.lightning.fragment; import android.Manifest; import android.app.Activity; import android.content.DialogInterface; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; @@ -15,9 +17,15 @@ import android.preference.PreferenceFragment; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.app.AlertDialog; +import android.util.Log; +import android.widget.ArrayAdapter; + +import com.anthonycr.grant.PermissionsManager; +import com.anthonycr.grant.PermissionsResultAction; import java.io.File; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -26,13 +34,13 @@ import javax.inject.Inject; import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.constant.Constants; import acr.browser.lightning.database.BookmarkLocalSync; +import acr.browser.lightning.database.BookmarkLocalSync.Source; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; - -import com.anthonycr.grant.PermissionsManager; -import com.anthonycr.grant.PermissionsResultAction; - +import acr.browser.lightning.react.OnSubscribe; +import acr.browser.lightning.react.Schedulers; import acr.browser.lightning.utils.Preconditions; import acr.browser.lightning.utils.Utils; @@ -41,6 +49,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref private static final String SETTINGS_EXPORT = "export_bookmark"; private static final String SETTINGS_IMPORT = "import_bookmark"; private static final String SETTINGS_IMPORT_BROWSER = "import_browser"; + private static final String SETTINGS_DELETE_BOOKMARKS = "delete_bookmarks"; @Nullable private Activity mActivity; @@ -53,27 +62,41 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; - private ImportBookmarksTask mImportTaskReference; private static final File mPath = new File(Environment.getExternalStorageDirectory().toString()); private class ImportBookmarksTask extends AsyncTask { @NonNull private final WeakReference mActivityReference; + private final Source mSource; - public ImportBookmarksTask(Activity activity) { + public ImportBookmarksTask(Activity activity, Source source) { mActivityReference = new WeakReference<>(activity); + mSource = source; } @Override protected Integer doInBackground(Void... params) { - List list = null; - if (getSync().isStockSupported()) { - list = getSync().getBookmarksFromStockBrowser(); - } else if (getSync().isChromeSupported()) { - list = getSync().getBookmarksFromChrome(); + List list; + Log.d(Constants.TAG, "Loading bookmarks from: " + mSource.name()); + switch (mSource) { + case STOCK: + list = getSync().getBookmarksFromStockBrowser(); + break; + case CHROME_STABLE: + list = getSync().getBookmarksFromChrome(); + break; + case CHROME_BETA: + list = getSync().getBookmarksFromChromeBeta(); + break; + case CHROME_DEV: + list = getSync().getBookmarksFromChromeDev(); + break; + default: + list = new ArrayList<>(0); + break; } int count = 0; - if (list != null && !list.isEmpty()) { + if (!list.isEmpty()) { mBookmarkManager.addBookmarkList(list); count = list.size(); } @@ -124,30 +147,28 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref public void onDestroy() { super.onDestroy(); mActivity = null; - if (mImportTaskReference != null) { - mImportTaskReference.cancel(false); - } } private void initPrefs() { - Preference exportpref = findPreference(SETTINGS_EXPORT); - Preference importpref = findPreference(SETTINGS_IMPORT); + Preference exportPref = findPreference(SETTINGS_EXPORT); + Preference importPref = findPreference(SETTINGS_IMPORT); + Preference deletePref = findPreference(SETTINGS_DELETE_BOOKMARKS); - exportpref.setOnPreferenceClickListener(this); - importpref.setOnPreferenceClickListener(this); + exportPref.setOnPreferenceClickListener(this); + importPref.setOnPreferenceClickListener(this); + deletePref.setOnPreferenceClickListener(this); - BrowserApp.getTaskThread().execute(mInitializeImportPreference); - } + BrowserApp.getTaskThread().execute(new Runnable() { + @Override + public void run() { + Preference importStock = findPreference(SETTINGS_IMPORT_BROWSER); + importStock.setEnabled(getSync().isBrowserImportSupported()); + importStock.setOnPreferenceClickListener(BookmarkSettingsFragment.this); + } + }); - private final Runnable mInitializeImportPreference = new Runnable() { - @Override - public void run() { - Preference importStock = findPreference(SETTINGS_IMPORT_BROWSER); - importStock.setEnabled(getSync().isStockSupported() || getSync().isChromeSupported()); - importStock.setOnPreferenceClickListener(BookmarkSettingsFragment.this); - } - }; + } @Override public boolean onPreferenceClick(@NonNull Preference preference) { @@ -182,14 +203,125 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref }); return true; case SETTINGS_IMPORT_BROWSER: - mImportTaskReference = new ImportBookmarksTask(getActivity()); - mImportTaskReference.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + getSync().getSupportedBrowsers().subscribeOn(Schedulers.worker()) + .observeOn(Schedulers.main()).subscribe(new OnSubscribe>() { + @Override + public void onNext(@Nullable List items) { + Activity activity = getActivity(); + if (items == null || activity == null) { + return; + } + List titles = buildTitleList(activity, items); + showChooserDialog(activity, titles); + } + }); + return true; + case SETTINGS_DELETE_BOOKMARKS: + showDeleteBookmarksDialog(); return true; default: return false; } } + private void showDeleteBookmarksDialog() { + Activity activity = getActivity(); + if (activity == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(R.string.action_delete); + builder.setMessage(R.string.action_delete_all_bookmarks); + builder.setNegativeButton(R.string.no, null); + builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mBookmarkManager.deleteAllBookmarks(); + } + }); + builder.show(); + } + + @NonNull + private List buildTitleList(@NonNull Activity activity, @NonNull List items) { + List titles = new ArrayList<>(); + String title; + for (Source source : items) { + switch (source) { + case STOCK: + titles.add(getString(R.string.stock_browser)); + break; + case CHROME_STABLE: + title = getTitle(activity, "com.android.chrome"); + if (title != null) { + titles.add(title); + } + break; + case CHROME_BETA: + title = getTitle(activity, "com.chrome.beta"); + if (title != null) { + titles.add(title); + } + break; + case CHROME_DEV: + title = getTitle(activity, "com.chrome.beta"); + if (title != null) { + titles.add(title); + } + break; + default: + break; + } + } + return titles; + } + + private void showChooserDialog(final Activity activity, List list) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + final ArrayAdapter adapter = new ArrayAdapter<>(activity, + android.R.layout.simple_list_item_1); + for (String title : list) { + adapter.add(title); + } + builder.setTitle(R.string.supported_browsers_title); + builder.setAdapter(adapter, new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + String title = adapter.getItem(which); + Source source = null; + if (title.equals(getString(R.string.stock_browser))) { + source = Source.STOCK; + } else if (title.equals(getTitle(activity, "com.android.chrome"))) { + source = Source.CHROME_STABLE; + } else if (title.equals(getTitle(activity, "com.android.beta"))) { + source = Source.CHROME_BETA; + } else if (title.equals(getTitle(activity, "com.android.dev"))) { + source = Source.CHROME_DEV; + } + if (source != null) { + new ImportBookmarksTask(activity, source).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + }); + builder.show(); + } + + @Nullable + private String getTitle(@NonNull Activity activity, @NonNull String packageName) { + PackageManager pm = activity.getPackageManager(); + try { + ApplicationInfo info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); + CharSequence title = pm.getApplicationLabel(info); + if (title != null) { + return title.toString(); + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } + private void loadFileList(@Nullable File path) { File file; if (path != null) { diff --git a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java index e34e8af..ccbb847 100644 --- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java +++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java @@ -308,7 +308,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { protected List doInBackground(String... arg0) { mIsExecuting = true; - List filter = new ArrayList<>(); + List filter = new ArrayList<>(5); String query = arg0[0]; try { query = SPACE_PATTERN.matcher(query).replaceAll("+"); diff --git a/app/src/main/java/acr/browser/lightning/react/Observable.java b/app/src/main/java/acr/browser/lightning/react/Observable.java index 89a0b8f..e9b06b7 100644 --- a/app/src/main/java/acr/browser/lightning/react/Observable.java +++ b/app/src/main/java/acr/browser/lightning/react/Observable.java @@ -144,7 +144,7 @@ public class Observable { private static class SubscriberImpl implements Subscriber { @Nullable private OnSubscribe mOnSubscribe; - @NonNull private Observable mObservable; + @NonNull private final Observable mObservable; private boolean mOnCompleteExecuted = false; public SubscriberImpl(@NonNull OnSubscribe onSubscribe, @NonNull Observable observable) { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index 2781900..a1d8c73 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -194,7 +194,7 @@ public class LightningWebClient extends WebViewClient { @NonNull private static List getAllSslErrorMessageCodes(@NonNull SslError error) { - List errorCodeMessageCodes = new ArrayList<>(); + List errorCodeMessageCodes = new ArrayList<>(1); if (error.hasError(SslError.SSL_DATE_INVALID)) { errorCodeMessageCodes.add(R.string.message_certificate_date_invalid); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 58e9c79..96fdbb7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -42,7 +42,7 @@ Block Images Allow sites to open new windows Enable Cookies - Import bookmarks from Browser + Import bookmarks from browser Text size Recommended Search Engine @@ -50,6 +50,8 @@ Use wide viewport Load pages in overview mode Restore lost tabs on start + Supported Browsers + Stock Browser No stock browser detected Supported stock browser detected Hide status bar while browsing @@ -230,4 +232,5 @@ Remove Identifying Headers Add to Homescreen Shortcut Added to Homescreen + Delete all bookmarks diff --git a/app/src/main/res/xml/preference_bookmarks.xml b/app/src/main/res/xml/preference_bookmarks.xml index afb06c8..348fcaf 100644 --- a/app/src/main/res/xml/preference_bookmarks.xml +++ b/app/src/main/res/xml/preference_bookmarks.xml @@ -4,12 +4,15 @@ + android:title="@string/export_bookmarks"/> + android:title="@string/import_backup"/> + android:title="@string/importbookmarks"/> + \ No newline at end of file