Browse Source

Refactoring: Bookmarks as Fragment

1. Incognito mode in another process
2. Bookmarks as a Fragement using Otto
3. Initial bookmarks as fragment implementation
master
Stefano Pacifici 9 years ago
parent
commit
3c9cd73bf0
  1. 1
      app/build.gradle
  2. 3
      app/src/main/AndroidManifest.xml
  3. 669
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  4. 5
      app/src/main/java/acr/browser/lightning/activity/MainActivity.java
  5. 78
      app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
  6. 44
      app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
  7. 19
      app/src/main/java/acr/browser/lightning/bus/BusProvider.java
  8. 2
      app/src/main/java/acr/browser/lightning/controller/BrowserController.java
  9. 59
      app/src/main/java/acr/browser/lightning/database/BookmarkManager.java
  10. 493
      app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
  11. 9
      app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
  12. 127
      app/src/main/java/acr/browser/lightning/utils/DownloadImageTask.java
  13. 19
      app/src/main/java/acr/browser/lightning/utils/Utils.java
  14. 11
      app/src/main/java/acr/browser/lightning/view/LightningView.java
  15. 14
      app/src/main/res/layout/activity_main.xml
  16. 6
      app/src/main/res/layout/bookmark_drawer.xml
  17. 29
      app/src/main/res/layout/dialog_edit_bookmark.xml
  18. 5
      app/src/main/res/raw/default_bookmarks.dat
  19. 2
      external/netcipher

1
app/build.gradle

