diff --git a/app/build.gradle b/app/build.gradle index a0c6770..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 @@ -48,9 +49,15 @@ 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' + 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 1cc2031..cbb5f66 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,7 +20,7 @@ android:required="false" /> + 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 eb19a59..df08f12 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,27 @@ 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.Bus; +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 javax.inject.Inject; + import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; +import acr.browser.lightning.bus.BookmarkEvents; +import acr.browser.lightning.bus.BrowserEvents; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; @@ -113,6 +112,7 @@ import acr.browser.lightning.controller.BrowserController; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; +import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.object.DrawerArrowDrawable; import acr.browser.lightning.object.SearchAdapter; @@ -133,9 +133,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 +146,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; @@ -176,11 +174,24 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Storage private HistoryDatabase mHistoryDatabase; - private BookmarkManager mBookmarkManager; private PreferenceManager mPreferences; + // The singleton BookmarkManager + @Inject + BookmarkManager bookmarkManager; + + // Event bus + @Inject + Bus eventBus; + + @Inject + BookmarkPage bookmarkPage; + + @Inject + BookmarksDialogBuilder bookmarksDialogBuilder; + // Image - private Bitmap mDefaultVideoPoster, mWebpageBitmap, mFolderBitmap; + private Bitmap mDefaultVideoPoster, mWebpageBitmap; private final ColorDrawable mBackground = new ColorDrawable(); private Drawable mDeleteIcon, mRefreshIcon, mClearIcon, mIcon; private DrawerArrowDrawable mArrowDrawable; @@ -196,7 +207,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(); @@ -210,6 +221,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + BrowserApp.getAppComponent().inject(this); initialize(); } @@ -241,11 +253,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 +266,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 +291,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 +327,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 +358,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); @@ -807,7 +780,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()); + eventBus + .post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(), + mCurrentView.getUrl())); } return true; case R.id.action_find: @@ -823,75 +798,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. @@ -991,146 +897,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 @@ -1192,7 +958,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } }, 150); - updateBookmarkIndicator(mWebView.getUrl()); + // Should update the bookmark status in BookmarksFragment + eventBus + .post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); // new Handler().postDelayed(new Runnable() { // @Override @@ -1218,7 +986,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); @@ -1229,6 +997,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); + eventBus.post(new BrowserEvents.CurrentPageUrl(url)); + } + @Override public void closeEmptyTab() { if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) { @@ -1401,11 +1179,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); - } + eventBus + .post(new BrowserEvents.UserPressedBack()); } else { if (mCurrentView != null) { Log.d(Constants.TAG, "onBackPressed"); @@ -1443,6 +1218,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (isIncognito() && isFinishing()) { overridePendingTransition(R.anim.fade_in_scale, R.anim.slide_down_out); } + + eventBus.unregister(busEventListener); } void saveOpenTabs() { @@ -1492,7 +1269,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) { @@ -1507,6 +1283,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements IntentFilter filter = new IntentFilter(); filter.addAction(NETWORK_BROADCAST_ACTION); registerReceiver(mNetworkReceiver, filter); + + eventBus.register(busEventListener); } /** @@ -1521,7 +1299,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)); } } @@ -1667,6 +1445,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } /** + * TODO Can this method been removed? * Animates the color of the toolbar from one color to another. Optionally animates * the color of the tab background, for use when the tabs are displayed on the top * of the screen. @@ -1721,177 +1500,13 @@ 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(); - if (domain == null) { - return url; - } - return domain.startsWith("www.") ? domain.substring(4) : domain; - } - @Override public void updateUrl(String url, boolean shortUrl) { if (url == null || mSearch == null || mSearch.hasFocus()) { return; } + eventBus + .post(new BrowserEvents.CurrentPageUrl(url)); if (shortUrl && !url.startsWith(Constants.FILE)) { switch (mPreferences.getUrlBoxContentChoice()) { case 0: // Default, show only the domain @@ -2005,7 +1620,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void run() { - mCurrentView.loadUrl(HistoryPage.getHistoryPage(mActivity)); + loadUrlInCurrentView(HistoryPage.getHistoryPage(mActivity)); mSearch.setText(""); } @@ -2057,9 +1672,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } finally { Utils.close(outputStream); } - File bookmarkWebPage = new File(mActivity.getFilesDir(), BookmarkPage.FILENAME); + File bookmarkWebPage = new File(mActivity.getFilesDir(), Constants.BOOKMARKS_FILENAME); - BookmarkPage.buildBookmarkPage(this, null, mBookmarkManager.getBookmarksFromFolder(null, true)); + bookmarkPage.buildBookmarkPage(null, bookmarkManager.getBookmarksFromFolder(null, true)); view.loadUrl(Constants.FILE + bookmarkWebPage); } @@ -2492,12 +2107,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final String newUrl = result.getExtra(); longPressHistoryLink(newUrl); } - } else if (currentUrl.endsWith(BookmarkPage.FILENAME)) { + } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) { if (url != null) { - longPressBookmarkLink(url); + bookmarksDialogBuilder.showLongPressedDialogForUrl(this, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - longPressBookmarkLink(newUrl); + bookmarksDialogBuilder.showLongPressedDialogForUrl(this, newUrl); } } } else { @@ -2522,103 +2137,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 @@ -2636,7 +2154,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements case DialogInterface.BUTTON_NEUTRAL: if (mCurrentView != null) { - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); } break; } @@ -2663,7 +2181,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements break; case DialogInterface.BUTTON_NEGATIVE: - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); break; case DialogInterface.BUTTON_NEUTRAL: @@ -2696,7 +2214,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements break; case DialogInterface.BUTTON_NEGATIVE: - mCurrentView.loadUrl(url); + loadUrlInCurrentView(url); break; case DialogInterface.BUTTON_NEUTRAL: @@ -2757,17 +2275,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()) { @@ -2819,11 +2326,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; } } @@ -2869,4 +2371,103 @@ 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) { + eventBus + .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(); + } + + /** + * This is received when the user edit a bookmark + * + * @param event + */ + @Subscribe + public void bookmarkChanged(final BookmarkEvents.BookmarkChanged event) { + if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) + && mCurrentView.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { + openBookmarkPage(mWebView); + } + eventBus + .post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); + } + + /** + * Notify the browser that a bookmark was deleted + * + * @param event + */ + @Subscribe + public void bookmarkDeleted(final BookmarkEvents.Deleted event) { + if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE) + && mCurrentView.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { + openBookmarkPage(mWebView); + } + eventBus + .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/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java new file mode 100644 index 0000000..dbaf0bc --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -0,0 +1,31 @@ +package acr.browser.lightning.app; + +import javax.inject.Singleton; + +import acr.browser.lightning.activity.BrowserActivity; +import acr.browser.lightning.constant.BookmarkPage; +import acr.browser.lightning.dialog.BookmarksDialogBuilder; +import acr.browser.lightning.fragment.BookmarkSettingsFragment; +import acr.browser.lightning.fragment.BookmarksFragment; +import acr.browser.lightning.object.SearchAdapter; +import dagger.Component; + +/** + * Created by Stefano Pacifici on 01/09/15. + */ +@Singleton +@Component(modules = {AppModule.class}) +public interface AppComponent { + + void inject(BrowserActivity activity); + + void inject(BookmarksFragment fragment); + + void inject(BookmarkSettingsFragment fragment); + + void inject(SearchAdapter adapter); + + void inject(BookmarksDialogBuilder builder); + + void inject(BookmarkPage bookmarkPage); +} diff --git a/app/src/main/java/acr/browser/lightning/app/AppModule.java b/app/src/main/java/acr/browser/lightning/app/AppModule.java new file mode 100644 index 0000000..d273880 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/app/AppModule.java @@ -0,0 +1,41 @@ +package acr.browser.lightning.app; + +import android.content.Context; + +import com.squareup.otto.Bus; + +import javax.inject.Singleton; + +import acr.browser.lightning.database.BookmarkManager; +import dagger.Module; +import dagger.Provides; + +/** + * Created by Stefano Pacifici on 01/09/15. + */ +@Module +public class AppModule { + private final BrowserApp app; + private final Bus bus; + + public AppModule(BrowserApp app) { + this.app = app; + this.bus = new Bus(); + } + + @Provides + public Context provideContext() { + return app.getApplicationContext(); + } + + @Provides + @Singleton + public BookmarkManager provideBookmarkManager() { + return new BookmarkManager(app.getApplicationContext()); + } + + @Provides + public Bus provideBus() { + return bus; + } +} diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserApp.java b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java similarity index 50% rename from app/src/main/java/acr/browser/lightning/activity/BrowserApp.java rename to app/src/main/java/acr/browser/lightning/app/BrowserApp.java index 7419e05..081f8f4 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserApp.java +++ b/app/src/main/java/acr/browser/lightning/app/BrowserApp.java @@ -1,4 +1,4 @@ -package acr.browser.lightning.activity; +package acr.browser.lightning.app; import android.app.Application; import android.content.Context; @@ -6,14 +6,25 @@ import android.content.Context; public class BrowserApp extends Application { private static Context context; + private static AppComponent appComponent; @Override public void onCreate() { super.onCreate(); context = getApplicationContext(); + buildDepencyGraph(); } public static Context getAppContext() { return context; } + + public static AppComponent getAppComponent() { + return appComponent; + } + + public void buildDepencyGraph() { + appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); + } + } 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..3331eb7 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java @@ -0,0 +1,92 @@ +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 { + } + + /** + * Sended when a bookmark is edited + */ + public static class BookmarkChanged { + + public final HistoryItem oldBookmark; + public final HistoryItem newBookmark; + + public BookmarkChanged(final HistoryItem oldItem, final HistoryItem newItem) { + oldBookmark = oldItem; + newBookmark = newItem; + } + } +} 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/constant/BookmarkPage.java b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java index 081bad1..34b0512 100644 --- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java +++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java @@ -3,22 +3,22 @@ */ package acr.browser.lightning.constant; -import android.app.Activity; +import android.content.Context; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.List; +import javax.inject.Inject; + import acr.browser.lightning.R; -import acr.browser.lightning.activity.BrowserApp; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.utils.Utils; -public class BookmarkPage { - - public static final String FILENAME = "bookmarks.html"; +public final class BookmarkPage { public static final String HEADING = "\n" + "\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/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..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,10 @@ 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; import org.json.JSONObject; @@ -13,82 +13,198 @@ 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; +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 final Context mContext; + private static final String TAG = BookmarkManager.class.getSimpleName(); + 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 BookmarkInitializer(Context context) { + mContext = context; + } + + @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; + } + } + + } + + /** + * 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); + } - public static BookmarkManager getInstance(Context context) { - if (mInstance == null) { - mInstance = new BookmarkManager(context); + if (success) { + // Overwrite the bookmarks file by renaming the temp file + tempFile.renameTo(bookmarksFile); + } } - return mInstance; } - private BookmarkManager(Context context) { - mContext = context; - mBookmarkList.clear(); - mBookmarkList.addAll(getAllBookmarks(true)); - mBookmarkSearchSet = getBookmarkUrls(mBookmarkList); + @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; } @@ -98,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()))); } /** @@ -132,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; } @@ -148,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()))); } /** @@ -165,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()))); } /** @@ -187,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); } - overwriteBookmarks(mBookmarkList); + 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); + } + mBookmarksMap.put(newUrl, newItem); + mExecutor.execute(new BookmarksWriter(new LinkedList<>(mBookmarksMap.values()))); } /** @@ -248,30 +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) { - List bookmarks = new ArrayList<>(); - 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); - 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(); - } finally { - Utils.close(bookmarksReader); - } + final List bookmarks = new ArrayList<>(mBookmarksMap.values()); if (sort) { Collections.sort(bookmarks, new SortIgnoreCase()); } @@ -294,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()); @@ -320,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; } @@ -335,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; } /** @@ -372,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); } /** @@ -432,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 * @@ -498,17 +534,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/dialog/BookmarksDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java new file mode 100644 index 0000000..fdf2ac6 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java @@ -0,0 +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, 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 new file mode 100644 index 0000000..e0bd147 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -0,0 +1,361 @@ +package acr.browser.lightning.fragment; + +import android.content.Context; +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.FrameLayout; +import android.widget.ImageView; +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 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.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; + +/** + * 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 + @Inject + BookmarkManager mBookmarkManager; + + // Event bus + @Inject + Bus eventBus; + + // Dialog builder + @Inject + BookmarksDialogBuilder bookmarksDialogBuilder; + + // 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(); + 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 + 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 { + eventBus.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(); + eventBus.register(this); + } + + @Override + public void onStop() { + super.onStop(); + eventBus.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(); + eventBus + .post(new BookmarkEvents.Added(item)); + updateBookmarkIndicator(event.url); + } + } + + @Subscribe + public void currentPageInfo(final BrowserEvents.CurrentPageUrl event) { + 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); + 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()) { + 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.item); + assert mBookmarks.size() < size; + mBookmarkAdapter.notifyDataSetChanged(); + } + + 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()) { + bookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item); + } else { + bookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item); + } + } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.action_add_bookmark: + eventBus.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/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 d2aa0c2..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 { @@ -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..9569053 --- /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 = "" + 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 + 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..290b51c 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; @@ -308,5 +311,4 @@ public final class Utils { canvas.drawPath(wallpath, paint); } - } 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..40ea0bd 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -98,6 +98,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 +176,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 +295,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 +350,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 +530,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 +650,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 +672,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 +727,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..2698a7b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -27,7 +27,20 @@ - + + + + \ 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..1ed789c 100644 --- a/app/src/main/res/layout/bookmark_drawer.xml +++ b/app/src/main/res/layout/bookmark_drawer.xml @@ -1,13 +1,8 @@ + + + + + + + + \ 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/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' } } diff --git a/external/netcipher b/external/netcipher index be23314..7727f04 160000 --- a/external/netcipher +++ b/external/netcipher @@ -1 +1 @@ -Subproject commit be233148c1c644b77b4f90089c82d85a50940c57 +Subproject commit 7727f0402ce43489e5ebf4ee42dcacddad37c491