From 3c9cd73bf08a51559219df2c718458a67b85a95a Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 27 Aug 2015 16:47:55 +0200 Subject: [PATCH 1/5] Refactoring: Bookmarks as Fragment 1. Incognito mode in another process 2. Bookmarks as a Fragement using Otto 3. Initial bookmarks as fragment implementation --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 3 +- .../lightning/activity/BrowserActivity.java | 669 ++++-------------- .../lightning/activity/MainActivity.java | 5 + .../browser/lightning/bus/BookmarkEvents.java | 78 ++ .../browser/lightning/bus/BrowserEvents.java | 44 ++ .../browser/lightning/bus/BusProvider.java | 19 + .../controller/BrowserController.java | 2 +- .../lightning/database/BookmarkManager.java | 59 +- .../lightning/fragment/BookmarksFragment.java | 493 +++++++++++++ .../preference/PreferenceManager.java | 9 - .../lightning/utils/DownloadImageTask.java | 127 ++++ .../acr/browser/lightning/utils/Utils.java | 19 + .../browser/lightning/view/LightningView.java | 11 +- app/src/main/res/layout/activity_main.xml | 14 +- app/src/main/res/layout/bookmark_drawer.xml | 6 +- .../main/res/layout/dialog_edit_bookmark.xml | 29 + app/src/main/res/raw/default_bookmarks.dat | 5 + external/netcipher | 2 +- 19 files changed, 1001 insertions(+), 594 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java create mode 100644 app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java create mode 100644 app/src/main/java/acr/browser/lightning/bus/BusProvider.java create mode 100644 app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java create mode 100644 app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java create mode 100644 app/src/main/res/layout/dialog_edit_bookmark.xml create mode 100644 app/src/main/res/raw/default_bookmarks.dat diff --git a/app/build.gradle b/app/build.gradle index a0c6770..9cc5b1e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,6 +48,7 @@ dependencies { compile 'com.android.support:design:23.0.0' compile 'com.android.support:recyclerview-v7:23.0.0' compile 'org.jsoup:jsoup:1.8.1' + compile 'com.squareup:otto:1.3.8' // Only Lightning Plus needs the proxy libraries lightningPlusCompile 'net.i2p.android:client:0.7' lightningPlusCompile(project(':libnetcipher')) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1cc2031..8d8ec38 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -110,7 +110,8 @@ android:label="@string/app_name" android:launchMode="singleTask" android:theme="@style/Theme.DarkTheme" - android:windowSoftInputMode="stateHidden" > + android:windowSoftInputMode="stateHidden" + android:process=":incognito"> diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 3a5482b..0c55ee0 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -30,7 +30,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.MediaPlayer; import android.net.Uri; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -65,7 +64,6 @@ import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; -import android.view.animation.AccelerateInterpolator; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.DecelerateInterpolator; @@ -86,26 +84,26 @@ import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.VideoView; +import com.squareup.otto.Subscribe; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import acr.browser.lightning.R; +import acr.browser.lightning.bus.BookmarkEvents; +import acr.browser.lightning.bus.BrowserEvents; +import acr.browser.lightning.bus.BusProvider; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; @@ -133,9 +131,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private DrawerLayout mDrawerLayout; private FrameLayout mBrowserFrame; private FullscreenHolder mFullscreenContainer; - private ListView mDrawerListRight; private RecyclerView mDrawerListLeft; - private LinearLayout mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; + private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private RelativeLayout mSearchBar; // List @@ -147,12 +144,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Views private AnimatedProgressBar mProgressBar; private AutoCompleteTextView mSearch; - private ImageView mArrowImage, mBookmarkTitleImage, mBookmarkImage; + private ImageView mArrowImage; private VideoView mVideoView; private View mCustomView, mVideoProgressView; // Adapter - private BookmarkViewAdapter mBookmarkAdapter; private LightningViewAdapter mTabAdapter; private SearchAdapter mSearchAdapter; @@ -180,7 +176,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private PreferenceManager mPreferences; // Image - private Bitmap mDefaultVideoPoster, mWebpageBitmap, mFolderBitmap; + private Bitmap mDefaultVideoPoster, mWebpageBitmap; private final ColorDrawable mBackground = new ColorDrawable(); private Drawable mDeleteIcon, mRefreshIcon, mSearchIcon, mIcon; private DrawerArrowDrawable mArrowDrawable; @@ -196,7 +192,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - abstract boolean isIncognito(); + public abstract boolean isIncognito(); abstract void initializeTabs(); @@ -241,11 +237,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Drawer stutters otherwise mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); - mDrawerRight = (LinearLayout) findViewById(R.id.right_drawer); + mDrawerRight = (ViewGroup) findViewById(R.id.right_drawer); mDrawerRight.setLayerType(View.LAYER_TYPE_HARDWARE, null); - mDrawerListRight = (ListView) findViewById(R.id.right_drawer_list); - mBookmarkTitleImage = (ImageView) findViewById(R.id.starIcon); - mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon); tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); @@ -257,7 +250,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mDrawerLayout.setDrawerListener(new DrawerLocker()); mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme); - mFolderBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_folder, mDarkTheme); mHomepage = mPreferences.getHomepage(); @@ -283,11 +275,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } mDrawerListLeft.setAdapter(mTabAdapter); -// mDrawerListLeft.setOnItemClickListener(new DrawerItemClickListener()); -// mDrawerListLeft.setOnItemLongClickListener(new DrawerItemLongClickListener()); - - mDrawerListRight.setOnItemClickListener(new BookmarkItemClickListener()); - mDrawerListRight.setOnItemLongClickListener(new BookmarkItemLongClickListener()); mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext()); @@ -324,12 +311,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements setupFrameLayoutButton(R.id.action_back, R.id.icon_back); setupFrameLayoutButton(R.id.action_forward, R.id.icon_forward); - setupFrameLayoutButton(R.id.action_add_bookmark, R.id.icon_star); setupFrameLayoutButton(R.id.action_toggle_desktop, R.id.icon_desktop); setupFrameLayoutButton(R.id.action_reading, R.id.icon_reading); - mBookmarkImage = (ImageView) findViewById(R.id.icon_star); - // create the search EditText in the ToolBar mSearch = (AutoCompleteTextView) actionBar.getCustomView().findViewById(R.id.search); mUntitledTitle = getString(R.string.untitled); @@ -358,38 +342,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void run() { - mBookmarkManager = BookmarkManager.getInstance(mActivity.getApplicationContext()); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - if (mBookmarkList.isEmpty() && mPreferences.getDefaultBookmarks()) { - for (String[] array : BookmarkManager.DEFAULT_BOOKMARKS) { - HistoryItem bookmark = new HistoryItem(array[0], array[1]); - if (mBookmarkManager.addBookmark(bookmark)) { - mBookmarkList.add(bookmark); - } - } - Collections.sort(mBookmarkList, new BookmarkManager.SortIgnoreCase()); - mPreferences.setDefaultBookmarks(false); - } - mBookmarkAdapter = new BookmarkViewAdapter(mActivity, R.layout.bookmark_list_item, - mBookmarkList); - mDrawerListRight.setAdapter(mBookmarkAdapter); initializeSearchSuggestions(mSearch); } }).run(); - View view = findViewById(R.id.bookmark_back_button); - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mBookmarkManager == null) - return; - if (!mBookmarkManager.isRootFolder()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - } - } - }); - mDrawerLayout.setDrawerShadow(R.drawable.drawer_right_shadow, GravityCompat.END); mDrawerLayout.setDrawerShadow(R.drawable.drawer_left_shadow, GravityCompat.START); @@ -811,7 +768,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements return true; case R.id.action_add_bookmark: if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) { - addBookmark(mCurrentView.getTitle(), mCurrentView.getUrl()); + BusProvider.getInstance() + .post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(), + mCurrentView.getUrl())); } return true; case R.id.action_find: @@ -827,75 +786,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - /** - * refreshes the underlying list of the Bookmark adapter since the bookmark - * adapter doesn't always change when notifyDataChanged gets called. - */ - private void notifyBookmarkDataSetChanged() { - if (mBookmarkAdapter != null) - mBookmarkAdapter.notifyDataSetChanged(); - } - - private void addBookmark(String title, String url) { - HistoryItem bookmark = new HistoryItem(url, title); - if (mBookmarkManager.addBookmark(bookmark)) { - mBookmarkList.add(bookmark); - Collections.sort(mBookmarkList, new BookmarkManager.SortIgnoreCase()); - notifyBookmarkDataSetChanged(); - mSearchAdapter.refreshBookmarks(); - updateBookmarkIndicator(mCurrentView.getUrl()); - } - } - - private void setBookmarkDataSet(List items, boolean animate) { - mBookmarkList.clear(); - mBookmarkList.addAll(items); - notifyBookmarkDataSetChanged(); - final int resource; - if (mBookmarkManager.isRootFolder()) - resource = R.drawable.ic_action_star; - else - resource = R.drawable.ic_action_back; - - final Animation startRotation = new Animation() { - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - mBookmarkTitleImage.setRotationY(90 * interpolatedTime); - } - }; - final Animation finishRotation = new Animation() { - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - mBookmarkTitleImage.setRotationY((-90) + (90 * interpolatedTime)); - } - }; - startRotation.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationStart(Animation animation) { - } - - @Override - public void onAnimationEnd(Animation animation) { - mBookmarkTitleImage.setImageResource(resource); - mBookmarkTitleImage.startAnimation(finishRotation); - } - - @Override - public void onAnimationRepeat(Animation animation) { - } - }); - startRotation.setInterpolator(new AccelerateInterpolator()); - finishRotation.setInterpolator(new DecelerateInterpolator()); - startRotation.setDuration(250); - finishRotation.setDuration(250); - - if (animate) { - mBookmarkTitleImage.startAnimation(startRotation); - } else { - mBookmarkTitleImage.setImageResource(resource); - } - } - /** * method that shows a dialog asking what string the user wishes to search * for. It highlights the text entered. @@ -995,146 +885,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - private class BookmarkItemClickListener implements ListView.OnItemClickListener { - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (mBookmarkList.get(position).isFolder()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(mBookmarkList.get(position).getTitle(), true), true); - return; - } - if (mCurrentView != null) { - mCurrentView.loadUrl(mBookmarkList.get(position).getUrl()); - } - // keep any jank from happening when the drawer is closed after the - // URL starts to load - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - mDrawerLayout.closeDrawer(mDrawerRight); - } - }, 150); - } - } - - private class BookmarkItemLongClickListener implements ListView.OnItemLongClickListener { - - @Override - public boolean onItemLongClick(AdapterView arg0, View arg1, final int position, long arg3) { - longPressBookmarkLink(mBookmarkList.get(position).getUrl()); - return true; - } - - } - - /** - * Takes in the id of which bookmark was selected and shows a dialog that - * allows the user to rename and change the url of the bookmark - * - * @param id which id in the list was chosen - */ - private synchronized void editBookmark(final int id) { - final AlertDialog.Builder editBookmarkDialog = new AlertDialog.Builder(mActivity); - editBookmarkDialog.setTitle(R.string.title_edit_bookmark); - final EditText getTitle = new EditText(mActivity); - getTitle.setHint(R.string.hint_title); - getTitle.setText(mBookmarkList.get(id).getTitle()); - getTitle.setSingleLine(); - final EditText getUrl = new EditText(mActivity); - getUrl.setHint(R.string.hint_url); - getUrl.setText(mBookmarkList.get(id).getUrl()); - getUrl.setSingleLine(); - final AutoCompleteTextView getFolder = new AutoCompleteTextView(mActivity); - getFolder.setHint(R.string.folder); - getFolder.setText(mBookmarkList.get(id).getFolder()); - getFolder.setSingleLine(); - List folders = mBookmarkManager.getFolderTitles(); - ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, folders); - getFolder.setThreshold(1); - getFolder.setAdapter(suggestionsAdapter); - LinearLayout layout = new LinearLayout(mActivity); - layout.setOrientation(LinearLayout.VERTICAL); - int padding = Utils.dpToPx(10); - layout.setPadding(padding, padding, padding, padding); - layout.addView(getTitle); - layout.addView(getUrl); - layout.addView(getFolder); - editBookmarkDialog.setView(layout); - editBookmarkDialog.setPositiveButton(getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - HistoryItem item = new HistoryItem(); - String currentFolder = mBookmarkList.get(id).getFolder(); - item.setTitle(getTitle.getText().toString()); - item.setUrl(getUrl.getText().toString()); - item.setUrl(getUrl.getText().toString()); - item.setFolder(getFolder.getText().toString()); - mBookmarkManager.editBookmark(mBookmarkList.get(id), item); - - List list = mBookmarkManager.getBookmarksFromFolder(currentFolder, true); - if (list.isEmpty()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - } else { - setBookmarkDataSet(list, false); - } - - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - } - if (mCurrentView != null) { - updateBookmarkIndicator(mCurrentView.getUrl()); - } - } - }); - editBookmarkDialog.show(); - } - - /** - * Show a dialog to rename a folder - * - * @param id the position of the HistoryItem (folder) in the bookmark list - */ - private synchronized void renameFolder(final int id) { - final AlertDialog.Builder editFolderDialog = new AlertDialog.Builder(mActivity); - editFolderDialog.setTitle(R.string.title_rename_folder); - final EditText getTitle = new EditText(mActivity); - getTitle.setHint(R.string.hint_title); - getTitle.setText(mBookmarkList.get(id).getTitle()); - getTitle.setSingleLine(); - LinearLayout layout = new LinearLayout(mActivity); - layout.setOrientation(LinearLayout.VERTICAL); - int padding = Utils.dpToPx(10); - layout.setPadding(padding, padding, padding, padding); - layout.addView(getTitle); - editFolderDialog.setView(layout); - editFolderDialog.setPositiveButton(getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - String oldTitle = mBookmarkList.get(id).getTitle(); - String newTitle = getTitle.getText().toString(); - - mBookmarkManager.renameFolder(oldTitle, newTitle); - - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - } - if (mCurrentView != null) { - updateBookmarkIndicator(mCurrentView.getUrl()); - } - } - }); - editFolderDialog.show(); - } - /** * displays the WebView contained in the LightningView Also handles the * removal of previous views @@ -1196,7 +946,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } }, 150); - updateBookmarkIndicator(mWebView.getUrl()); + // Should update the bookmark status in BookmarksFragment + BusProvider.getInstance() + .post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); // new Handler().postDelayed(new Runnable() { // @Override @@ -1222,7 +974,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements source = intent.getExtras().getString("SOURCE"); } if (num == 1) { - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); } else if (url != null) { if (url.startsWith(Constants.FILE)) { Utils.showSnackbar(this, R.string.message_blocked_local); @@ -1233,6 +985,16 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } + private void loadUrlInCurrentView(final String url) { + if (mCurrentView == null) { + // This is a problem, probably an assert will be better than a return + return; + } + + mCurrentView.loadUrl(url); + BusProvider.getInstance().post(new BrowserEvents.CurrentPageUrl(url)); + } + @Override public void closeEmptyTab() { if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) { @@ -1405,11 +1167,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) { mDrawerLayout.closeDrawer(mDrawerLeft); } else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) { - if (!mBookmarkManager.isRootFolder()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - } else { - mDrawerLayout.closeDrawer(mDrawerRight); - } + BusProvider.getInstance() + .post(new BrowserEvents.UserPressedBack()); } else { if (mCurrentView != null) { Log.d(Constants.TAG, "onBackPressed"); @@ -1444,6 +1203,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } catch (IllegalArgumentException e) { e.printStackTrace(); } + + BusProvider.getInstance().unregister(busEventListener); } void saveOpenTabs() { @@ -1493,7 +1254,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mCurrentView.onResume(); } mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext()); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); initializePreferences(); for (int n = 0; n < mWebViewList.size(); n++) { if (mWebViewList.get(n) != null) { @@ -1508,6 +1268,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements IntentFilter filter = new IntentFilter(); filter.addAction(NETWORK_BROADCAST_ACTION); registerReceiver(mNetworkReceiver, filter); + + BusProvider.getInstance().register(busEventListener); } /** @@ -1522,7 +1284,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements query = query.trim(); mCurrentView.stopLoading(); if (mCurrentView != null) { - mCurrentView.loadUrl(UrlUtils.smartUrlFilter(query, true, searchUrl)); + loadUrlInCurrentView(UrlUtils.smartUrlFilter(query, true, searchUrl)); } } @@ -1722,163 +1484,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements }); } - public class BookmarkViewAdapter extends ArrayAdapter { - - final Context context; - List data = null; - final int layoutResourceId; - final Bitmap folderIcon; - - public BookmarkViewAdapter(Context context, int layoutResourceId, List data) { - super(context, layoutResourceId, data); - this.layoutResourceId = layoutResourceId; - this.context = context; - this.data = data; - this.folderIcon = mFolderBitmap; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - BookmarkViewHolder holder; - - if (row == null) { - LayoutInflater inflater = ((Activity) context).getLayoutInflater(); - row = inflater.inflate(layoutResourceId, parent, false); - - holder = new BookmarkViewHolder(); - holder.txtTitle = (TextView) row.findViewById(R.id.textBookmark); - holder.favicon = (ImageView) row.findViewById(R.id.faviconBookmark); - row.setTag(holder); - } else { - holder = (BookmarkViewHolder) row.getTag(); - } - - ViewCompat.jumpDrawablesToCurrentState(row); - - HistoryItem web = data.get(position); - holder.txtTitle.setText(web.getTitle()); - holder.favicon.setImageBitmap(mWebpageBitmap); - if (web.isFolder()) { - holder.favicon.setImageBitmap(this.folderIcon); - } else if (web.getBitmap() == null) { - getImage(holder.favicon, web); - } else { - holder.favicon.setImageBitmap(web.getBitmap()); - } - return row; - } - - class BookmarkViewHolder { - TextView txtTitle; - ImageView favicon; - } - } - - private void getImage(ImageView image, HistoryItem web) { - new DownloadImageTask(image, web).execute(web.getUrl()); - } - - private class DownloadImageTask extends AsyncTask { - - final ImageView bmImage; - final HistoryItem mWeb; - - public DownloadImageTask(ImageView bmImage, HistoryItem web) { - this.bmImage = bmImage; - this.mWeb = web; - } - - protected Bitmap doInBackground(String... urls) { - String url = urls[0]; - Bitmap mIcon = null; - // unique path for each url that is bookmarked. - String hash = String.valueOf(Utils.getDomainName(url).hashCode()); - File image = new File(mActivity.getCacheDir(), hash + ".png"); - String urldisplay; - try { - urldisplay = Utils.getProtocol(url) + getDomainName(url) + "/favicon.ico"; - } catch (URISyntaxException e) { - e.printStackTrace(); - urldisplay = "https://www.google.com/s2/favicons?domain_url=" + url; - } - // checks to see if the image exists - if (!image.exists()) { - FileOutputStream fos = null; - InputStream in = null; - try { - // if not, download it... - URL urlDownload = new URL(urldisplay); - HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - mIcon = BitmapFactory.decodeStream(in); - } - // ...and cache it - if (mIcon != null) { - fos = new FileOutputStream(image); - mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - Log.d(Constants.TAG, "Downloaded: " + urldisplay); - } - - } catch (Exception e) { - e.printStackTrace(); - } finally { - Utils.close(in); - Utils.close(fos); - } - } else { - // if it exists, retrieve it from the cache - mIcon = BitmapFactory.decodeFile(image.getPath()); - } - if (mIcon == null) { - InputStream in = null; - FileOutputStream fos = null; - try { - // if not, download it... - URL urlDownload = new URL("https://www.google.com/s2/favicons?domain_url=" - + url); - HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); - connection.setDoInput(true); - connection.connect(); - in = connection.getInputStream(); - - if (in != null) { - mIcon = BitmapFactory.decodeStream(in); - } - // ...and cache it - if (mIcon != null) { - fos = new FileOutputStream(image); - mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); - fos.flush(); - } - - } catch (Exception e) { - e.printStackTrace(); - } finally { - Utils.close(in); - Utils.close(fos); - } - } - if (mIcon == null) { - return mWebpageBitmap; - } else { - return mIcon; - } - } - - protected void onPostExecute(Bitmap result) { - Bitmap fav = Utils.padFavicon(result); - bmImage.setImageBitmap(fav); - mWeb.setBitmap(fav); - notifyBookmarkDataSetChanged(); - } - } - private static String getDomainName(String url) throws URISyntaxException { URI uri = new URI(url); String domain = uri.getHost(); @@ -1893,6 +1498,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (url == null || mSearch == null || mSearch.hasFocus()) { return; } + BusProvider.getInstance() + .post(new BrowserEvents.CurrentPageUrl(url)); if (shortUrl && !url.startsWith(Constants.FILE)) { switch (mPreferences.getUrlBoxContentChoice()) { case 0: // Default, show only the domain @@ -2006,7 +1613,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void run() { - mCurrentView.loadUrl(HistoryPage.getHistoryPage(mActivity)); + loadUrlInCurrentView(HistoryPage.getHistoryPage(mActivity)); mSearch.setText(""); } @@ -2494,12 +2101,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements longPressHistoryLink(newUrl); } } else if (currentUrl.endsWith(BookmarkPage.FILENAME)) { + /* TODO Wtf is this? if (url != null) { longPressBookmarkLink(url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); longPressBookmarkLink(newUrl); - } + } */ } } else { if (url != null) { @@ -2523,103 +2131,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - private void longPressFolder(String url) { - String title; - if (url.startsWith(Constants.FILE)) { - // We are getting the title from the url - // Strip '-bookmarks.html' from the end of the url - title = url.substring(0, url.length() - BookmarkPage.FILENAME.length() - 1); - - // Strip the beginning of the url off and leave only the title - title = title.substring(Constants.FILE.length() + mActivity.getFilesDir().toString().length() + 1); - } else if (url.startsWith(Constants.FOLDER)) { - title = url.substring(Constants.FOLDER.length()); - } else { - title = url; - } - final int position = BookmarkManager.getIndexOfBookmark(mBookmarkList, Constants.FOLDER + title); - if (position == -1) { - return; - } - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - renameFolder(position); - break; - - case DialogInterface.BUTTON_NEGATIVE: - mBookmarkManager.deleteFolder(mBookmarkList.get(position).getTitle()); - - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - } - if (mCurrentView != null) { - updateBookmarkIndicator(mCurrentView.getUrl()); - } - break; - } - } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - builder.setTitle(R.string.action_folder) - .setMessage(R.string.dialog_folder) - .setCancelable(true) - .setPositiveButton(R.string.action_rename, dialogClickListener) - .setNegativeButton(R.string.action_delete, dialogClickListener) - .show(); - } - - private void longPressBookmarkLink(final String url) { - if (url.startsWith(Constants.FILE) || url.startsWith(Constants.FOLDER)) { - longPressFolder(url); - return; - } - final int position = BookmarkManager.getIndexOfBookmark(mBookmarkList, url); - if (position == -1) { - return; - } - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - newTab(mBookmarkList.get(position).getUrl(), false); - mDrawerLayout.closeDrawers(); - break; - case DialogInterface.BUTTON_NEGATIVE: - if (mBookmarkManager.deleteBookmark(mBookmarkList.get(position))) { - mBookmarkList.remove(position); - notifyBookmarkDataSetChanged(); - mSearchAdapter.refreshBookmarks(); - openBookmarks(); - if (mCurrentView != null) { - updateBookmarkIndicator(mCurrentView.getUrl()); - } - } - break; - case DialogInterface.BUTTON_NEUTRAL: - editBookmark(position); - break; - } - } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - builder.setTitle(R.string.action_bookmarks) - .setMessage(R.string.dialog_bookmark) - .setCancelable(true) - .setPositiveButton(R.string.action_new_tab, dialogClickListener) - .setNegativeButton(R.string.action_delete, dialogClickListener) - .setNeutralButton(R.string.action_edit, dialogClickListener) - .show(); - } - private void longPressHistoryLink(final String url) { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override @@ -2637,7 +2148,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements case DialogInterface.BUTTON_NEUTRAL: if (mCurrentView != null) { - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); } break; } @@ -2664,7 +2175,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements break; case DialogInterface.BUTTON_NEGATIVE: - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); break; case DialogInterface.BUTTON_NEUTRAL: @@ -2697,7 +2208,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements break; case DialogInterface.BUTTON_NEGATIVE: - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); break; case DialogInterface.BUTTON_NEUTRAL: @@ -2758,17 +2269,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - @Override - public void updateBookmarkIndicator(String url) { - if (url == null || !mBookmarkManager.isBookmark(url)) { - mBookmarkImage.setImageResource(R.drawable.ic_action_star); - mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); - } else { - mBookmarkImage.setImageResource(R.drawable.ic_bookmark); - mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(this), PorterDuff.Mode.SRC_IN); - } - } - @Override public void onClick(View v) { switch (v.getId()) { @@ -2820,11 +2320,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mCurrentView.reload(); closeDrawers(); break; - case R.id.action_add_bookmark: - if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) { - addBookmark(mCurrentView.getTitle(), mCurrentView.getUrl()); - } - break; } } @@ -2870,4 +2365,84 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements PermissionsManager.getInstance().notifyPermissionsChange(permissions); super.onRequestPermissionsResult(requestCode, permissions, grantResults); } + + private final Object busEventListener = new Object() { + /** + * Load the given bookmark in the current tab, used by the the + * {@link acr.browser.lightning.fragment.BookmarksFragment} + * @param event The event as it comes from the bus + */ + @Subscribe + public void loadBookmarkInCurrentTab(final BookmarkEvents.Clicked event) { + loadUrlInCurrentView(event.bookmark.getUrl()); + // keep any jank from happening when the drawer is closed after the + // URL starts to load + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + mDrawerLayout.closeDrawer(mDrawerRight); + } + }, 150); + } + + /** + * Load the given bookmark in a new tab, used by the the + * {@link acr.browser.lightning.fragment.BookmarksFragment} + * @param event The event as it comes from the bus + */ + @Subscribe + public void loadBookmarkInNewTab(final BookmarkEvents.AsNewTab event) { + newTab(event.bookmark.getUrl(), true); + mDrawerLayout.closeDrawers(); + } + + /** + * When receive a {@link acr.browser.lightning.bus.BookmarkEvents.WantToBookmarkCurrentPage} + * message this receiver answer firing the + * {@link acr.browser.lightning.bus.BrowserEvents.AddBookmark} message + * + * @param event basically a marker + */ + @Subscribe + public void bookmarkCurrentPage(final BookmarkEvents.WantToBookmarkCurrentPage event) { + BusProvider.getInstance() + .post(new BrowserEvents + .AddBookmark(mCurrentView.getTitle(), mCurrentView.getUrl())); + } + + /** + * This message is received when a bookmark was added by the + * {@link acr.browser.lightning.fragment.BookmarksFragment} + * + * @param event a marker + */ + @Subscribe + public void bookmarkAdded(final BookmarkEvents.Added event) { + mSearchAdapter.refreshBookmarks(); + } + + /** + * Notify the browser that a bookmark was deleted + * + * @param event + */ + @Subscribe + public void bookmarkDeleted(final BookmarkEvents.Deleted event) { + BusProvider.getInstance() + .post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); + } + + /** + * The {@link acr.browser.lightning.fragment.BookmarksFragment} send this message on reply + * to {@link acr.browser.lightning.bus.BrowserEvents.UserPressedBack} message if the + * fragement is showing the boomarks root folder. + * + * @param event a marker + */ + @Subscribe + public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) { + mDrawerLayout.closeDrawer(mDrawerRight); + } + }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java index 32a867d..7234951 100644 --- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java @@ -6,7 +6,10 @@ import android.view.Menu; import android.webkit.CookieManager; import android.webkit.CookieSyncManager; +import com.squareup.otto.Subscribe; + import acr.browser.lightning.R; +import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.preference.PreferenceManager; @SuppressWarnings("deprecation") @@ -60,4 +63,6 @@ public class MainActivity extends BrowserActivity { closeDrawers(); moveTaskToBack(true); } + + } diff --git a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java new file mode 100644 index 0000000..8e60c47 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java @@ -0,0 +1,78 @@ +package acr.browser.lightning.bus; + +import acr.browser.lightning.database.HistoryItem; + +/** + * Created by Stefano Pacifici on 26/08/15. + */ +public final class BookmarkEvents { + + private BookmarkEvents() { + // No instances + } + + /** + * A bookmark was clicked + */ + public final static class Clicked { + public final HistoryItem bookmark; + + public Clicked(final HistoryItem bookmark) { + this.bookmark = bookmark; + } + } + + /** + * The user ask to open the bookmark as new tab + */ + public final static class AsNewTab { + public final HistoryItem bookmark; + + public AsNewTab(final HistoryItem bookmark) { + this.bookmark = bookmark; + } + } + + /** + * The user ask to delete the selected bookmark + */ + public static class Deleted { + public final HistoryItem item; + + public Deleted(final HistoryItem item) { + this.item = item; + } + } + + /** + * The user ask to bookmark the currently displayed page + */ + public static class WantToBookmarkCurrentPage { + } + + /** + * The bookmark was added + */ + public static class Added { + public final HistoryItem item; + + public Added(final HistoryItem item) { + this.item = item; + } + } + + /** + * The {@link acr.browser.lightning.fragment.BookmarksFragment} want to know the url (and title) + * of the currently shown web page. + */ + public static class WantInfoAboutCurrentPage { + } + + /** + * Sended by the {@link acr.browser.lightning.fragment.BookmarksFragment} when it wants to close + * itself (generally in reply to a {@link acr.browser.lightning.bus.BrowserEvents.UserPressedBack} + * event. + */ + public static class CloseBookmarks { + } +} diff --git a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java new file mode 100644 index 0000000..15ff373 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -0,0 +1,44 @@ +package acr.browser.lightning.bus; + +/** + * Created by Stefano Pacifici on 26/08/15. + */ +public final class BrowserEvents { + + private BrowserEvents() { + // No instances + } + + /** + * Used to reply to the {@link acr.browser.lightning.fragment.BookmarksFragment} message + * {@link acr.browser.lightning.bus.BookmarkEvents.WantToBookmarkCurrentPage}. The interaction + * result is a new bookmark added. + */ + public static class AddBookmark { + public final String title, url; + + public AddBookmark(final String title, final String url) { + this.title = title; + this.url = url; + } + } + + /** + * Used to reply to {@link acr.browser.lightning.fragment.BookmarksFragment} message + * {@link acr.browser.lightning.bus.BookmarkEvents.WantInfoAboutCurrentPage}. This is generally + * used to update the {@link acr.browser.lightning.fragment.BookmarksFragment} interface. + */ + public static class CurrentPageUrl { + public final String url; + + public CurrentPageUrl(final String url) { + this.url = url; + } + } + + /** + * Notify the BookmarksFragment and TabsFragment that the user pressed the back button + */ + public static class UserPressedBack { + } +} diff --git a/app/src/main/java/acr/browser/lightning/bus/BusProvider.java b/app/src/main/java/acr/browser/lightning/bus/BusProvider.java new file mode 100644 index 0000000..530b183 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/BusProvider.java @@ -0,0 +1,19 @@ +package acr.browser.lightning.bus; + +import com.squareup.otto.Bus; + +/** + * Created by Stefano Pacifici on 25/08/15. + */ +public class BusProvider { + + private static final Bus bus = new Bus(); + + public static Bus getInstance() { + return bus; + } + + private BusProvider() { + // No instances + } +} diff --git a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java index b5d6afa..21750a8 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -56,6 +56,6 @@ public interface BrowserController { boolean proxyIsNotReady(); - void updateBookmarkIndicator(String url); + // void updateBookmarkIndicator(String url); } 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 87f4be4..fb6f0a9 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -6,6 +6,7 @@ import android.database.Cursor; import android.os.Environment; import android.provider.Browser; import android.support.annotation.NonNull; +import android.util.Log; import org.json.JSONException; import org.json.JSONObject; @@ -13,9 +14,12 @@ import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -32,6 +36,8 @@ import acr.browser.lightning.utils.Utils; public class BookmarkManager { + private static final String TAG = BookmarkManager.class.getSimpleName(); + private final Context mContext; private static final String TITLE = "title"; private static final String URL = "url"; @@ -251,24 +257,36 @@ public class BookmarkManager { * @return returns a list of bookmarks that can be sorted */ public synchronized List getAllBookmarks(boolean sort) { - List bookmarks = new ArrayList<>(); - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); + final List bookmarks = new ArrayList<>(); + final File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); + BufferedReader bookmarksReader = null; try { - bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); + final InputStream inputStream; + if (bookmarksFile.exists() && bookmarksFile.isFile()) { + inputStream = new FileInputStream(bookmarksFile); + } else { + inputStream = mContext.getResources().openRawResource(R.raw.default_bookmarks); + } + bookmarksReader = + new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = bookmarksReader.readLine()) != null) { - JSONObject object = new JSONObject(line); - HistoryItem item = new HistoryItem(); - item.setTitle(object.getString(TITLE)); - item.setUrl(object.getString(URL)); - item.setFolder(object.getString(FOLDER)); - item.setOrder(object.getInt(ORDER)); - item.setImageId(R.drawable.ic_bookmark); - bookmarks.add(item); - } - } catch (IOException | JSONException e) { - e.printStackTrace(); + try { + JSONObject object = new JSONObject(line); + HistoryItem item = new HistoryItem(); + item.setTitle(object.getString(TITLE)); + item.setUrl(object.getString(URL)); + item.setFolder(object.getString(FOLDER)); + item.setOrder(object.getInt(ORDER)); + item.setImageId(R.drawable.ic_bookmark); + bookmarks.add(item); + } catch (JSONException e) { + Log.e(TAG, "Can't parse line " + line, e); + } + } + } catch (IOException e) { + Log.e(TAG, "Error reading the bookmarks file", e); } finally { Utils.close(bookmarksReader); } @@ -498,17 +516,4 @@ public class BookmarkManager { } } - - private static final String[] DEV = {"https://twitter.com/RestainoAnthony", "The Developer"}; - private static final String[] FACEBOOK = {"https://www.facebook.com/", "Facebook"}; - private static final String[] TWITTER = {"https://twitter.com", "Twitter"}; - private static final String[] GOOGLE = {"https://www.google.com/", "Google"}; - private static final String[] YAHOO = {"https://www.yahoo.com/", "Yahoo"}; - public static final String[][] DEFAULT_BOOKMARKS = { - DEV, - FACEBOOK, - TWITTER, - GOOGLE, - YAHOO - }; } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java new file mode 100644 index 0000000..2367c15 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -0,0 +1,493 @@ +package acr.browser.lightning.fragment; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.IdRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Transformation; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemLongClickListener; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; + +import com.squareup.otto.Bus; +import com.squareup.otto.Subscribe; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import acr.browser.lightning.R; +import acr.browser.lightning.activity.BrowserActivity; +import acr.browser.lightning.bus.BookmarkEvents; +import acr.browser.lightning.bus.BrowserEvents; +import acr.browser.lightning.bus.BusProvider; +import acr.browser.lightning.database.BookmarkManager; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.preference.PreferenceManager; +import acr.browser.lightning.utils.DownloadImageTask; +import acr.browser.lightning.utils.ThemeUtils; +import acr.browser.lightning.utils.Utils; + +import static android.support.v7.app.AlertDialog.Builder; + +/** + * Created by Stefano Pacifici on 25/08/15. Based on Anthony C. Restaino's code. + */ +public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { + + // Managers + private BookmarkManager mBookmarkManager; + + // Adapter + private BookmarkViewAdapter mBookmarkAdapter; + + // Preloaded images + private Bitmap mWebpageBitmap, mFolderBitmap; + + // Bookmarks + private List mBookmarks = new ArrayList<>(); + + // Views + private ListView mBookmarksListView; + private ImageView mBookmarkTitleImage, mBookmarkImage; + + // Colors + private int mIconColor; + + // Init asynchronously the bookmark manager + private final Runnable initBookmarkManager = new Runnable() { + @Override + public void run() { + final Context context = getContext(); + mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext()); + mBookmarkAdapter = new BookmarkViewAdapter(context, mBookmarks); + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + mBookmarksListView.setAdapter(mBookmarkAdapter); + } + }; + + // Handle bookmark click + private final OnItemClickListener itemClickListener = new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + final HistoryItem item = mBookmarks.get(position); + if (item.isFolder()) { + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), + true); + } else { + BusProvider.getInstance().post(new BookmarkEvents.Clicked(item)); + } + } + }; + + private final OnItemLongClickListener itemLongClickListener = new OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { + final HistoryItem item = mBookmarks.get(position); + handleLongPress(item, position); + return true; + } + }; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.bookmark_drawer, container, false); + mBookmarksListView = (ListView) view.findViewById(R.id.right_drawer_list); + mBookmarksListView.setOnItemClickListener(itemClickListener); + mBookmarksListView.setOnItemLongClickListener(itemLongClickListener); + mBookmarkTitleImage = (ImageView) view.findViewById(R.id.starIcon); + mBookmarkImage = (ImageView) view.findViewById(R.id.icon_star); + final View backView = view.findViewById(R.id.bookmark_back_button); + backView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mBookmarkManager == null) + return; + if (!mBookmarkManager.isRootFolder()) { + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); + } + } + }); + + // Must be called here, only here we have a reference to the ListView + new Thread(initBookmarkManager).run(); + return view; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + // TODO this code depend way too much on BrowserActivity + super.onActivityCreated(savedInstanceState); + final BrowserActivity activity = (BrowserActivity) getActivity(); + final PreferenceManager preferenceManager =PreferenceManager.getInstance(); + boolean darkTheme = preferenceManager.getUseTheme() != 0 || activity.isIncognito(); + mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme); + mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme); + mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) : + ThemeUtils.getIconLightThemeColor(activity); + setupFrameLayoutButton(getView(), R.id.action_add_bookmark, R.id.icon_star); + mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); + } + + @Override + public void onStart() { + super.onStart(); + BusProvider.getInstance().register(this); + } + + @Override + public void onStop() { + super.onStop(); + BusProvider.getInstance().unregister(this); + } + + @Subscribe + public void addBookmark(final BrowserEvents.AddBookmark event) { + final HistoryItem item = new HistoryItem(event.url, event.title); + if (mBookmarkManager.addBookmark(item)) { + mBookmarks.add(item); + Collections.sort(mBookmarks, new BookmarkManager.SortIgnoreCase()); + mBookmarkAdapter.notifyDataSetChanged(); + BusProvider.getInstance() + .post(new BookmarkEvents.Added(item)); + updateBookmarkIndicator(event.url); + } + } + + @Subscribe + public void currentPageInfo(final BrowserEvents.CurrentPageUrl event) { + updateBookmarkIndicator(event.url); + } + + private void updateBookmarkIndicator(final String url) { + if (!mBookmarkManager.isBookmark(url)) { + mBookmarkImage.setImageResource(R.drawable.ic_action_star); + mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); + } else { + mBookmarkImage.setImageResource(R.drawable.ic_bookmark); + mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(getContext()), PorterDuff.Mode.SRC_IN); + } + } + + @Subscribe + public void userPressedBack(final BrowserEvents.UserPressedBack event) { + if (mBookmarkManager.isRootFolder()) { + BusProvider.getInstance() + .post(new BookmarkEvents.CloseBookmarks()); + } else { + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); + } + } + + private void setBookmarkDataSet(List items, boolean animate) { + mBookmarks.clear(); + mBookmarks.addAll(items); + mBookmarkAdapter.notifyDataSetChanged(); + final int resource; + if (mBookmarkManager.isRootFolder()) + resource = R.drawable.ic_action_star; + else + resource = R.drawable.ic_action_back; + + final Animation startRotation = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + mBookmarkTitleImage.setRotationY(90 * interpolatedTime); + } + }; + final Animation finishRotation = new Animation() { + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + mBookmarkTitleImage.setRotationY((-90) + (90 * interpolatedTime)); + } + }; + startRotation.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + } + + @Override + public void onAnimationEnd(Animation animation) { + mBookmarkTitleImage.setImageResource(resource); + mBookmarkTitleImage.startAnimation(finishRotation); + } + + @Override + public void onAnimationRepeat(Animation animation) { + } + }); + startRotation.setInterpolator(new AccelerateInterpolator()); + finishRotation.setInterpolator(new DecelerateInterpolator()); + startRotation.setDuration(250); + finishRotation.setDuration(250); + + if (animate) { + mBookmarkTitleImage.startAnimation(startRotation); + } else { + mBookmarkTitleImage.setImageResource(resource); + } + } + + // TODO this is basically a copy/paste from BrowserActivity, should be changed + private void setupFrameLayoutButton(@NonNull View view, @IdRes int buttonId, @IdRes int imageId) { + FrameLayout frameButton = (FrameLayout) view.findViewById(buttonId); + frameButton.setOnClickListener(this); + frameButton.setOnLongClickListener(this); + ImageView buttonImage = (ImageView) view.findViewById(imageId); + buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); + } + + private void handleLongPress(final HistoryItem item, final int position) { + if (item.isFolder()) { + longPressFolder(item, position); + return; + } else { + final Bus bus = BusProvider.getInstance(); + final DialogInterface.OnClickListener dialogClickListener = + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + bus.post(new BookmarkEvents.AsNewTab(item)); + break; + case DialogInterface.BUTTON_NEGATIVE: + if (mBookmarkManager.deleteBookmark(item)) { + mBookmarks.remove(position); + mBookmarkAdapter.notifyDataSetChanged(); + bus.post(new BookmarkEvents.Deleted(item)); + } + break; + case DialogInterface.BUTTON_NEUTRAL: + editBookmark(item, position); + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(R.string.action_bookmarks) + .setMessage(R.string.dialog_bookmark) + .setCancelable(true) + .setPositiveButton(R.string.action_new_tab, dialogClickListener) + .setNegativeButton(R.string.action_delete, dialogClickListener) + .setNeutralButton(R.string.action_edit, dialogClickListener) + .show(); + } + } + + private void longPressFolder(final HistoryItem item, final int position) { + final DialogInterface.OnClickListener dialogClickListener = + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + renameFolder(item, position); + break; + + case DialogInterface.BUTTON_NEGATIVE: + mBookmarkManager.deleteFolder(item.getTitle()); + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + BusProvider.getInstance().post(new BookmarkEvents.Deleted(item)); + /* TODO Restore Bookmarkpage + if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) + && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { + openBookmarkPage(mWebView); + }*/ + break; + } + } + }; + + Builder builder = new Builder(getContext()); + builder.setTitle(R.string.action_folder) + .setMessage(R.string.dialog_folder) + .setCancelable(true) + .setPositiveButton(R.string.action_rename, dialogClickListener) + .setNegativeButton(R.string.action_delete, dialogClickListener) + .show(); + } + + /** + * Takes in the id of which bookmark was selected and shows a dialog that + * allows the user to rename and change the url of the bookmark + * + * @param item the bookmark + * @param position the position inside the adapter + */ + private synchronized void editBookmark(final HistoryItem item, final int position) { + final Builder editBookmarkDialog = new Builder(getContext()); + editBookmarkDialog.setTitle(R.string.title_edit_bookmark); + final View dialogLayout = View.inflate(getContext(), R.layout.dialog_edit_bookmark, null); + final EditText getTitle = (EditText) dialogLayout.findViewById(R.id.bookmark_title); + getTitle.setText(item.getTitle()); + final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url); + getUrl.setText(item.getUrl()); + final AutoCompleteTextView getFolder = + (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); + getFolder.setHint(R.string.folder); + getFolder.setText(item.getFolder()); + final List folders = mBookmarkManager.getFolderTitles(); + final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(getContext(), + android.R.layout.simple_dropdown_item_1line, folders); + getFolder.setThreshold(1); + getFolder.setAdapter(suggestionsAdapter); + editBookmarkDialog.setView(dialogLayout); + editBookmarkDialog.setPositiveButton(getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + HistoryItem editedItem = new HistoryItem(); + String currentFolder = item.getFolder(); + editedItem.setTitle(getTitle.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setFolder(getFolder.getText().toString()); + mBookmarkManager.editBookmark(item, editedItem); + + List list = mBookmarkManager.getBookmarksFromFolder(currentFolder, true); + if (list.isEmpty()) { + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); + } else { + setBookmarkDataSet(list, false); + } + BusProvider.getInstance() + .post(new BookmarkEvents.WantInfoAboutCurrentPage()); + /* TODO Restore BookmarkPage + if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) + && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { + openBookmarkPage(mWebView); + }*/ + } + }); + editBookmarkDialog.show(); + } + + /** + * Show a dialog to rename a folder + * + * @param id the position of the HistoryItem (folder) in the bookmark list + */ + private synchronized void renameFolder(final HistoryItem item, final int id) { + final Context context = getContext(); + final Builder editFolderDialog = new Builder(context); + editFolderDialog.setTitle(R.string.title_rename_folder); + final EditText getTitle = new EditText(context); + getTitle.setHint(R.string.hint_title); + getTitle.setText(item.getTitle()); + getTitle.setSingleLine(); + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + int padding = Utils.dpToPx(10); + layout.setPadding(padding, padding, padding, padding); + layout.addView(getTitle); + editFolderDialog.setView(layout); + editFolderDialog.setPositiveButton(getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + String oldTitle = item.getTitle(); + String newTitle = getTitle.getText().toString(); + + mBookmarkManager.renameFolder(oldTitle, newTitle); + + setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + /* TODO Restore Bookmarkpage + if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) + && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { + openBookmarkPage(mWebView); + }*/ + } + }); + editFolderDialog.show(); + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.action_add_bookmark: + BusProvider.getInstance().post(new BookmarkEvents.WantToBookmarkCurrentPage()); + break; + default: + break; + } + } + + @Override + public boolean onLongClick(View v) { + return false; + } + + private class BookmarkViewAdapter extends ArrayAdapter { + + final Context context; + + public BookmarkViewAdapter(Context context, List data) { + super(context, R.layout.bookmark_list_item, data); + this.context = context; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View row = convertView; + BookmarkViewHolder holder; + + if (row == null) { + LayoutInflater inflater = LayoutInflater.from(context); + row = inflater.inflate(R.layout.bookmark_list_item, parent, false); + + holder = new BookmarkViewHolder(); + holder.txtTitle = (TextView) row.findViewById(R.id.textBookmark); + holder.favicon = (ImageView) row.findViewById(R.id.faviconBookmark); + row.setTag(holder); + } else { + holder = (BookmarkViewHolder) row.getTag(); + } + + ViewCompat.jumpDrawablesToCurrentState(row); + + HistoryItem web = mBookmarks.get(position); + holder.txtTitle.setText(web.getTitle()); + holder.favicon.setImageBitmap(mWebpageBitmap); + if (web.isFolder()) { + holder.favicon.setImageBitmap(mFolderBitmap); + } else if (web.getBitmap() == null) { + new DownloadImageTask(holder.favicon, web, mWebpageBitmap).execute(); + } else { + holder.favicon.setImageBitmap(web.getBitmap()); + } + return row; + } + + class BookmarkViewHolder { + TextView txtTitle; + ImageView favicon; + } + } + +} diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index d2aa0c2..2f93a6e 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -44,7 +44,6 @@ public class PreferenceManager { public static final String INVERT_COLORS = "invertColors"; public static final String READING_TEXT_SIZE = "readingTextSize"; public static final String THEME = "Theme"; - public static final String DEFAULT_BOOKMARKS = "defaultBookmarks"; public static final String TEXT_ENCODING = "textEncoding"; public static final String CLEAR_WEBSTORAGE_EXIT = "clearWebStorageExit"; public static final String SHOW_TABS_IN_DRAWER = "showTabsInDrawer"; @@ -117,10 +116,6 @@ public class PreferenceManager { return mPrefs.getBoolean(Name.COOKIES, true); } - public boolean getDefaultBookmarks() { - return mPrefs.getBoolean(Name.DEFAULT_BOOKMARKS, true); - } - public String getDownloadDirectory() { return mPrefs.getString(Name.DOWNLOAD_DIRECTORY, Environment.DIRECTORY_DOWNLOADS); } @@ -317,10 +312,6 @@ public class PreferenceManager { putBoolean(Name.COOKIES, enable); } - public void setDefaultBookmarks(boolean show) { - putBoolean(Name.DEFAULT_BOOKMARKS, show); - } - public void setDownloadDirectory(String directory) { putString(Name.DOWNLOAD_DIRECTORY, directory); } diff --git a/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java b/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java new file mode 100644 index 0000000..5bca4a6 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java @@ -0,0 +1,127 @@ +package acr.browser.lightning.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.AsyncTask; +import android.support.annotation.NonNull; +import android.util.Log; +import android.widget.ImageView; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URISyntaxException; +import java.net.URL; + +import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.database.HistoryItem; + +/** + * Created by Stefano Pacifici on 25/08/15. + */ +public class DownloadImageTask extends AsyncTask { + + final ImageView bmImage; + final HistoryItem mWeb; + final File mCacheDir; + final String mUrl; + final Bitmap mDefaultBitmap; + + public DownloadImageTask(@NonNull ImageView bmImage, @NonNull HistoryItem web, + @NonNull Bitmap defaultBitmap) { + assert bmImage != null; + assert web != null; + assert defaultBitmap != null; + this.bmImage = bmImage; + this.mWeb = web; + this.mCacheDir = bmImage.getContext().getCacheDir(); + this.mUrl = web.getUrl(); + this.mDefaultBitmap = defaultBitmap; + } + + protected Bitmap doInBackground(Void... params) { + Bitmap mIcon = null; + // unique path for each url that is bookmarked. + final Uri uri = Uri.parse(mUrl); + + final String hash = "" + Utils.hash(uri.getHost()); + final File image = new File(mCacheDir, hash + ".png"); + final Uri urldisplay = Uri.fromParts(uri.getScheme(), uri.getHost(), "favicon.ico"); + // checks to see if the image exists + if (!image.exists()) { + FileOutputStream fos = null; + InputStream in = null; + try { + // if not, download it... + final URL urlDownload = new URL(urldisplay.toString()); + final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); + connection.setDoInput(true); + connection.connect(); + in = connection.getInputStream(); + + if (in != null) { + mIcon = BitmapFactory.decodeStream(in); + } + // ...and cache it + if (mIcon != null) { + fos = new FileOutputStream(image); + mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.flush(); + Log.d(Constants.TAG, "Downloaded: " + urldisplay); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + Utils.close(in); + Utils.close(fos); + } + } else { + // if it exists, retrieve it from the cache + mIcon = BitmapFactory.decodeFile(image.getPath()); + } + if (mIcon == null) { + InputStream in = null; + FileOutputStream fos = null; + try { + // if not, download it... + final URL urlDownload = new URL("https://www.google.com/s2/favicons?domain_url=" + + uri.toString()); + final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection(); + connection.setDoInput(true); + connection.connect(); + in = connection.getInputStream(); + + if (in != null) { + mIcon = BitmapFactory.decodeStream(in); + } + // ...and cache it + if (mIcon != null) { + fos = new FileOutputStream(image); + mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos); + fos.flush(); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + Utils.close(in); + Utils.close(fos); + } + } + if (mIcon == null) { + return mDefaultBitmap; + } else { + return mIcon; + } + } + + protected void onPostExecute(Bitmap result) { + final Bitmap fav = Utils.padFavicon(result); + bmImage.setImageBitmap(fav); + mWeb.setBitmap(fav); + // notifyBookmarkDataSetChanged(); + } +} diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 837bdeb..4825c1b 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -34,8 +34,11 @@ import android.webkit.URLUtil; import java.io.Closeable; import java.io.File; import java.io.IOException; +import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; @@ -309,4 +312,20 @@ public final class Utils { canvas.drawPath(wallpath, paint); } + /** + * Calculate the SHA-1 hash of the given string + * @param str the string to hash + * @return the long representation of the hash + */ + public static long hash(final String str) { + try { + final MessageDigest digest = MessageDigest.getInstance("SHA-1"); + final byte[] bytes = digest.digest(str.getBytes()); + final BigInteger intRepr = new BigInteger(bytes); + return intRepr.longValue(); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.TAG, "The device has not SHA-1 support", e); + return 0; + } + } } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index e7d06c0..1511aec 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -56,6 +56,8 @@ import java.io.IOException; import java.net.URISyntaxException; import acr.browser.lightning.R; +import acr.browser.lightning.bus.BrowserEvents; +import acr.browser.lightning.bus.BusProvider; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.controller.BrowserController; @@ -98,6 +100,7 @@ public class LightningView { private PermissionsManager mPermissionsManager; private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; + @SuppressLint("NewApi") public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) { mActivity = activity; @@ -175,6 +178,7 @@ public class LightningView { * if you don't have a reference to them * @param context the context in which the WebView was created */ + @SuppressLint("NewApi") public synchronized void initializePreferences(@Nullable WebSettings settings, Context context) { if (settings == null && mWebView == null) { return; @@ -293,6 +297,7 @@ public class LightningView { * @param settings the WebSettings object to use. * @param context the Context which was used to construct the WebView. */ + @SuppressLint("NewApi") private void initializeSettings(WebSettings settings, Context context) { if (API < Build.VERSION_CODES.JELLY_BEAN_MR2) { settings.setAppCacheMaxSize(Long.MAX_VALUE); @@ -347,6 +352,7 @@ public class LightningView { mToggleDesktop = !mToggleDesktop; } + @SuppressLint("NewApi") public void setUserAgent(Context context, int choice) { if (mWebView == null) return; WebSettings settings = mWebView.getSettings(); @@ -526,6 +532,7 @@ public class LightningView { } } + @SuppressLint("NewApi") public synchronized void find(String text) { if (mWebView != null) { if (API >= Build.VERSION_CODES.JELLY_BEAN_MR1) { @@ -645,11 +652,11 @@ public class LightningView { return null; } + @SuppressLint("NewApi") @Override public void onPageFinished(WebView view, String url) { if (view.isShown()) { mBrowserController.updateUrl(url, true); - mBrowserController.updateBookmarkIndicator(url); view.postInvalidate(); } if (view.getTitle() == null || view.getTitle().isEmpty()) { @@ -667,7 +674,6 @@ public class LightningView { public void onPageStarted(WebView view, String url, Bitmap favicon) { if (isShown()) { mBrowserController.updateUrl(url, false); - mBrowserController.updateBookmarkIndicator(url); mBrowserController.showActionBar(); } mTitle.setFavicon(mWebpageBitmap); @@ -723,6 +729,7 @@ public class LightningView { private boolean mIsRunning = false; private float mZoomScale = 0.0f; + @SuppressLint("NewApi") @Override public void onScaleChanged(final WebView view, final float oldScale, final float newScale) { if (view.isShown() && mTextReflow && API >= android.os.Build.VERSION_CODES.KITKAT) { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index db9476a..6ba6418 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -27,7 +27,19 @@ - + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bookmark_drawer.xml b/app/src/main/res/layout/bookmark_drawer.xml index 0a5e553..b84bedd 100644 --- a/app/src/main/res/layout/bookmark_drawer.xml +++ b/app/src/main/res/layout/bookmark_drawer.xml @@ -1,13 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/raw/default_bookmarks.dat b/app/src/main/res/raw/default_bookmarks.dat new file mode 100644 index 0000000..4607c15 --- /dev/null +++ b/app/src/main/res/raw/default_bookmarks.dat @@ -0,0 +1,5 @@ +{"url": "https://twitter.com/RestainoAnthony", "title": "The Developer", "folder": "", "order": 0} +{"url": "https://www.facebook.com/", "title": "Facebook", "folder": "", "order": 2} +{"url": "https://twitter.com", "title": "Twitter", "folder": "", "order": 3} +{"url": "https://www.google.com/", "title": "Google", "folder": "", "order": 4} +{"url": "https://www.yahoo.com/", "title": "Yahoo", "folder": "", "order": 5} diff --git a/external/netcipher b/external/netcipher index be23314..442d282 160000 --- a/external/netcipher +++ b/external/netcipher @@ -1 +1 @@ -Subproject commit be233148c1c644b77b4f90089c82d85a50940c57 +Subproject commit 442d282b07940a9992f54fcf61c44e12472cca83 From 4eaf01e6ccb9fd02e7ce6615d5848a399afbcc7c Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 27 Aug 2015 22:00:31 +0200 Subject: [PATCH 2/5] Updated netchiper submodule --- external/netcipher | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/netcipher b/external/netcipher index 442d282..7727f04 160000 --- a/external/netcipher +++ b/external/netcipher @@ -1 +1 @@ -Subproject commit 442d282b07940a9992f54fcf61c44e12472cca83 +Subproject commit 7727f0402ce43489e5ebf4ee42dcacddad37c491 From 23e97306dda9cf99baa2a642851b476c4cf75024 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 3 Sep 2015 15:33:40 +0200 Subject: [PATCH 3/5] BookmarkPage restored and proper dependency injection --- app/build.gradle | 6 + .../browser/lightning/utils/ProxyUtils.java | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../lightning/activity/BrowserActivity.java | 84 ++-- .../browser/lightning/app/AppComponent.java | 6 + .../acr/browser/lightning/app/BrowserApp.java | 2 - .../browser/lightning/bus/BookmarkEvents.java | 18 +- .../lightning/constant/BookmarkPage.java | 38 +- .../browser/lightning/constant/Constants.java | 5 + .../lightning/constant/HistoryPage.java | 2 +- .../browser/lightning/constant/StartPage.java | 2 +- .../lightning/database/BookmarkManager.java | 420 +++++++++--------- .../dialog/BookmarksDialogBuilder.java | 196 +++++++- .../fragment/BookmarkSettingsFragment.java | 8 +- .../lightning/fragment/BookmarksFragment.java | 226 ++-------- .../lightning/object/SearchAdapter.java | 7 +- .../preference/PreferenceManager.java | 2 +- .../lightning/utils/DownloadImageTask.java | 2 +- .../acr/browser/lightning/utils/Utils.java | 17 - .../browser/lightning/view/LightningView.java | 2 - build.gradle | 1 + 21 files changed, 591 insertions(+), 457 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9cc5b1e..9a56b33 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' android { compileSdkVersion 23 @@ -49,9 +50,14 @@ dependencies { compile 'com.android.support:recyclerview-v7:23.0.0' compile 'org.jsoup:jsoup:1.8.1' compile 'com.squareup:otto:1.3.8' + compile 'com.google.dagger:dagger:2.0.1' + apt 'com.google.dagger:dagger-compiler:2.0.1' + // Only Lightning Plus needs the proxy libraries lightningPlusCompile 'net.i2p.android:client:0.7' lightningPlusCompile(project(':libnetcipher')) + + provided 'javax.annotation:jsr250-api:1.0' // git submodule foreach git reset --hard // git submodule update --remote } \ No newline at end of file diff --git a/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java index 4238d1b..eea6f02 100644 --- a/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java @@ -10,7 +10,7 @@ import android.util.Log; import net.i2p.android.ui.I2PAndroidHelper; import acr.browser.lightning.R; -import acr.browser.lightning.activity.BrowserApp; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; import info.guardianproject.netcipher.proxy.OrbotHelper; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8d8ec38..cbb5f66 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ android:required="false" /> \n" + @@ -49,29 +49,41 @@ public class BookmarkPage { public static final String END = ""; - public static void buildBookmarkPage(final Activity activity, final String folder, final List list) { - final BookmarkManager manager = BookmarkManager.getInstance(activity); - File bookmarkWebPage; + @Inject + BookmarkManager manager; + + private final File FILES_DIR; + private final File CACHE_DIR; + + @Inject + public BookmarkPage(Context context) { + BrowserApp.getAppComponent().inject(this); + FILES_DIR = context.getFilesDir(); + CACHE_DIR = context.getCacheDir(); + } + + public void buildBookmarkPage(final String folder, final List list) { + final File bookmarkWebPage; if (folder == null || folder.isEmpty()) { - bookmarkWebPage = new File(activity.getFilesDir(), BookmarkPage.FILENAME); + bookmarkWebPage = new File(FILES_DIR, Constants.BOOKMARKS_FILENAME); } else { - bookmarkWebPage = new File(activity.getFilesDir(), folder + '-' + BookmarkPage.FILENAME); + bookmarkWebPage = new File(FILES_DIR, folder + '-' + Constants.BOOKMARKS_FILENAME); } final StringBuilder bookmarkBuilder = new StringBuilder(BookmarkPage.HEADING); - String folderIconPath = Constants.FILE + activity.getCacheDir() + "/folder.png"; + final String folderIconPath = Constants.FILE + CACHE_DIR + "/folder.png"; for (int n = 0; n < list.size(); n++) { final HistoryItem item = list.get(n); bookmarkBuilder.append(BookmarkPage.PART1); if (item.isFolder()) { - File folderPage = new File(activity.getFilesDir(), item.getTitle() + '-' + BookmarkPage.FILENAME); + final File folderPage = new File(FILES_DIR, item.getTitle() + '-' + Constants.BOOKMARKS_FILENAME); bookmarkBuilder.append(Constants.FILE).append(folderPage); bookmarkBuilder.append(BookmarkPage.PART2); bookmarkBuilder.append(folderIconPath); new Thread(new Runnable() { @Override public void run() { - buildBookmarkPage(activity, item.getTitle(), manager.getBookmarksFromFolder(item.getTitle(), true)); + buildBookmarkPage(item.getTitle(), manager.getBookmarksFromFolder(item.getTitle(), true)); } }).run(); } else { diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index 11d9457..4e6ea88 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -47,6 +47,11 @@ public final class Constants { public static final int PROXY_I2P = 2; public static final int PROXY_MANUAL = 3; + /** + * The bookmark page standard suffix + */ + public static final String BOOKMARKS_FILENAME = "bookmarks.html"; + public static final String DEFAULT_ENCODING = "UTF-8"; public static final String[] TEXT_ENCODINGS = {"ISO-8859-1", "UTF-8", "GBK", "Big5", "ISO-2022-JP", "SHIFT_JS", "EUC-JP", "EUC-KR"}; diff --git a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java index 836cbb2..5c2c058 100644 --- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java @@ -11,7 +11,7 @@ import java.util.List; import android.content.Context; -import acr.browser.lightning.activity.BrowserApp; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.R; import acr.browser.lightning.database.HistoryDatabase; diff --git a/app/src/main/java/acr/browser/lightning/constant/StartPage.java b/app/src/main/java/acr/browser/lightning/constant/StartPage.java index 50103cc..118696f 100644 --- a/app/src/main/java/acr/browser/lightning/constant/StartPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/StartPage.java @@ -9,7 +9,7 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; -import acr.browser.lightning.activity.BrowserApp; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.R; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; 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 fb6f0a9..ab5637f 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkManager.java @@ -2,10 +2,9 @@ package acr.browser.lightning.database; import android.app.Activity; import android.content.Context; -import android.database.Cursor; import android.os.Environment; -import android.provider.Browser; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import org.json.JSONException; @@ -23,78 +22,189 @@ import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.inject.Singleton; import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; +@Singleton public class BookmarkManager { private static final String TAG = BookmarkManager.class.getSimpleName(); - private final Context mContext; private static final String TITLE = "title"; private static final String URL = "url"; private static final String FOLDER = "folder"; private static final String ORDER = "order"; private static final String FILE_BOOKMARKS = "bookmarks.dat"; - private Set mBookmarkSearchSet = new HashSet<>(); - private final List mBookmarkList = new ArrayList<>(); + + private final String DEFAULT_BOOKMARK_TITLE; + + private Map mBookmarksMap = new HashMap<>(); + // private final List mBookmarkList = new ArrayList<>(); private String mCurrentFolder = ""; - private static BookmarkManager mInstance; + private final ExecutorService mExecutor; + private boolean mReady = false; + private final File mFilesDir; + + public BookmarkManager(Context context) { + mExecutor = Executors.newSingleThreadExecutor(); + mFilesDir = context.getFilesDir(); + DEFAULT_BOOKMARK_TITLE = context.getString(R.string.untitled); + mExecutor.execute(new BookmarkInitializer(context)); + } + + /** + * + * @return true if the BookmarkManager was initialized, false otherwise + */ + public boolean isReady() { + return mReady; + } + + /** + * Look for bookmark using the url + * @param url the lookup url + * @return the bookmark as an {@link HistoryItem} or null + */ + @Nullable + public HistoryItem findBookmarkForUrl(final String url) { + return mBookmarksMap.get(url); + } + + /** + * Initialize the Bookmaneger, it's a one-time operation and will be executed asynchronously. + * When done, mReady flag will been setted to true. + */ + private class BookmarkInitializer implements Runnable{ + private final Context mContext; - public static BookmarkManager getInstance(Context context) { - if (mInstance == null) { - mInstance = new BookmarkManager(context); + public BookmarkInitializer(Context context) { + mContext = context; } - return mInstance; + + @Override + public void run() { + synchronized (BookmarkManager.this) { + final Map bookmarks = new HashMap<>(); + final File bookmarksFile = new File(mFilesDir, FILE_BOOKMARKS); + + BufferedReader bookmarksReader = null; + try { + final InputStream inputStream; + if (bookmarksFile.exists() && bookmarksFile.isFile()) { + inputStream = new FileInputStream(bookmarksFile); + } else { + inputStream = mContext.getResources().openRawResource(R.raw.default_bookmarks); + } + bookmarksReader = + new BufferedReader(new InputStreamReader(inputStream)); + String line; + while ((line = bookmarksReader.readLine()) != null) { + try { + JSONObject object = new JSONObject(line); + HistoryItem item = new HistoryItem(); + item.setTitle(object.getString(TITLE)); + final String url = object.getString(URL); + item.setUrl(url); + item.setFolder(object.getString(FOLDER)); + item.setOrder(object.getInt(ORDER)); + item.setImageId(R.drawable.ic_bookmark); + bookmarks.put(url, item); + } catch (JSONException e) { + Log.e(TAG, "Can't parse line " + line, e); + } + } + } catch (IOException e) { + Log.e(TAG, "Error reading the bookmarks file", e); + } finally { + Utils.close(bookmarksReader); + } + mBookmarksMap = bookmarks; + mReady = true; + } + } + } - private BookmarkManager(Context context) { - mContext = context; - mBookmarkList.clear(); - mBookmarkList.addAll(getAllBookmarks(true)); - mBookmarkSearchSet = getBookmarkUrls(mBookmarkList); + /** + * Dump all the given bookmarks to the bookmark file using a temporary file + */ + private class BookmarksWriter implements Runnable { + + private final List mBookmarks; + + public BookmarksWriter(List bookmarks) { + mBookmarks = bookmarks; + } + + @Override + public void run() { + final File tempFile = new File(mFilesDir, + String.format("bm_%d.dat", System.currentTimeMillis())); + final File bookmarksFile = new File(mFilesDir, FILE_BOOKMARKS); + boolean success = false; + BufferedWriter bookmarkWriter = null; + try { + bookmarkWriter = new BufferedWriter(new FileWriter(tempFile, false)); + JSONObject object = new JSONObject(); + for (HistoryItem item : mBookmarks) { + object.put(TITLE, item.getTitle()); + object.put(URL, item.getUrl()); + object.put(FOLDER, item.getFolder()); + object.put(ORDER, item.getOrder()); + bookmarkWriter.write(object.toString()); + bookmarkWriter.newLine(); + } + success = true; + } catch (IOException | JSONException e) { + e.printStackTrace(); + } finally { + Utils.close(bookmarkWriter); + } + + if (success) { + // Overwrite the bookmarks file by renaming the temp file + tempFile.renameTo(bookmarksFile); + } + } + } + + @Override + protected void finalize() throws Throwable { + mExecutor.shutdownNow(); + super.finalize(); } public boolean isBookmark(String url) { - return mBookmarkSearchSet.contains(url); + return mBookmarksMap.containsKey(url); } /** - * This method adds the the HistoryItem item to permanent bookmark storage. - * It returns true if the operation was successful. + * This method adds the the HistoryItem item to permanent bookmark storage.
+ * This operation is blocking if the manager is still not ready. * - * @param item the item to add + * @param item the item to add + * @return It returns true if the operation was successful. */ - public synchronized boolean addBookmark(HistoryItem item) { - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - if (item.getUrl() == null || mBookmarkSearchSet.contains(item.getUrl())) { + public synchronized boolean addBookmark(@NonNull HistoryItem item) { + final String url = item.getUrl(); + if (url == null || mBookmarksMap.containsKey(url)) { return false; } - mBookmarkList.add(item); - BufferedWriter bookmarkWriter = null; - try { - bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true)); - JSONObject object = new JSONObject(); - object.put(TITLE, item.getTitle()); - object.put(URL, item.getUrl()); - object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getOrder()); - bookmarkWriter.write(object.toString()); - bookmarkWriter.newLine(); - mBookmarkSearchSet.add(item.getUrl()); - } catch (IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarkWriter); - } + mBookmarksMap.put(url, item); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); return true; } @@ -104,28 +214,16 @@ public class BookmarkManager { * @param list the list of HistoryItems to add to bookmarks */ private synchronized void addBookmarkList(List list) { - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - BufferedWriter bookmarkWriter = null; - try { - bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true)); - JSONObject object = new JSONObject(); - for (HistoryItem item : list) { - if (item.getUrl() != null && !mBookmarkSearchSet.contains(item.getUrl())) { - object.put(TITLE, item.getTitle()); - object.put(URL, item.getUrl()); - object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getOrder()); - bookmarkWriter.write(object.toString()); - bookmarkWriter.newLine(); - mBookmarkSearchSet.add(item.getUrl()); - mBookmarkList.add(item); - } + if (list == null || list.isEmpty()) { + return; + } + for (HistoryItem item : list) { + final String url = item.getUrl(); + if (url != null && !mBookmarksMap.containsKey(url)) { + mBookmarksMap.put(url, item); } - } catch (IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarkWriter); } + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } /** @@ -138,9 +236,8 @@ public class BookmarkManager { if (deleteItem == null || deleteItem.isFolder()) { return false; } - mBookmarkSearchSet.remove(deleteItem.getUrl()); - mBookmarkList.remove(deleteItem); - overwriteBookmarks(mBookmarkList); + mBookmarksMap.remove(deleteItem.getUrl()); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); return true; } @@ -154,15 +251,15 @@ public class BookmarkManager { if (newName.isEmpty()) { return; } - for (int n = 0; n < mBookmarkList.size(); n++) { - if (mBookmarkList.get(n).getFolder().equals(oldName)) { - mBookmarkList.get(n).setFolder(newName); - } else if (mBookmarkList.get(n).isFolder() && mBookmarkList.get(n).getTitle().equals(oldName)) { - mBookmarkList.get(n).setTitle(newName); - mBookmarkList.get(n).setUrl(Constants.FOLDER + newName); + for (HistoryItem item: mBookmarksMap.values()) { + if (item.getFolder().equals(oldName)) { + item.setFolder(newName); + } else if (item.isFolder() && item.getTitle().equals(oldName)) { + item.setTitle(newName); + item.setUrl(Constants.FOLDER + newName); } } - overwriteBookmarks(mBookmarkList); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } /** @@ -171,16 +268,22 @@ public class BookmarkManager { * @param name the name of the folder to be deleted */ public synchronized void deleteFolder(@NonNull String name) { - Iterator iterator = mBookmarkList.iterator(); - while (iterator.hasNext()) { - HistoryItem item = iterator.next(); - if (!item.isFolder() && item.getFolder().equals(name)) { - item.setFolder(""); - } else if (item.getTitle().equals(name)) { - iterator.remove(); + final Map bookmarks = new HashMap<>(); + for (HistoryItem item: mBookmarksMap.values()) { + final String url = item.getUrl(); + if (item.isFolder()) { + if (!item.getTitle().equals(name)) { + bookmarks.put(url, item); + } + } else { + if (item.getFolder().equals(name)) { + item.setFolder(""); + } + bookmarks.put(url, item); } } - overwriteBookmarks(mBookmarkList); + mBookmarksMap = bookmarks; + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } /** @@ -193,21 +296,21 @@ public class BookmarkManager { if (oldItem == null || newItem == null || oldItem.isFolder()) { return; } - mBookmarkList.remove(oldItem); - mBookmarkList.add(newItem); - if (!oldItem.getUrl().equals(newItem.getUrl())) { - // Update the BookmarkMap if the URL has been changed - mBookmarkSearchSet.remove(oldItem.getUrl()); - mBookmarkSearchSet.add(newItem.getUrl()); - } if (newItem.getUrl().isEmpty()) { deleteBookmark(oldItem); return; } if (newItem.getTitle().isEmpty()) { - newItem.setTitle(mContext.getString(R.string.untitled)); + newItem.setTitle(DEFAULT_BOOKMARK_TITLE); + } + final String oldUrl = oldItem.getUrl(); + final String newUrl = newItem.getUrl(); + if (!oldUrl.equals(newUrl)) { + // The url has been changed, remove the old one + mBookmarksMap.remove(oldUrl); } - overwriteBookmarks(mBookmarkList); + mBookmarksMap.put(newUrl, newItem); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } /** @@ -254,42 +357,12 @@ public class BookmarkManager { * This is a disk-bound operation and should not be * done very frequently. * + * @param sort force to sort the returned bookmarkList + * * @return returns a list of bookmarks that can be sorted */ public synchronized List getAllBookmarks(boolean sort) { - final List bookmarks = new ArrayList<>(); - final File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - - BufferedReader bookmarksReader = null; - try { - final InputStream inputStream; - if (bookmarksFile.exists() && bookmarksFile.isFile()) { - inputStream = new FileInputStream(bookmarksFile); - } else { - inputStream = mContext.getResources().openRawResource(R.raw.default_bookmarks); - } - bookmarksReader = - new BufferedReader(new InputStreamReader(inputStream)); - String line; - while ((line = bookmarksReader.readLine()) != null) { - try { - JSONObject object = new JSONObject(line); - HistoryItem item = new HistoryItem(); - item.setTitle(object.getString(TITLE)); - item.setUrl(object.getString(URL)); - item.setFolder(object.getString(FOLDER)); - item.setOrder(object.getInt(ORDER)); - item.setImageId(R.drawable.ic_bookmark); - bookmarks.add(item); - } catch (JSONException e) { - Log.e(TAG, "Can't parse line " + line, e); - } - } - } catch (IOException e) { - Log.e(TAG, "Error reading the bookmarks file", e); - } finally { - Utils.close(bookmarksReader); - } + final List bookmarks = new ArrayList<>(mBookmarksMap.values()); if (sort) { Collections.sort(bookmarks, new SortIgnoreCase()); } @@ -312,9 +385,9 @@ public class BookmarkManager { folder = ""; } mCurrentFolder = folder; - for (int n = 0; n < mBookmarkList.size(); n++) { - if (mBookmarkList.get(n).getFolder().equals(folder)) - bookmarks.add(mBookmarkList.get(n)); + for (HistoryItem item: mBookmarksMap.values()) { + if (item.getFolder().equals(folder)) + bookmarks.add(item); } if (sort) { Collections.sort(bookmarks, new SortIgnoreCase()); @@ -338,9 +411,9 @@ public class BookmarkManager { */ private Set getBookmarkUrls(List list) { Set set = new HashSet<>(); - for (int n = 0; n < list.size(); n++) { - if (!mBookmarkList.get(n).isFolder()) - set.add(mBookmarkList.get(n).getUrl()); + for (HistoryItem item: mBookmarksMap.values()) { + if (!item.isFolder()) + set.add(item.getUrl()); } return set; } @@ -353,34 +426,23 @@ public class BookmarkManager { * @return a list of all folders */ public synchronized List getFolders(boolean sort) { - List folders = new ArrayList<>(); - Set folderMap = new HashSet<>(); - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - BufferedReader bookmarksReader = null; - try { - bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); - String line; - while ((line = bookmarksReader.readLine()) != null) { - JSONObject object = new JSONObject(line); - String folderName = object.getString(FOLDER); - if (!folderName.isEmpty() && !folderMap.contains(folderName)) { - HistoryItem item = new HistoryItem(); - item.setTitle(folderName); - item.setUrl(Constants.FOLDER + folderName); - item.setIsFolder(true); - folderMap.add(folderName); - folders.add(item); - } + final HashMap folders = new HashMap<>(); + for (HistoryItem item: mBookmarksMap.values()) { + final String folderName = item.getFolder(); + if (folderName != null && !folderName.isEmpty() && !folders.containsKey(folderName)) { + final HistoryItem folder = new HistoryItem(); + folder.setIsFolder(true); + folder.setTitle(folderName); + folder.setImageId(R.drawable.ic_folder); + folder.setUrl(Constants.FOLDER + folderName); + folders.put(folderName, folder); } - } catch (IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarksReader); } + final List result = new ArrayList<>(folders.values()); if (sort) { - Collections.sort(folders, new SortIgnoreCase()); + Collections.sort(result, new SortIgnoreCase()); } - return folders; + return result; } /** @@ -390,27 +452,14 @@ public class BookmarkManager { * @return a list of folder title strings */ public synchronized List getFolderTitles() { - List folders = new ArrayList<>(); - Set folderMap = new HashSet<>(); - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - BufferedReader bookmarksReader = null; - try { - bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); - String line; - while ((line = bookmarksReader.readLine()) != null) { - JSONObject object = new JSONObject(line); - String folderName = object.getString(FOLDER); - if (!folderName.isEmpty() && !folderMap.contains(folderName)) { - folders.add(folderName); - folderMap.add(folderName); - } + final Set folders = new HashSet<>(); + for (HistoryItem item: mBookmarksMap.values()) { + final String folderName = item.getFolder(); + if (folderName != null && !folderName.isEmpty()) { + folders.add(folderName); } - } catch (IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarksReader); } - return folders; + return new ArrayList<>(folders); } /** @@ -450,37 +499,6 @@ public class BookmarkManager { } } - /** - * This method overwrites the entire bookmark file with the list of - * bookmarks. This is useful when an edit has been made to one or more - * bookmarks in the list - * - * @param list the list of bookmarks to overwrite the old ones with - */ - private synchronized void overwriteBookmarks(List list) { - File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); - BufferedWriter bookmarkWriter = null; - try { - bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, false)); - JSONObject object = new JSONObject(); - for (int n = 0; n < list.size(); n++) { - HistoryItem item = list.get(n); - if (!item.isFolder()) { - object.put(TITLE, item.getTitle()); - object.put(URL, item.getUrl()); - object.put(FOLDER, item.getFolder()); - object.put(ORDER, item.getOrder()); - bookmarkWriter.write(object.toString()); - bookmarkWriter.newLine(); - } - } - } catch (IOException | JSONException e) { - e.printStackTrace(); - } finally { - Utils.close(bookmarkWriter); - } - } - /** * find the index of a bookmark in a list using only its URL * diff --git a/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java index 814ccde..fdf2ac6 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java @@ -1,7 +1,201 @@ package acr.browser.lightning.dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.net.Uri; +import android.support.v7.app.AlertDialog; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.LinearLayout; + +import com.squareup.otto.Bus; + +import java.util.List; + +import javax.inject.Inject; + +import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.bus.BookmarkEvents; +import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.database.BookmarkManager; +import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.utils.Utils; + /** - * Created by Stefano Pacifici on 02/09/15. + * Created by Stefano Pacifici on 02/09/15, based on Anthony C. Restaino's code. */ public class BookmarksDialogBuilder { + + @Inject + BookmarkManager bookmarkManager; + + @Inject + Bus eventBus; + + @Inject + public BookmarksDialogBuilder() { + BrowserApp.getAppComponent().inject(this); + } + + /** + * Show the appropriated dialog for the long pressed link. It means that we try to understand + * if the link is relative to a bookmark or is just a folder. + * @param context used to show the dialog + * @param url the long pressed url + */ + public void showLongPressedDialogForUrl(final Context context, final String url) { + final HistoryItem item; + if (url.startsWith(Constants.FILE) && url.endsWith(Constants.BOOKMARKS_FILENAME)) { + // TODO this in so many ways is wrong, probably we need to redesign the folder mechanism + final Uri uri = Uri.parse(url); + final String filename = uri.getLastPathSegment(); + final String folderTitle = filename.substring(0, filename.length() - Constants.BOOKMARKS_FILENAME.length() - 1); + item = new HistoryItem(); + item.setIsFolder(true); + item.setTitle(folderTitle); + item.setImageId(R.drawable.ic_folder); + item.setUrl(Constants.FOLDER + folderTitle); + } else { + item = bookmarkManager.findBookmarkForUrl(url); + } + if (item != null) { + if (item.isFolder()) { + showBookmarkFolderLongPressedDialog(context, item); + } else { + showLongPressedDialogForUrl(context, item); + } + } + } + + public void showLongPressedDialogForUrl(final Context context, final HistoryItem item) { + final DialogInterface.OnClickListener dialogClickListener = + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + eventBus.post(new BookmarkEvents.AsNewTab(item)); + break; + case DialogInterface.BUTTON_NEGATIVE: + if (bookmarkManager.deleteBookmark(item)) { + eventBus.post(new BookmarkEvents.Deleted(item)); + } + break; + case DialogInterface.BUTTON_NEUTRAL: + showEditBookmarkDialog(context, item); + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.action_bookmarks) + .setMessage(R.string.dialog_bookmark) + .setCancelable(true) + .setPositiveButton(R.string.action_new_tab, dialogClickListener) + .setNegativeButton(R.string.action_delete, dialogClickListener) + .setNeutralButton(R.string.action_edit, dialogClickListener) + .show(); + } + + public void showEditBookmarkDialog(final Context context, final HistoryItem item) { + final AlertDialog.Builder editBookmarkDialog = new AlertDialog.Builder(context); + editBookmarkDialog.setTitle(R.string.title_edit_bookmark); + final View dialogLayout = View.inflate(context, R.layout.dialog_edit_bookmark, null); + final EditText getTitle = (EditText) dialogLayout.findViewById(R.id.bookmark_title); + getTitle.setText(item.getTitle()); + final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url); + getUrl.setText(item.getUrl()); + final AutoCompleteTextView getFolder = + (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); + getFolder.setHint(R.string.folder); + getFolder.setText(item.getFolder()); + final List folders = bookmarkManager.getFolderTitles(); + final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(context, + android.R.layout.simple_dropdown_item_1line, folders); + getFolder.setThreshold(1); + getFolder.setAdapter(suggestionsAdapter); + editBookmarkDialog.setView(dialogLayout); + editBookmarkDialog.setPositiveButton(context.getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + HistoryItem editedItem = new HistoryItem(); + String currentFolder = item.getFolder(); + editedItem.setTitle(getTitle.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setUrl(getUrl.getText().toString()); + editedItem.setFolder(getFolder.getText().toString()); + bookmarkManager.editBookmark(item, editedItem); + eventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + } + }); + editBookmarkDialog.show(); + } + + public void showBookmarkFolderLongPressedDialog(final Context context, final HistoryItem item) { + assert item.isFolder(); + final DialogInterface.OnClickListener dialogClickListener = + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + showRenameFolderDialog(context, item); + break; + + case DialogInterface.BUTTON_NEGATIVE: + bookmarkManager.deleteFolder(item.getTitle()); + // setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); + eventBus.post(new BookmarkEvents.Deleted(item)); + break; + } + } + }; + + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.action_folder) + .setMessage(R.string.dialog_folder) + .setCancelable(true) + .setPositiveButton(R.string.action_rename, dialogClickListener) + .setNegativeButton(R.string.action_delete, dialogClickListener) + .show(); + } + + public void showRenameFolderDialog(final Context context, final HistoryItem item) { + assert item.isFolder(); + final AlertDialog.Builder editFolderDialog = new AlertDialog.Builder(context); + editFolderDialog.setTitle(R.string.title_rename_folder); + final EditText getTitle = new EditText(context); + getTitle.setHint(R.string.hint_title); + getTitle.setText(item.getTitle()); + getTitle.setSingleLine(); + LinearLayout layout = new LinearLayout(context); + layout.setOrientation(LinearLayout.VERTICAL); + int padding = Utils.dpToPx(10); + layout.setPadding(padding, padding, padding, padding); + layout.addView(getTitle); + editFolderDialog.setView(layout); + editFolderDialog.setPositiveButton(context.getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + final String oldTitle = item.getTitle(); + final String newTitle = getTitle.getText().toString(); + final HistoryItem editedItem = new HistoryItem(); + editedItem.setTitle(newTitle); + editedItem.setUrl(Constants.FOLDER + newTitle); + editedItem.setFolder(item.getFolder()); + editedItem.setIsFolder(true); + bookmarkManager.renameFolder(oldTitle, newTitle); + eventBus.post(new BookmarkEvents.BookmarkChanged(item, editedItem)); + } + }); + editFolderDialog.show(); + } } 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 73d209e..87014d0 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -17,7 +17,10 @@ import java.io.File; import java.util.Arrays; import java.util.Comparator; +import javax.inject.Inject; + import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.utils.PermissionsManager; @@ -27,7 +30,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref private static final String SETTINGS_IMPORT = "import_bookmark"; private Activity mActivity; - private BookmarkManager mBookmarkManager; + @Inject BookmarkManager mBookmarkManager; private File[] mFileList; private String[] mFileNameList; private PermissionsManager mPermissionsManager; @@ -40,13 +43,12 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + BrowserApp.getAppComponent().inject(this); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preference_bookmarks); mActivity = getActivity(); - mBookmarkManager = BookmarkManager.getInstance(mActivity.getApplicationContext()); - initPrefs(); mPermissionsManager = PermissionsManager.getInstance(); diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 2367c15..4e1eaf8 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -1,8 +1,6 @@ package acr.browser.lightning.fragment; -import android.app.AlertDialog; import android.content.Context; -import android.content.DialogInterface; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.os.Bundle; @@ -22,11 +20,8 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; -import android.widget.AutoCompleteTextView; -import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; @@ -37,19 +32,19 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javax.inject.Inject; + import acr.browser.lightning.R; import acr.browser.lightning.activity.BrowserActivity; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.bus.BrowserEvents; -import acr.browser.lightning.bus.BusProvider; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.DownloadImageTask; import acr.browser.lightning.utils.ThemeUtils; -import acr.browser.lightning.utils.Utils; - -import static android.support.v7.app.AlertDialog.Builder; /** * Created by Stefano Pacifici on 25/08/15. Based on Anthony C. Restaino's code. @@ -57,7 +52,16 @@ import static android.support.v7.app.AlertDialog.Builder; public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { // Managers - private BookmarkManager mBookmarkManager; + @Inject + BookmarkManager mBookmarkManager; + + // Event bus + @Inject + Bus eventBus; + + // Dialog builder + @Inject + BookmarksDialogBuilder bookmarksDialogBuilder; // Adapter private BookmarkViewAdapter mBookmarkAdapter; @@ -80,13 +84,18 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Override public void run() { final Context context = getContext(); - mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext()); mBookmarkAdapter = new BookmarkViewAdapter(context, mBookmarks); setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); mBookmarksListView.setAdapter(mBookmarkAdapter); } }; + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + BrowserApp.getAppComponent().inject(this); + } + // Handle bookmark click private final OnItemClickListener itemClickListener = new OnItemClickListener() { @Override @@ -96,7 +105,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), true); } else { - BusProvider.getInstance().post(new BookmarkEvents.Clicked(item)); + eventBus.post(new BookmarkEvents.Clicked(item)); } } }; @@ -154,13 +163,13 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Override public void onStart() { super.onStart(); - BusProvider.getInstance().register(this); + eventBus.register(this); } @Override public void onStop() { super.onStop(); - BusProvider.getInstance().unregister(this); + eventBus.unregister(this); } @Subscribe @@ -170,7 +179,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, mBookmarks.add(item); Collections.sort(mBookmarks, new BookmarkManager.SortIgnoreCase()); mBookmarkAdapter.notifyDataSetChanged(); - BusProvider.getInstance() + eventBus .post(new BookmarkEvents.Added(item)); updateBookmarkIndicator(event.url); } @@ -181,6 +190,16 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, updateBookmarkIndicator(event.url); } + @Subscribe + public void bookmarkChanged(BookmarkEvents.BookmarkChanged event) { + final int size = mBookmarks.size(); + mBookmarks.remove(event.oldBookmark); + assert mBookmarks.size() < size; + mBookmarks.add(event.newBookmark); + mBookmarkAdapter.notifyDataSetChanged(); + Collections.sort(mBookmarks, new BookmarkManager.SortIgnoreCase()); + } + private void updateBookmarkIndicator(final String url) { if (!mBookmarkManager.isBookmark(url)) { mBookmarkImage.setImageResource(R.drawable.ic_action_star); @@ -194,13 +213,22 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Subscribe public void userPressedBack(final BrowserEvents.UserPressedBack event) { if (mBookmarkManager.isRootFolder()) { - BusProvider.getInstance() + eventBus .post(new BookmarkEvents.CloseBookmarks()); } else { setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); } } + @Subscribe + public void bookmarkDeleted(final BookmarkEvents.Deleted event) { + final HistoryItem item = event.item; + final int size = mBookmarks.size(); + mBookmarks.remove(event); + assert mBookmarks.size() < size; + mBookmarkAdapter.notifyDataSetChanged(); + } + private void setBookmarkDataSet(List items, boolean animate) { mBookmarks.clear(); mBookmarks.addAll(items); @@ -261,177 +289,17 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, private void handleLongPress(final HistoryItem item, final int position) { if (item.isFolder()) { - longPressFolder(item, position); - return; + bookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item); } else { - final Bus bus = BusProvider.getInstance(); - final DialogInterface.OnClickListener dialogClickListener = - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - bus.post(new BookmarkEvents.AsNewTab(item)); - break; - case DialogInterface.BUTTON_NEGATIVE: - if (mBookmarkManager.deleteBookmark(item)) { - mBookmarks.remove(position); - mBookmarkAdapter.notifyDataSetChanged(); - bus.post(new BookmarkEvents.Deleted(item)); - } - break; - case DialogInterface.BUTTON_NEUTRAL: - editBookmark(item, position); - break; - } - } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setTitle(R.string.action_bookmarks) - .setMessage(R.string.dialog_bookmark) - .setCancelable(true) - .setPositiveButton(R.string.action_new_tab, dialogClickListener) - .setNegativeButton(R.string.action_delete, dialogClickListener) - .setNeutralButton(R.string.action_edit, dialogClickListener) - .show(); + bookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item); } } - private void longPressFolder(final HistoryItem item, final int position) { - final DialogInterface.OnClickListener dialogClickListener = - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - renameFolder(item, position); - break; - - case DialogInterface.BUTTON_NEGATIVE: - mBookmarkManager.deleteFolder(item.getTitle()); - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - BusProvider.getInstance().post(new BookmarkEvents.Deleted(item)); - /* TODO Restore Bookmarkpage - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - }*/ - break; - } - } - }; - - Builder builder = new Builder(getContext()); - builder.setTitle(R.string.action_folder) - .setMessage(R.string.dialog_folder) - .setCancelable(true) - .setPositiveButton(R.string.action_rename, dialogClickListener) - .setNegativeButton(R.string.action_delete, dialogClickListener) - .show(); - } - - /** - * Takes in the id of which bookmark was selected and shows a dialog that - * allows the user to rename and change the url of the bookmark - * - * @param item the bookmark - * @param position the position inside the adapter - */ - private synchronized void editBookmark(final HistoryItem item, final int position) { - final Builder editBookmarkDialog = new Builder(getContext()); - editBookmarkDialog.setTitle(R.string.title_edit_bookmark); - final View dialogLayout = View.inflate(getContext(), R.layout.dialog_edit_bookmark, null); - final EditText getTitle = (EditText) dialogLayout.findViewById(R.id.bookmark_title); - getTitle.setText(item.getTitle()); - final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url); - getUrl.setText(item.getUrl()); - final AutoCompleteTextView getFolder = - (AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder); - getFolder.setHint(R.string.folder); - getFolder.setText(item.getFolder()); - final List folders = mBookmarkManager.getFolderTitles(); - final ArrayAdapter suggestionsAdapter = new ArrayAdapter<>(getContext(), - android.R.layout.simple_dropdown_item_1line, folders); - getFolder.setThreshold(1); - getFolder.setAdapter(suggestionsAdapter); - editBookmarkDialog.setView(dialogLayout); - editBookmarkDialog.setPositiveButton(getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - HistoryItem editedItem = new HistoryItem(); - String currentFolder = item.getFolder(); - editedItem.setTitle(getTitle.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setUrl(getUrl.getText().toString()); - editedItem.setFolder(getFolder.getText().toString()); - mBookmarkManager.editBookmark(item, editedItem); - - List list = mBookmarkManager.getBookmarksFromFolder(currentFolder, true); - if (list.isEmpty()) { - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); - } else { - setBookmarkDataSet(list, false); - } - BusProvider.getInstance() - .post(new BookmarkEvents.WantInfoAboutCurrentPage()); - /* TODO Restore BookmarkPage - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - }*/ - } - }); - editBookmarkDialog.show(); - } - - /** - * Show a dialog to rename a folder - * - * @param id the position of the HistoryItem (folder) in the bookmark list - */ - private synchronized void renameFolder(final HistoryItem item, final int id) { - final Context context = getContext(); - final Builder editFolderDialog = new Builder(context); - editFolderDialog.setTitle(R.string.title_rename_folder); - final EditText getTitle = new EditText(context); - getTitle.setHint(R.string.hint_title); - getTitle.setText(item.getTitle()); - getTitle.setSingleLine(); - LinearLayout layout = new LinearLayout(context); - layout.setOrientation(LinearLayout.VERTICAL); - int padding = Utils.dpToPx(10); - layout.setPadding(padding, padding, padding, padding); - layout.addView(getTitle); - editFolderDialog.setView(layout); - editFolderDialog.setPositiveButton(getResources().getString(R.string.action_ok), - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - String oldTitle = item.getTitle(); - String newTitle = getTitle.getText().toString(); - - mBookmarkManager.renameFolder(oldTitle, newTitle); - - setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false); - /* TODO Restore Bookmarkpage - if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) - && mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) { - openBookmarkPage(mWebView); - }*/ - } - }); - editFolderDialog.show(); - } - @Override public void onClick(View v) { switch (v.getId()) { case R.id.action_add_bookmark: - BusProvider.getInstance().post(new BookmarkEvents.WantToBookmarkCurrentPage()); + eventBus.post(new BookmarkEvents.WantToBookmarkCurrentPage()); break; default: break; 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 1b77252..a8e6ac9 100644 --- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java +++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java @@ -36,7 +36,10 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; +import javax.inject.Inject; + import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; @@ -58,7 +61,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { private boolean mIsExecuting = false; private final boolean mDarkTheme; private final boolean mIncognito; - private final BookmarkManager mBookmarkManager; + @Inject BookmarkManager mBookmarkManager; private static final String CACHE_FILE_TYPE = ".sgg"; private static final String ENCODING = "ISO-8859-1"; private static final long INTERVAL_DAY = 86400000; @@ -71,8 +74,8 @@ public class SearchAdapter extends BaseAdapter implements Filterable { private final Drawable mBookmarkDrawable; public SearchAdapter(Context context, boolean dark, boolean incognito) { + BrowserApp.getAppComponent().inject(this); mDatabaseHandler = HistoryDatabase.getInstance(context.getApplicationContext()); - mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext()); mAllBookmarks.addAll(mBookmarkManager.getAllBookmarks(true)); mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled(); mContext = context; diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index 2f93a6e..b7886d8 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -3,7 +3,7 @@ package acr.browser.lightning.preference; import android.content.SharedPreferences; import android.os.Environment; -import acr.browser.lightning.activity.BrowserApp; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; public class PreferenceManager { diff --git a/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java b/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java index 5bca4a6..9569053 100644 --- a/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java +++ b/app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java @@ -46,7 +46,7 @@ public class DownloadImageTask extends AsyncTask { // unique path for each url that is bookmarked. final Uri uri = Uri.parse(mUrl); - final String hash = "" + Utils.hash(uri.getHost()); + final String hash = "" + uri.getHost().hashCode(); final File image = new File(mCacheDir, hash + ".png"); final Uri urldisplay = Uri.fromParts(uri.getScheme(), uri.getHost(), "favicon.ico"); // checks to see if the image exists diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index 4825c1b..290b51c 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -311,21 +311,4 @@ public final class Utils { canvas.drawPath(wallpath, paint); } - - /** - * Calculate the SHA-1 hash of the given string - * @param str the string to hash - * @return the long representation of the hash - */ - public static long hash(final String str) { - try { - final MessageDigest digest = MessageDigest.getInstance("SHA-1"); - final byte[] bytes = digest.digest(str.getBytes()); - final BigInteger intRepr = new BigInteger(bytes); - return intRepr.longValue(); - } catch (NoSuchAlgorithmException e) { - Log.e(Constants.TAG, "The device has not SHA-1 support", e); - return 0; - } - } } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index 1511aec..40ea0bd 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -56,8 +56,6 @@ import java.io.IOException; import java.net.URISyntaxException; import acr.browser.lightning.R; -import acr.browser.lightning.bus.BrowserEvents; -import acr.browser.lightning.bus.BusProvider; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.controller.BrowserController; diff --git a/build.gradle b/build.gradle index 349f446..44b6898 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7' } } From 83790bec70abf5664225b9986418a9bc59d27ae5 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 3 Sep 2015 15:57:12 +0200 Subject: [PATCH 4/5] Fix bookmarks drawer background problems --- app/src/main/res/layout/activity_main.xml | 1 + app/src/main/res/layout/bookmark_drawer.xml | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6ba6418..2698a7b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -32,6 +32,7 @@ android:layout_gravity="end" android:fitsSystemWindows="true" android:id="@+id/right_drawer" + android:background="?attr/drawerBackground" android:layout_width="@dimen/navigation_width" android:layout_height="match_parent"> From 2619210f8c6f62110f507439bcbdb7471a2e9dd0 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 7 Sep 2015 10:02:23 +0200 Subject: [PATCH 5/5] Fix removing the BookmarksEvent.Deleted instead of the actual bookmark --- .../java/acr/browser/lightning/fragment/BookmarksFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 4e1eaf8..e0bd147 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -224,7 +224,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, public void bookmarkDeleted(final BookmarkEvents.Deleted event) { final HistoryItem item = event.item; final int size = mBookmarks.size(); - mBookmarks.remove(event); + mBookmarks.remove(event.item); assert mBookmarks.size() < size; mBookmarkAdapter.notifyDataSetChanged(); }