@ -48,6 +48,7 @@ dependencies {
compile 'com.android.support:design:23.0.0' compile 'com.android.support:design:23.0.0'
compile 'com.android.support:recyclerview-v7:23.0.0' compile 'com.android.support:recyclerview-v7:23.0.0'
compile 'org.jsoup:jsoup:1.8.1' compile 'org.jsoup:jsoup:1.8.1'
compile 'com.squareup:otto:1.3.8'
// Only Lightning Plus needs the proxy libraries // Only Lightning Plus needs the proxy libraries
lightningPlusCompile 'net.i2p.android:client:0.7' lightningPlusCompile 'net.i2p.android:client:0.7'
lightningPlusCompile(project(':libnetcipher')) lightningPlusCompile(project(':libnetcipher'))

3
app/src/main/AndroidManifest.xml

@ -110,7 +110,8 @@
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/Theme.DarkTheme" android:theme="@style/Theme.DarkTheme"
android:windowSoftInputMode="stateHidden" > android:windowSoftInputMode="stateHidden"
android:process=":incognito">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.INCOGNITO" /> <action android:name="android.intent.action.INCOGNITO" />

669
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.graphics.drawable.Drawable;
import android.media.MediaPlayer; import android.media.MediaPlayer;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@ -65,7 +64,6 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation; import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener; import android.view.animation.Animation.AnimationListener;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
@ -86,26 +84,26 @@ import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener; import android.widget.TextView.OnEditorActionListener;
import android.widget.VideoView; import android.widget.VideoView;
import com.squareup.otto.Subscribe;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.bus.BusProvider;
import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.HistoryPage; import acr.browser.lightning.constant.HistoryPage;
@ -133,9 +131,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private DrawerLayout mDrawerLayout; private DrawerLayout mDrawerLayout;
private FrameLayout mBrowserFrame; private FrameLayout mBrowserFrame;
private FullscreenHolder mFullscreenContainer; private FullscreenHolder mFullscreenContainer;
private ListView mDrawerListRight;
private RecyclerView mDrawerListLeft; private RecyclerView mDrawerListLeft;
private LinearLayout mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout;
private RelativeLayout mSearchBar; private RelativeLayout mSearchBar;
// List // List
@ -147,12 +144,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
// Views // Views
private AnimatedProgressBar mProgressBar; private AnimatedProgressBar mProgressBar;
private AutoCompleteTextView mSearch; private AutoCompleteTextView mSearch;
private ImageView mArrowImage, mBookmarkTitleImage, mBookmarkImage; private ImageView mArrowImage;
private VideoView mVideoView; private VideoView mVideoView;
private View mCustomView, mVideoProgressView; private View mCustomView, mVideoProgressView;
// Adapter // Adapter
private BookmarkViewAdapter mBookmarkAdapter;
private LightningViewAdapter mTabAdapter; private LightningViewAdapter mTabAdapter;
private SearchAdapter mSearchAdapter; private SearchAdapter mSearchAdapter;
@ -180,7 +176,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private PreferenceManager mPreferences; private PreferenceManager mPreferences;
// Image // Image
private Bitmap mDefaultVideoPoster, mWebpageBitmap, mFolderBitmap; private Bitmap mDefaultVideoPoster, mWebpageBitmap;
private final ColorDrawable mBackground = new ColorDrawable(); private final ColorDrawable mBackground = new ColorDrawable();
private Drawable mDeleteIcon, mRefreshIcon, mSearchIcon, mIcon; private Drawable mDeleteIcon, mRefreshIcon, mSearchIcon, mIcon;
private DrawerArrowDrawable mArrowDrawable; private DrawerArrowDrawable mArrowDrawable;
@ -196,7 +192,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
abstract boolean isIncognito(); public abstract boolean isIncognito();
abstract void initializeTabs(); abstract void initializeTabs();
@ -241,11 +237,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
// Drawer stutters otherwise // Drawer stutters otherwise
mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 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); 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); ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon);
tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
@ -257,7 +250,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mDrawerLayout.setDrawerListener(new DrawerLocker()); mDrawerLayout.setDrawerListener(new DrawerLocker());
mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme); mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme);
mFolderBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_folder, mDarkTheme);
mHomepage = mPreferences.getHomepage(); mHomepage = mPreferences.getHomepage();
@ -283,11 +275,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
mDrawerListLeft.setAdapter(mTabAdapter); mDrawerListLeft.setAdapter(mTabAdapter);
// mDrawerListLeft.setOnItemClickListener(new DrawerItemClickListener());
// mDrawerListLeft.setOnItemLongClickListener(new DrawerItemLongClickListener());
mDrawerListRight.setOnItemClickListener(new BookmarkItemClickListener());
mDrawerListRight.setOnItemLongClickListener(new BookmarkItemLongClickListener());
mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext()); mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext());
@ -324,12 +311,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
setupFrameLayoutButton(R.id.action_back, R.id.icon_back); setupFrameLayoutButton(R.id.action_back, R.id.icon_back);
setupFrameLayoutButton(R.id.action_forward, R.id.icon_forward); 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_toggle_desktop, R.id.icon_desktop);
setupFrameLayoutButton(R.id.action_reading, R.id.icon_reading); setupFrameLayoutButton(R.id.action_reading, R.id.icon_reading);
mBookmarkImage = (ImageView) findViewById(R.id.icon_star);
// create the search EditText in the ToolBar // create the search EditText in the ToolBar
mSearch = (AutoCompleteTextView) actionBar.getCustomView().findViewById(R.id.search); mSearch = (AutoCompleteTextView) actionBar.getCustomView().findViewById(R.id.search);
mUntitledTitle = getString(R.string.untitled); mUntitledTitle = getString(R.string.untitled);
@ -358,38 +342,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override @Override
public void run() { 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); initializeSearchSuggestions(mSearch);
} }
}).run(); }).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_right_shadow, GravityCompat.END);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_left_shadow, GravityCompat.START); mDrawerLayout.setDrawerShadow(R.drawable.drawer_left_shadow, GravityCompat.START);
@ -811,7 +768,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
return true; return true;
case R.id.action_add_bookmark: case R.id.action_add_bookmark:
if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) { if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) {
addBookmark(mCurrentView.getTitle(), mCurrentView.getUrl()); BusProvider.getInstance()
.post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(),
mCurrentView.getUrl()));
} }
return true; return true;
case R.id.action_find: case R.id.action_find:
@ -827,75 +786,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
/**
* refreshes the underlying list of the Bookmark adapter since the bookmark
* adapter doesn't always change when notifyDataChanged gets called.
*/
private void notifyBookmarkDataSetChanged() {
if (mBookmarkAdapter != null)
mBookmarkAdapter.notifyDataSetChanged();
}
private void addBookmark(String title, String url) {
HistoryItem bookmark = new HistoryItem(url, title);
if (mBookmarkManager.addBookmark(bookmark)) {
mBookmarkList.add(bookmark);
Collections.sort(mBookmarkList, new BookmarkManager.SortIgnoreCase());
notifyBookmarkDataSetChanged();
mSearchAdapter.refreshBookmarks();
updateBookmarkIndicator(mCurrentView.getUrl());
}
}
private void setBookmarkDataSet(List<HistoryItem> 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 * method that shows a dialog asking what string the user wishes to search
* for. It highlights the text entered. * for. It highlights the text entered.
@ -995,146 +885,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
private class BookmarkItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mBookmarkList.get(position).isFolder()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(mBookmarkList.get(position).getTitle(), true), true);
return;
}
if (mCurrentView != null) {
mCurrentView.loadUrl(mBookmarkList.get(position).getUrl());
}
// keep any jank from happening when the drawer is closed after the
// URL starts to load
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mDrawerLayout.closeDrawer(mDrawerRight);
}
}, 150);
}
}
private class BookmarkItemLongClickListener implements ListView.OnItemLongClickListener {
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, final int position, long arg3) {
longPressBookmarkLink(mBookmarkList.get(position).getUrl());
return true;
}
}
/**
* Takes in the id of which bookmark was selected and shows a dialog that
* allows the user to rename and change the url of the bookmark
*
* @param id which id in the list was chosen
*/
private synchronized void editBookmark(final int id) {
final AlertDialog.Builder editBookmarkDialog = new AlertDialog.Builder(mActivity);
editBookmarkDialog.setTitle(R.string.title_edit_bookmark);
final EditText getTitle = new EditText(mActivity);
getTitle.setHint(R.string.hint_title);
getTitle.setText(mBookmarkList.get(id).getTitle());
getTitle.setSingleLine();
final EditText getUrl = new EditText(mActivity);
getUrl.setHint(R.string.hint_url);
getUrl.setText(mBookmarkList.get(id).getUrl());
getUrl.setSingleLine();
final AutoCompleteTextView getFolder = new AutoCompleteTextView(mActivity);
getFolder.setHint(R.string.folder);
getFolder.setText(mBookmarkList.get(id).getFolder());
getFolder.setSingleLine();
List<String> folders = mBookmarkManager.getFolderTitles();
ArrayAdapter<String> 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<HistoryItem> 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 * displays the WebView contained in the LightningView Also handles the
* removal of previous views * removal of previous views
@ -1196,7 +946,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
}, 150); }, 150);
updateBookmarkIndicator(mWebView.getUrl()); // Should update the bookmark status in BookmarksFragment
BusProvider.getInstance()
.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl()));
// new Handler().postDelayed(new Runnable() { // new Handler().postDelayed(new Runnable() {
// @Override // @Override
@ -1222,7 +974,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
source = intent.getExtras().getString("SOURCE"); source = intent.getExtras().getString("SOURCE");
} }
if (num == 1) { if (num == 1) {
mCurrentView.loadUrl(url); loadUrlInCurrentView(url);
} else if (url != null) { } else if (url != null) {
if (url.startsWith(Constants.FILE)) { if (url.startsWith(Constants.FILE)) {
Utils.showSnackbar(this, R.string.message_blocked_local); Utils.showSnackbar(this, R.string.message_blocked_local);
@ -1233,6 +985,16 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
private void loadUrlInCurrentView(final String url) {
if (mCurrentView == null) {
// This is a problem, probably an assert will be better than a return
return;
}
mCurrentView.loadUrl(url);
BusProvider.getInstance().post(new BrowserEvents.CurrentPageUrl(url));
}
@Override @Override
public void closeEmptyTab() { public void closeEmptyTab() {
if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) { if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) {
@ -1405,11 +1167,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) { if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) {
mDrawerLayout.closeDrawer(mDrawerLeft); mDrawerLayout.closeDrawer(mDrawerLeft);
} else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) { } else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) {
if (!mBookmarkManager.isRootFolder()) { BusProvider.getInstance()
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true); .post(new BrowserEvents.UserPressedBack());
} else {
mDrawerLayout.closeDrawer(mDrawerRight);
}
} else { } else {
if (mCurrentView != null) { if (mCurrentView != null) {
Log.d(Constants.TAG, "onBackPressed"); Log.d(Constants.TAG, "onBackPressed");
@ -1444,6 +1203,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
e.printStackTrace(); e.printStackTrace();
} }
BusProvider.getInstance().unregister(busEventListener);
} }
void saveOpenTabs() { void saveOpenTabs() {
@ -1493,7 +1254,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mCurrentView.onResume(); mCurrentView.onResume();
} }
mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext()); mHistoryDatabase = HistoryDatabase.getInstance(getApplicationContext());
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
initializePreferences(); initializePreferences();
for (int n = 0; n < mWebViewList.size(); n++) { for (int n = 0; n < mWebViewList.size(); n++) {
if (mWebViewList.get(n) != null) { if (mWebViewList.get(n) != null) {
@ -1508,6 +1268,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(NETWORK_BROADCAST_ACTION); filter.addAction(NETWORK_BROADCAST_ACTION);
registerReceiver(mNetworkReceiver, filter); registerReceiver(mNetworkReceiver, filter);
BusProvider.getInstance().register(busEventListener);
} }
/** /**
@ -1522,7 +1284,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
query = query.trim(); query = query.trim();
mCurrentView.stopLoading(); mCurrentView.stopLoading();
if (mCurrentView != null) { if (mCurrentView != null) {
mCurrentView.loadUrl(UrlUtils.smartUrlFilter(query, true, searchUrl)); loadUrlInCurrentView(UrlUtils.smartUrlFilter(query, true, searchUrl));
} }
} }
@ -1722,163 +1484,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}); });
} }
public class BookmarkViewAdapter extends ArrayAdapter<HistoryItem> {
final Context context;
List<HistoryItem> data = null;
final int layoutResourceId;
final Bitmap folderIcon;
public BookmarkViewAdapter(Context context, int layoutResourceId, List<HistoryItem> 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<String, Void, Bitmap> {
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 { private static String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url); URI uri = new URI(url);
String domain = uri.getHost(); String domain = uri.getHost();
@ -1893,6 +1498,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
if (url == null || mSearch == null || mSearch.hasFocus()) { if (url == null || mSearch == null || mSearch.hasFocus()) {
return; return;
} }
BusProvider.getInstance()
.post(new BrowserEvents.CurrentPageUrl(url));
if (shortUrl && !url.startsWith(Constants.FILE)) { if (shortUrl && !url.startsWith(Constants.FILE)) {
switch (mPreferences.getUrlBoxContentChoice()) { switch (mPreferences.getUrlBoxContentChoice()) {
case 0: // Default, show only the domain case 0: // Default, show only the domain
@ -2006,7 +1613,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override @Override
public void run() { public void run() {
mCurrentView.loadUrl(HistoryPage.getHistoryPage(mActivity)); loadUrlInCurrentView(HistoryPage.getHistoryPage(mActivity));
mSearch.setText(""); mSearch.setText("");
} }
@ -2494,12 +2101,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
longPressHistoryLink(newUrl); longPressHistoryLink(newUrl);
} }
} else if (currentUrl.endsWith(BookmarkPage.FILENAME)) { } else if (currentUrl.endsWith(BookmarkPage.FILENAME)) {
/* TODO Wtf is this?
if (url != null) { if (url != null) {
longPressBookmarkLink(url); longPressBookmarkLink(url);
} else if (result != null && result.getExtra() != null) { } else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra(); final String newUrl = result.getExtra();
longPressBookmarkLink(newUrl); longPressBookmarkLink(newUrl);
} } */
} }
} else { } else {
if (url != null) { if (url != null) {
@ -2523,103 +2131,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
private void longPressFolder(String url) {
String title;
if (url.startsWith(Constants.FILE)) {
// We are getting the title from the url
// Strip '-bookmarks.html' from the end of the url
title = url.substring(0, url.length() - BookmarkPage.FILENAME.length() - 1);
// Strip the beginning of the url off and leave only the title
title = title.substring(Constants.FILE.length() + mActivity.getFilesDir().toString().length() + 1);
} else if (url.startsWith(Constants.FOLDER)) {
title = url.substring(Constants.FOLDER.length());
} else {
title = url;
}
final int position = BookmarkManager.getIndexOfBookmark(mBookmarkList, Constants.FOLDER + title);
if (position == -1) {
return;
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
renameFolder(position);
break;
case DialogInterface.BUTTON_NEGATIVE:
mBookmarkManager.deleteFolder(mBookmarkList.get(position).getTitle());
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
&& mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) {
openBookmarkPage(mWebView);
}
if (mCurrentView != null) {
updateBookmarkIndicator(mCurrentView.getUrl());
}
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(R.string.action_folder)
.setMessage(R.string.dialog_folder)
.setCancelable(true)
.setPositiveButton(R.string.action_rename, dialogClickListener)
.setNegativeButton(R.string.action_delete, dialogClickListener)
.show();
}
private void longPressBookmarkLink(final String url) {
if (url.startsWith(Constants.FILE) || url.startsWith(Constants.FOLDER)) {
longPressFolder(url);
return;
}
final int position = BookmarkManager.getIndexOfBookmark(mBookmarkList, url);
if (position == -1) {
return;
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
newTab(mBookmarkList.get(position).getUrl(), false);
mDrawerLayout.closeDrawers();
break;
case DialogInterface.BUTTON_NEGATIVE:
if (mBookmarkManager.deleteBookmark(mBookmarkList.get(position))) {
mBookmarkList.remove(position);
notifyBookmarkDataSetChanged();
mSearchAdapter.refreshBookmarks();
openBookmarks();
if (mCurrentView != null) {
updateBookmarkIndicator(mCurrentView.getUrl());
}
}
break;
case DialogInterface.BUTTON_NEUTRAL:
editBookmark(position);
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(R.string.action_bookmarks)
.setMessage(R.string.dialog_bookmark)
.setCancelable(true)
.setPositiveButton(R.string.action_new_tab, dialogClickListener)
.setNegativeButton(R.string.action_delete, dialogClickListener)
.setNeutralButton(R.string.action_edit, dialogClickListener)
.show();
}
private void longPressHistoryLink(final String url) { private void longPressHistoryLink(final String url) {
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override @Override
@ -2637,7 +2148,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
case DialogInterface.BUTTON_NEUTRAL: case DialogInterface.BUTTON_NEUTRAL:
if (mCurrentView != null) { if (mCurrentView != null) {
mCurrentView.loadUrl(url); loadUrlInCurrentView(url);
} }
break; break;
} }
@ -2664,7 +2175,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
break; break;
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
mCurrentView.loadUrl(url); loadUrlInCurrentView(url);
break; break;
case DialogInterface.BUTTON_NEUTRAL: case DialogInterface.BUTTON_NEUTRAL:
@ -2697,7 +2208,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
break; break;
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:
mCurrentView.loadUrl(url); loadUrlInCurrentView(url);
break; break;
case DialogInterface.BUTTON_NEUTRAL: case DialogInterface.BUTTON_NEUTRAL:
@ -2758,17 +2269,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
} }
} }
@Override
public void updateBookmarkIndicator(String url) {
if (url == null || !mBookmarkManager.isBookmark(url)) {
mBookmarkImage.setImageResource(R.drawable.ic_action_star);
mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
} else {
mBookmarkImage.setImageResource(R.drawable.ic_bookmark);
mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(this), PorterDuff.Mode.SRC_IN);
}
}
@Override @Override
public void onClick(View v) { public void onClick(View v) {
switch (v.getId()) { switch (v.getId()) {
@ -2820,11 +2320,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mCurrentView.reload(); mCurrentView.reload();
closeDrawers(); closeDrawers();
break; break;
case R.id.action_add_bookmark:
if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) {
addBookmark(mCurrentView.getTitle(), mCurrentView.getUrl());
}
break;
} }
} }
@ -2870,4 +2365,84 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
PermissionsManager.getInstance().notifyPermissionsChange(permissions); PermissionsManager.getInstance().notifyPermissionsChange(permissions);
super.onRequestPermissionsResult(requestCode, permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults);
} }
private final Object busEventListener = new Object() {
/**
* Load the given bookmark in the current tab, used by the the
* {@link acr.browser.lightning.fragment.BookmarksFragment}
* @param event The event as it comes from the bus
*/
@Subscribe
public void loadBookmarkInCurrentTab(final BookmarkEvents.Clicked event) {
loadUrlInCurrentView(event.bookmark.getUrl());
// keep any jank from happening when the drawer is closed after the
// URL starts to load
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mDrawerLayout.closeDrawer(mDrawerRight);
}
}, 150);
}
/**
* Load the given bookmark in a new tab, used by the the
* {@link acr.browser.lightning.fragment.BookmarksFragment}
* @param event The event as it comes from the bus
*/
@Subscribe
public void loadBookmarkInNewTab(final BookmarkEvents.AsNewTab event) {
newTab(event.bookmark.getUrl(), true);
mDrawerLayout.closeDrawers();
}
/**
* When receive a {@link acr.browser.lightning.bus.BookmarkEvents.WantToBookmarkCurrentPage}
* message this receiver answer firing the
* {@link acr.browser.lightning.bus.BrowserEvents.AddBookmark} message
*
* @param event basically a marker
*/
@Subscribe
public void bookmarkCurrentPage(final BookmarkEvents.WantToBookmarkCurrentPage event) {
BusProvider.getInstance()
.post(new BrowserEvents
.AddBookmark(mCurrentView.getTitle(), mCurrentView.getUrl()));
}
/**
* This message is received when a bookmark was added by the
* {@link acr.browser.lightning.fragment.BookmarksFragment}
*
* @param event a marker
*/
@Subscribe
public void bookmarkAdded(final BookmarkEvents.Added event) {
mSearchAdapter.refreshBookmarks();
}
/**
* Notify the browser that a bookmark was deleted
*
* @param event
*/
@Subscribe
public void bookmarkDeleted(final BookmarkEvents.Deleted event) {
BusProvider.getInstance()
.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl()));
}
/**
* The {@link acr.browser.lightning.fragment.BookmarksFragment} send this message on reply
* to {@link acr.browser.lightning.bus.BrowserEvents.UserPressedBack} message if the
* fragement is showing the boomarks root folder.
*
* @param event a marker
*/
@Subscribe
public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) {
mDrawerLayout.closeDrawer(mDrawerRight);
}
};
} }

5
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.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
import com.squareup.otto.Subscribe;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
@ -60,4 +63,6 @@ public class MainActivity extends BrowserActivity {
closeDrawers(); closeDrawers();
moveTaskToBack(true); moveTaskToBack(true);
} }
} }

78
app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java

@ -0,0 +1,78 @@
package acr.browser.lightning.bus;
import acr.browser.lightning.database.HistoryItem;
/**
* Created by Stefano Pacifici on 26/08/15.
*/
public final class BookmarkEvents {
private BookmarkEvents() {
// No instances
}
/**
* A bookmark was clicked
*/
public final static class Clicked {
public final HistoryItem bookmark;
public Clicked(final HistoryItem bookmark) {
this.bookmark = bookmark;
}
}
/**
* The user ask to open the bookmark as new tab
*/
public final static class AsNewTab {
public final HistoryItem bookmark;
public AsNewTab(final HistoryItem bookmark) {
this.bookmark = bookmark;
}
}
/**
* The user ask to delete the selected bookmark
*/
public static class Deleted {
public final HistoryItem item;
public Deleted(final HistoryItem item) {
this.item = item;
}
}
/**
* The user ask to bookmark the currently displayed page
*/
public static class WantToBookmarkCurrentPage {
}
/**
* The bookmark was added
*/
public static class Added {
public final HistoryItem item;
public Added(final HistoryItem item) {
this.item = item;
}
}
/**
* The {@link acr.browser.lightning.fragment.BookmarksFragment} want to know the url (and title)
* of the currently shown web page.
*/
public static class WantInfoAboutCurrentPage {
}
/**
* Sended by the {@link acr.browser.lightning.fragment.BookmarksFragment} when it wants to close
* itself (generally in reply to a {@link acr.browser.lightning.bus.BrowserEvents.UserPressedBack}
* event.
*/
public static class CloseBookmarks {
}
}

44
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 {
}
}

19
app/src/main/java/acr/browser/lightning/bus/BusProvider.java

@ -0,0 +1,19 @@
package acr.browser.lightning.bus;
import com.squareup.otto.Bus;
/**
* Created by Stefano Pacifici on 25/08/15.
*/
public class BusProvider {
private static final Bus bus = new Bus();
public static Bus getInstance() {
return bus;
}
private BusProvider() {
// No instances
}
}

2
app/src/main/java/acr/browser/lightning/controller/BrowserController.java

@ -56,6 +56,6 @@ public interface BrowserController {
boolean proxyIsNotReady(); boolean proxyIsNotReady();
void updateBookmarkIndicator(String url); // void updateBookmarkIndicator(String url);
} }

59
app/src/main/java/acr/browser/lightning/database/BookmarkManager.java

@ -6,6 +6,7 @@ import android.database.Cursor;
import android.os.Environment; import android.os.Environment;
import android.provider.Browser; import android.provider.Browser;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -13,9 +14,12 @@ import org.json.JSONObject;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -32,6 +36,8 @@ import acr.browser.lightning.utils.Utils;
public class BookmarkManager { public class BookmarkManager {
private static final String TAG = BookmarkManager.class.getSimpleName();
private final Context mContext; private final Context mContext;
private static final String TITLE = "title"; private static final String TITLE = "title";
private static final String URL = "url"; private static final String URL = "url";
@ -251,24 +257,36 @@ public class BookmarkManager {
* @return returns a list of bookmarks that can be sorted * @return returns a list of bookmarks that can be sorted
*/ */
public synchronized List<HistoryItem> getAllBookmarks(boolean sort) { public synchronized List<HistoryItem> getAllBookmarks(boolean sort) {
List<HistoryItem> bookmarks = new ArrayList<>(); final List<HistoryItem> bookmarks = new ArrayList<>();
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); final File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
BufferedReader bookmarksReader = null; BufferedReader bookmarksReader = null;
try { try {
bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); final InputStream inputStream;
if (bookmarksFile.exists() && bookmarksFile.isFile()) {
inputStream = new FileInputStream(bookmarksFile);
} else {
inputStream = mContext.getResources().openRawResource(R.raw.default_bookmarks);
}
bookmarksReader =
new BufferedReader(new InputStreamReader(inputStream));
String line; String line;
while ((line = bookmarksReader.readLine()) != null) { while ((line = bookmarksReader.readLine()) != null) {
JSONObject object = new JSONObject(line); try {
HistoryItem item = new HistoryItem(); JSONObject object = new JSONObject(line);
item.setTitle(object.getString(TITLE)); HistoryItem item = new HistoryItem();
item.setUrl(object.getString(URL)); item.setTitle(object.getString(TITLE));
item.setFolder(object.getString(FOLDER)); item.setUrl(object.getString(URL));
item.setOrder(object.getInt(ORDER)); item.setFolder(object.getString(FOLDER));
item.setImageId(R.drawable.ic_bookmark); item.setOrder(object.getInt(ORDER));
bookmarks.add(item); item.setImageId(R.drawable.ic_bookmark);
} bookmarks.add(item);
} catch (IOException | JSONException e) { } catch (JSONException e) {
e.printStackTrace(); Log.e(TAG, "Can't parse line " + line, e);
}
}
} catch (IOException e) {
Log.e(TAG, "Error reading the bookmarks file", e);
} finally { } finally {
Utils.close(bookmarksReader); Utils.close(bookmarksReader);
} }
@ -498,17 +516,4 @@ public class BookmarkManager {
} }
} }
private static final String[] DEV = {"https://twitter.com/RestainoAnthony", "The Developer"};
private static final String[] FACEBOOK = {"https://www.facebook.com/", "Facebook"};
private static final String[] TWITTER = {"https://twitter.com", "Twitter"};
private static final String[] GOOGLE = {"https://www.google.com/", "Google"};
private static final String[] YAHOO = {"https://www.yahoo.com/", "Yahoo"};
public static final String[][] DEFAULT_BOOKMARKS = {
DEV,
FACEBOOK,
TWITTER,
GOOGLE,
YAHOO
};
} }

493
app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java

@ -0,0 +1,493 @@
package acr.browser.lightning.fragment;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.bus.BusProvider;
import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.DownloadImageTask;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
import static android.support.v7.app.AlertDialog.Builder;
/**
* Created by Stefano Pacifici on 25/08/15. Based on Anthony C. Restaino's code.
*/
public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
// Managers
private BookmarkManager mBookmarkManager;
// Adapter
private BookmarkViewAdapter mBookmarkAdapter;
// Preloaded images
private Bitmap mWebpageBitmap, mFolderBitmap;
// Bookmarks
private List<HistoryItem> mBookmarks = new ArrayList<>();
// Views
private ListView mBookmarksListView;
private ImageView mBookmarkTitleImage, mBookmarkImage;
// Colors
private int mIconColor;
// Init asynchronously the bookmark manager
private final Runnable initBookmarkManager = new Runnable() {
@Override
public void run() {
final Context context = getContext();
mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext());
mBookmarkAdapter = new BookmarkViewAdapter(context, mBookmarks);
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
mBookmarksListView.setAdapter(mBookmarkAdapter);
}
};
// Handle bookmark click
private final OnItemClickListener itemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final HistoryItem item = mBookmarks.get(position);
if (item.isFolder()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true),
true);
} else {
BusProvider.getInstance().post(new BookmarkEvents.Clicked(item));
}
}
};
private final OnItemLongClickListener itemLongClickListener = new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
final HistoryItem item = mBookmarks.get(position);
handleLongPress(item, position);
return true;
}
};
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.bookmark_drawer, container, false);
mBookmarksListView = (ListView) view.findViewById(R.id.right_drawer_list);
mBookmarksListView.setOnItemClickListener(itemClickListener);
mBookmarksListView.setOnItemLongClickListener(itemLongClickListener);
mBookmarkTitleImage = (ImageView) view.findViewById(R.id.starIcon);
mBookmarkImage = (ImageView) view.findViewById(R.id.icon_star);
final View backView = view.findViewById(R.id.bookmark_back_button);
backView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBookmarkManager == null)
return;
if (!mBookmarkManager.isRootFolder()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true);
}
}
});
// Must be called here, only here we have a reference to the ListView
new Thread(initBookmarkManager).run();
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
// TODO this code depend way too much on BrowserActivity
super.onActivityCreated(savedInstanceState);
final BrowserActivity activity = (BrowserActivity) getActivity();
final PreferenceManager preferenceManager =PreferenceManager.getInstance();
boolean darkTheme = preferenceManager.getUseTheme() != 0 || activity.isIncognito();
mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme);
mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme);
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) :
ThemeUtils.getIconLightThemeColor(activity);
setupFrameLayoutButton(getView(), R.id.action_add_bookmark, R.id.icon_star);
mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}
@Override
public void onStart() {
super.onStart();
BusProvider.getInstance().register(this);
}
@Override
public void onStop() {
super.onStop();
BusProvider.getInstance().unregister(this);
}
@Subscribe
public void addBookmark(final BrowserEvents.AddBookmark event) {
final HistoryItem item = new HistoryItem(event.url, event.title);
if (mBookmarkManager.addBookmark(item)) {
mBookmarks.add(item);
Collections.sort(mBookmarks, new BookmarkManager.SortIgnoreCase());
mBookmarkAdapter.notifyDataSetChanged();
BusProvider.getInstance()
.post(new BookmarkEvents.Added(item));
updateBookmarkIndicator(event.url);
}
}
@Subscribe
public void currentPageInfo(final BrowserEvents.CurrentPageUrl event) {
updateBookmarkIndicator(event.url);
}
private void updateBookmarkIndicator(final String url) {
if (!mBookmarkManager.isBookmark(url)) {
mBookmarkImage.setImageResource(R.drawable.ic_action_star);
mBookmarkImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
} else {
mBookmarkImage.setImageResource(R.drawable.ic_bookmark);
mBookmarkImage.setColorFilter(ThemeUtils.getAccentColor(getContext()), PorterDuff.Mode.SRC_IN);
}
}
@Subscribe
public void userPressedBack(final BrowserEvents.UserPressedBack event) {
if (mBookmarkManager.isRootFolder()) {
BusProvider.getInstance()
.post(new BookmarkEvents.CloseBookmarks());
} else {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true);
}
}
private void setBookmarkDataSet(List<HistoryItem> items, boolean animate) {
mBookmarks.clear();
mBookmarks.addAll(items);
mBookmarkAdapter.notifyDataSetChanged();
final int resource;
if (mBookmarkManager.isRootFolder())
resource = R.drawable.ic_action_star;
else
resource = R.drawable.ic_action_back;
final Animation startRotation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mBookmarkTitleImage.setRotationY(90 * interpolatedTime);
}
};
final Animation finishRotation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mBookmarkTitleImage.setRotationY((-90) + (90 * interpolatedTime));
}
};
startRotation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mBookmarkTitleImage.setImageResource(resource);
mBookmarkTitleImage.startAnimation(finishRotation);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
startRotation.setInterpolator(new AccelerateInterpolator());
finishRotation.setInterpolator(new DecelerateInterpolator());
startRotation.setDuration(250);
finishRotation.setDuration(250);
if (animate) {
mBookmarkTitleImage.startAnimation(startRotation);
} else {
mBookmarkTitleImage.setImageResource(resource);
}
}
// TODO this is basically a copy/paste from BrowserActivity, should be changed
private void setupFrameLayoutButton(@NonNull View view, @IdRes int buttonId, @IdRes int imageId) {
FrameLayout frameButton = (FrameLayout) view.findViewById(buttonId);
frameButton.setOnClickListener(this);
frameButton.setOnLongClickListener(this);
ImageView buttonImage = (ImageView) view.findViewById(imageId);
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}
private void handleLongPress(final HistoryItem item, final int position) {
if (item.isFolder()) {
longPressFolder(item, position);
return;
} else {
final Bus bus = BusProvider.getInstance();
final DialogInterface.OnClickListener dialogClickListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
bus.post(new BookmarkEvents.AsNewTab(item));
break;
case DialogInterface.BUTTON_NEGATIVE:
if (mBookmarkManager.deleteBookmark(item)) {
mBookmarks.remove(position);
mBookmarkAdapter.notifyDataSetChanged();
bus.post(new BookmarkEvents.Deleted(item));
}
break;
case DialogInterface.BUTTON_NEUTRAL:
editBookmark(item, position);
break;
}
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(R.string.action_bookmarks)
.setMessage(R.string.dialog_bookmark)
.setCancelable(true)
.setPositiveButton(R.string.action_new_tab, dialogClickListener)
.setNegativeButton(R.string.action_delete, dialogClickListener)
.setNeutralButton(R.string.action_edit, dialogClickListener)
.show();
}
}
private void longPressFolder(final HistoryItem item, final int position) {
final DialogInterface.OnClickListener dialogClickListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
renameFolder(item, position);
break;
case DialogInterface.BUTTON_NEGATIVE:
mBookmarkManager.deleteFolder(item.getTitle());
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
BusProvider.getInstance().post(new BookmarkEvents.Deleted(item));
/* TODO Restore Bookmarkpage
if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
&& mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) {
openBookmarkPage(mWebView);
}*/
break;
}
}
};
Builder builder = new Builder(getContext());
builder.setTitle(R.string.action_folder)
.setMessage(R.string.dialog_folder)
.setCancelable(true)
.setPositiveButton(R.string.action_rename, dialogClickListener)
.setNegativeButton(R.string.action_delete, dialogClickListener)
.show();
}
/**
* Takes in the id of which bookmark was selected and shows a dialog that
* allows the user to rename and change the url of the bookmark
*
* @param item the bookmark
* @param position the position inside the adapter
*/
private synchronized void editBookmark(final HistoryItem item, final int position) {
final Builder editBookmarkDialog = new Builder(getContext());
editBookmarkDialog.setTitle(R.string.title_edit_bookmark);
final View dialogLayout = View.inflate(getContext(), R.layout.dialog_edit_bookmark, null);
final EditText getTitle = (EditText) dialogLayout.findViewById(R.id.bookmark_title);
getTitle.setText(item.getTitle());
final EditText getUrl = (EditText) dialogLayout.findViewById(R.id.bookmark_url);
getUrl.setText(item.getUrl());
final AutoCompleteTextView getFolder =
(AutoCompleteTextView) dialogLayout.findViewById(R.id.bookmark_folder);
getFolder.setHint(R.string.folder);
getFolder.setText(item.getFolder());
final List<String> folders = mBookmarkManager.getFolderTitles();
final ArrayAdapter<String> suggestionsAdapter = new ArrayAdapter<>(getContext(),
android.R.layout.simple_dropdown_item_1line, folders);
getFolder.setThreshold(1);
getFolder.setAdapter(suggestionsAdapter);
editBookmarkDialog.setView(dialogLayout);
editBookmarkDialog.setPositiveButton(getResources().getString(R.string.action_ok),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
HistoryItem editedItem = new HistoryItem();
String currentFolder = item.getFolder();
editedItem.setTitle(getTitle.getText().toString());
editedItem.setUrl(getUrl.getText().toString());
editedItem.setUrl(getUrl.getText().toString());
editedItem.setFolder(getFolder.getText().toString());
mBookmarkManager.editBookmark(item, editedItem);
List<HistoryItem> list = mBookmarkManager.getBookmarksFromFolder(currentFolder, true);
if (list.isEmpty()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), true);
} else {
setBookmarkDataSet(list, false);
}
BusProvider.getInstance()
.post(new BookmarkEvents.WantInfoAboutCurrentPage());
/* TODO Restore BookmarkPage
if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
&& mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) {
openBookmarkPage(mWebView);
}*/
}
});
editBookmarkDialog.show();
}
/**
* Show a dialog to rename a folder
*
* @param id the position of the HistoryItem (folder) in the bookmark list
*/
private synchronized void renameFolder(final HistoryItem item, final int id) {
final Context context = getContext();
final Builder editFolderDialog = new Builder(context);
editFolderDialog.setTitle(R.string.title_rename_folder);
final EditText getTitle = new EditText(context);
getTitle.setHint(R.string.hint_title);
getTitle.setText(item.getTitle());
getTitle.setSingleLine();
LinearLayout layout = new LinearLayout(context);
layout.setOrientation(LinearLayout.VERTICAL);
int padding = Utils.dpToPx(10);
layout.setPadding(padding, padding, padding, padding);
layout.addView(getTitle);
editFolderDialog.setView(layout);
editFolderDialog.setPositiveButton(getResources().getString(R.string.action_ok),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String oldTitle = item.getTitle();
String newTitle = getTitle.getText().toString();
mBookmarkManager.renameFolder(oldTitle, newTitle);
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
/* TODO Restore Bookmarkpage
if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
&& mCurrentView.getUrl().endsWith(BookmarkPage.FILENAME)) {
openBookmarkPage(mWebView);
}*/
}
});
editFolderDialog.show();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.action_add_bookmark:
BusProvider.getInstance().post(new BookmarkEvents.WantToBookmarkCurrentPage());
break;
default:
break;
}
}
@Override
public boolean onLongClick(View v) {
return false;
}
private class BookmarkViewAdapter extends ArrayAdapter<HistoryItem> {
final Context context;
public BookmarkViewAdapter(Context context, List<HistoryItem> 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;
}
}
}

9
app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java

@ -44,7 +44,6 @@ public class PreferenceManager {
public static final String INVERT_COLORS = "invertColors"; public static final String INVERT_COLORS = "invertColors";
public static final String READING_TEXT_SIZE = "readingTextSize"; public static final String READING_TEXT_SIZE = "readingTextSize";
public static final String THEME = "Theme"; public static final String THEME = "Theme";
public static final String DEFAULT_BOOKMARKS = "defaultBookmarks";
public static final String TEXT_ENCODING = "textEncoding"; public static final String TEXT_ENCODING = "textEncoding";
public static final String CLEAR_WEBSTORAGE_EXIT = "clearWebStorageExit"; public static final String CLEAR_WEBSTORAGE_EXIT = "clearWebStorageExit";
public static final String SHOW_TABS_IN_DRAWER = "showTabsInDrawer"; public static final String SHOW_TABS_IN_DRAWER = "showTabsInDrawer";
@ -117,10 +116,6 @@ public class PreferenceManager {
return mPrefs.getBoolean(Name.COOKIES, true); return mPrefs.getBoolean(Name.COOKIES, true);
} }
public boolean getDefaultBookmarks() {
return mPrefs.getBoolean(Name.DEFAULT_BOOKMARKS, true);
}
public String getDownloadDirectory() { public String getDownloadDirectory() {
return mPrefs.getString(Name.DOWNLOAD_DIRECTORY, Environment.DIRECTORY_DOWNLOADS); return mPrefs.getString(Name.DOWNLOAD_DIRECTORY, Environment.DIRECTORY_DOWNLOADS);
} }
@ -317,10 +312,6 @@ public class PreferenceManager {
putBoolean(Name.COOKIES, enable); putBoolean(Name.COOKIES, enable);
} }
public void setDefaultBookmarks(boolean show) {
putBoolean(Name.DEFAULT_BOOKMARKS, show);
}
public void setDownloadDirectory(String directory) { public void setDownloadDirectory(String directory) {
putString(Name.DOWNLOAD_DIRECTORY, directory); putString(Name.DOWNLOAD_DIRECTORY, directory);
} }

127
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<Void, Void, Bitmap> {
final ImageView bmImage;
final HistoryItem mWeb;
final File mCacheDir;
final String mUrl;
final Bitmap mDefaultBitmap;
public DownloadImageTask(@NonNull ImageView bmImage, @NonNull HistoryItem web,
@NonNull Bitmap defaultBitmap) {
assert bmImage != null;
assert web != null;
assert defaultBitmap != null;
this.bmImage = bmImage;
this.mWeb = web;
this.mCacheDir = bmImage.getContext().getCacheDir();
this.mUrl = web.getUrl();
this.mDefaultBitmap = defaultBitmap;
}
protected Bitmap doInBackground(Void... params) {
Bitmap mIcon = null;
// unique path for each url that is bookmarked.
final Uri uri = Uri.parse(mUrl);
final String hash = "" + Utils.hash(uri.getHost());
final File image = new File(mCacheDir, hash + ".png");
final Uri urldisplay = Uri.fromParts(uri.getScheme(), uri.getHost(), "favicon.ico");
// checks to see if the image exists
if (!image.exists()) {
FileOutputStream fos = null;
InputStream in = null;
try {
// if not, download it...
final URL urlDownload = new URL(urldisplay.toString());
final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection();
connection.setDoInput(true);
connection.connect();
in = connection.getInputStream();
if (in != null) {
mIcon = BitmapFactory.decodeStream(in);
}
// ...and cache it
if (mIcon != null) {
fos = new FileOutputStream(image);
mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
Log.d(Constants.TAG, "Downloaded: " + urldisplay);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
Utils.close(in);
Utils.close(fos);
}
} else {
// if it exists, retrieve it from the cache
mIcon = BitmapFactory.decodeFile(image.getPath());
}
if (mIcon == null) {
InputStream in = null;
FileOutputStream fos = null;
try {
// if not, download it...
final URL urlDownload = new URL("https://www.google.com/s2/favicons?domain_url="
+ uri.toString());
final HttpURLConnection connection = (HttpURLConnection) urlDownload.openConnection();
connection.setDoInput(true);
connection.connect();
in = connection.getInputStream();
if (in != null) {
mIcon = BitmapFactory.decodeStream(in);
}
// ...and cache it
if (mIcon != null) {
fos = new FileOutputStream(image);
mIcon.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
Utils.close(in);
Utils.close(fos);
}
}
if (mIcon == null) {
return mDefaultBitmap;
} else {
return mIcon;
}
}
protected void onPostExecute(Bitmap result) {
final Bitmap fav = Utils.padFavicon(result);
bmImage.setImageBitmap(fav);
mWeb.setBitmap(fav);
// notifyBookmarkDataSetChanged();
}
}

19
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.Closeable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
@ -309,4 +312,20 @@ public final class Utils {
canvas.drawPath(wallpath, paint); canvas.drawPath(wallpath, paint);
} }
/**
* Calculate the SHA-1 hash of the given string
* @param str the string to hash
* @return the long representation of the hash
*/
public static long hash(final String str) {
try {
final MessageDigest digest = MessageDigest.getInstance("SHA-1");
final byte[] bytes = digest.digest(str.getBytes());
final BigInteger intRepr = new BigInteger(bytes);
return intRepr.longValue();
} catch (NoSuchAlgorithmException e) {
Log.e(Constants.TAG, "The device has not SHA-1 support", e);
return 0;
}
}
} }

11
app/src/main/java/acr/browser/lightning/view/LightningView.java

@ -56,6 +56,8 @@ import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.bus.BusProvider;
import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.constant.StartPage;
import acr.browser.lightning.controller.BrowserController; import acr.browser.lightning.controller.BrowserController;
@ -98,6 +100,7 @@ public class LightningView {
private PermissionsManager mPermissionsManager; private PermissionsManager mPermissionsManager;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
@SuppressLint("NewApi")
public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) { public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) {
mActivity = activity; mActivity = activity;
@ -175,6 +178,7 @@ public class LightningView {
* if you don't have a reference to them * if you don't have a reference to them
* @param context the context in which the WebView was created * @param context the context in which the WebView was created
*/ */
@SuppressLint("NewApi")
public synchronized void initializePreferences(@Nullable WebSettings settings, Context context) { public synchronized void initializePreferences(@Nullable WebSettings settings, Context context) {
if (settings == null && mWebView == null) { if (settings == null && mWebView == null) {
return; return;
@ -293,6 +297,7 @@ public class LightningView {
* @param settings the WebSettings object to use. * @param settings the WebSettings object to use.
* @param context the Context which was used to construct the WebView. * @param context the Context which was used to construct the WebView.
*/ */
@SuppressLint("NewApi")
private void initializeSettings(WebSettings settings, Context context) { private void initializeSettings(WebSettings settings, Context context) {
if (API < Build.VERSION_CODES.JELLY_BEAN_MR2) { if (API < Build.VERSION_CODES.JELLY_BEAN_MR2) {
settings.setAppCacheMaxSize(Long.MAX_VALUE); settings.setAppCacheMaxSize(Long.MAX_VALUE);
@ -347,6 +352,7 @@ public class LightningView {
mToggleDesktop = !mToggleDesktop; mToggleDesktop = !mToggleDesktop;
} }
@SuppressLint("NewApi")
public void setUserAgent(Context context, int choice) { public void setUserAgent(Context context, int choice) {
if (mWebView == null) return; if (mWebView == null) return;
WebSettings settings = mWebView.getSettings(); WebSettings settings = mWebView.getSettings();
@ -526,6 +532,7 @@ public class LightningView {
} }
} }
@SuppressLint("NewApi")
public synchronized void find(String text) { public synchronized void find(String text) {
if (mWebView != null) { if (mWebView != null) {
if (API >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (API >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@ -645,11 +652,11 @@ public class LightningView {
return null; return null;
} }
@SuppressLint("NewApi")
@Override @Override
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
if (view.isShown()) { if (view.isShown()) {
mBrowserController.updateUrl(url, true); mBrowserController.updateUrl(url, true);
mBrowserController.updateBookmarkIndicator(url);
view.postInvalidate(); view.postInvalidate();
} }
if (view.getTitle() == null || view.getTitle().isEmpty()) { if (view.getTitle() == null || view.getTitle().isEmpty()) {
@ -667,7 +674,6 @@ public class LightningView {
public void onPageStarted(WebView view, String url, Bitmap favicon) { public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (isShown()) { if (isShown()) {
mBrowserController.updateUrl(url, false); mBrowserController.updateUrl(url, false);
mBrowserController.updateBookmarkIndicator(url);
mBrowserController.showActionBar(); mBrowserController.showActionBar();
} }
mTitle.setFavicon(mWebpageBitmap); mTitle.setFavicon(mWebpageBitmap);
@ -723,6 +729,7 @@ public class LightningView {
private boolean mIsRunning = false; private boolean mIsRunning = false;
private float mZoomScale = 0.0f; private float mZoomScale = 0.0f;
@SuppressLint("NewApi")
@Override @Override
public void onScaleChanged(final WebView view, final float oldScale, final float newScale) { public void onScaleChanged(final WebView view, final float oldScale, final float newScale) {
if (view.isShown() && mTextReflow && API >= android.os.Build.VERSION_CODES.KITKAT) { if (view.isShown() && mTextReflow && API >= android.os.Build.VERSION_CODES.KITKAT) {

14
app/src/main/res/layout/activity_main.xml

@ -27,7 +27,19 @@
<include layout="@layout/tab_drawer" /> <include layout="@layout/tab_drawer" />
<include layout="@layout/bookmark_drawer" /> <FrameLayout
android:weightSum="1"
android:layout_gravity="end"
android:fitsSystemWindows="true"
android:id="@+id/right_drawer"
android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
class="acr.browser.lightning.fragment.BookmarksFragment" />
</FrameLayout>
<!-- include layout="@layout/bookmark_drawer" / -->
</android.support.v4.widget.DrawerLayout> </android.support.v4.widget.DrawerLayout>
</LinearLayout> </LinearLayout>

6
app/src/main/res/layout/bookmark_drawer.xml

@ -1,13 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/right_drawer" android:layout_width="match_parent"
android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="end"
android:background="?attr/drawerBackground" android:background="?attr/drawerBackground"
android:clickable="true" android:clickable="true"
android:weightSum="1"
android:fitsSystemWindows="true"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout

29
app/src/main/res/layout/dialog_edit_bookmark.xml

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bookmark_title"
android:singleLine="true"
android:hint="@string/hint_title"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bookmark_url"
android:hint="@string/hint_url"
android:singleLine="true"
android:inputType="textUri"/>
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bookmark_folder"
android:hint="@string/folder"
android:singleLine="true"/>
</LinearLayout>

5
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}

2
external/netcipher vendored

@ -1 +1 @@
Subproject commit be233148c1c644b77b4f90089c82d85a50940c57 Subproject commit 442d282b07940a9992f54fcf61c44e12472cca83
Loading…
Cancel
Save