diff --git a/.gitignore b/.gitignore
index 7f036ba..39bb026 100644
--- a/.gitignore
+++ b/.gitignore
@@ -50,3 +50,5 @@ out
# Source:
# https://raw.githubusercontent.com/github/gitignore/master/Android.gitignore
# https://gitlab.com/fdroid/fdroidclient/raw/master/.gitignore
+
+*.iml
diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index d6f1ddb..0000000
--- a/app/app.iml
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateLightningPlusDebugAndroidTestSources
- generateLightningPlusDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java b/app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java
index d49f9f2..ed8211b 100644
--- a/app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java
+++ b/app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java
@@ -6,10 +6,13 @@ import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log;
+import com.squareup.otto.Bus;
+
import net.i2p.android.ui.I2PAndroidHelper;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@@ -26,8 +29,11 @@ public class ProxyUtils {
private final PreferenceManager mPreferences;
private static ProxyUtils mInstance;
+ private final Bus mEventBus;
+
private ProxyUtils(Context context) {
- mPreferences = PreferenceManager.getInstance();
+ mPreferences = BrowserApp.getAppComponent().getPreferenceManager();
+ mEventBus = BrowserApp.getAppComponent().getBus();
mI2PHelper = new I2PAndroidHelper(context.getApplicationContext());
}
@@ -143,13 +149,13 @@ public class ProxyUtils {
}
- public boolean isProxyReady(Activity activity) {
+ public boolean isProxyReady() {
if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) {
if (!mI2PHelper.isI2PAndroidRunning()) {
- Utils.showSnackbar(activity, R.string.i2p_not_running);
+ mEventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_not_running));
return false;
} else if (!mI2PHelper.areTunnelsActive()) {
- Utils.showSnackbar(activity, R.string.i2p_tunnels_not_ready);
+ mEventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_tunnels_not_ready));
return false;
}
}
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 d49f9f2..f450692 100644
--- a/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java
+++ b/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java
@@ -10,6 +10,7 @@ import net.i2p.android.ui.I2PAndroidHelper;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@@ -27,7 +28,7 @@ public class ProxyUtils {
private static ProxyUtils mInstance;
private ProxyUtils(Context context) {
- mPreferences = PreferenceManager.getInstance();
+ mPreferences = BrowserApp.getAppComponent().getPreferenceManager();
mI2PHelper = new I2PAndroidHelper(context.getApplicationContext());
}
@@ -143,13 +144,15 @@ public class ProxyUtils {
}
- public boolean isProxyReady(Activity activity) {
+ public boolean isProxyReady() {
if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) {
if (!mI2PHelper.isI2PAndroidRunning()) {
- Utils.showSnackbar(activity, R.string.i2p_not_running);
+ BrowserApp.getAppComponent().getBus()
+ .post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_not_running));
return false;
} else if (!mI2PHelper.areTunnelsActive()) {
- Utils.showSnackbar(activity, R.string.i2p_tunnels_not_ready);
+ BrowserApp.getAppComponent().getBus()
+ .post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_tunnels_not_ready));
return false;
}
}
@@ -200,7 +203,7 @@ public class ProxyUtils {
break;
case Constants.PROXY_I2P:
- I2PAndroidHelper ih = new I2PAndroidHelper(activity.getApplicationContext());
+ I2PAndroidHelper ih = new I2PAndroidHelper(BrowserApp.getAppContext());
if (!ih.isI2PAndroidInstalled()) {
choice = Constants.NO_PROXY;
ih.promptToInstall(activity);
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 dd33312..88df5b2 100644
--- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
@@ -11,6 +11,7 @@ import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -18,14 +19,8 @@ import android.content.IntentFilter;
import android.database.sqlite.SQLiteException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
import android.graphics.PorterDuff;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaPlayer;
@@ -38,17 +33,15 @@ import android.provider.MediaStore;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.DrawerLayout.DrawerListener;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.graphics.Palette;
import android.support.v7.graphics.drawable.DrawerArrowDrawable;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.KeyEvent;
@@ -76,7 +69,6 @@ import android.webkit.ValueCallback;
import android.webkit.WebChromeClient.CustomViewCallback;
import android.webkit.WebIconDatabase;
import android.webkit.WebView;
-import android.webkit.WebView.HitTestResult;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
@@ -95,8 +87,6 @@ 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.util.ArrayList;
import java.util.List;
@@ -107,14 +97,17 @@ 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.bus.NavigationEvents;
+import acr.browser.lightning.bus.TabEvents;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.controller.BrowserController;
import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryDatabase;
-import acr.browser.lightning.dialog.BookmarksDialogBuilder;
-import acr.browser.lightning.object.ClickHandler;
+import acr.browser.lightning.dialog.LightningDialogBuilder;
+import acr.browser.lightning.fragment.BookmarksFragment;
+import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.SearchAdapter;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.receiver.NetworkReceiver;
@@ -157,12 +150,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
RelativeLayout mSearchBar;
- // Browser Views
- private final List mWebViewList = new ArrayList<>();
- private LightningView mCurrentView;
- private WebView mWebView;
- private RecyclerView mTabListView;
-
// Toolbar Views
private AutoCompleteTextView mSearch;
private ImageView mArrowImage;
@@ -173,11 +160,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private View mCustomView;
// Adapter
- private LightningViewAdapter mTabAdapter;
private SearchAdapter mSearchAdapter;
// Callback
- private ClickHandler mClickHandler;
private CustomViewCallback mCustomViewCallback;
private ValueCallback mUploadMessage;
private ValueCallback mFilePathCallback;
@@ -192,10 +177,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mCurrentUiColor = Color.BLACK;
private String mSearchText, mUntitledTitle, mHomepage, mCameraPhotoPath;
- // Storage
- private HistoryDatabase mHistoryDatabase;
- private final PreferenceManager mPreferences = PreferenceManager.getInstance();
-
// The singleton BookmarkManager
@Inject
BookmarkManager mBookmarkManager;
@@ -208,7 +189,15 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
BookmarkPage mBookmarkPage;
@Inject
- BookmarksDialogBuilder mBookmarksDialogBuilder;
+ LightningDialogBuilder bookmarksDialogBuilder;
+
+ @Inject
+ TabsManager tabsManager;
+
+ // Preference manager was moved on ThemeableBrowserActivity
+
+ @Inject
+ HistoryDatabase mHistoryDatabase;
// Image
private Bitmap mWebpageBitmap;
@@ -229,7 +218,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
public abstract boolean isIncognito();
- abstract void initializeTabs();
+// abstract void initializeTabs();
abstract void closeActivity();
@@ -257,18 +246,16 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mIconColor = mDarkTheme ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this);
mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet());
- mWebViewList.clear();
- mClickHandler = new ClickHandler(this);
// initialize background ColorDrawable
mBackground.setColor(((ColorDrawable) mToolbarLayout.getBackground()).getColor());
- setupFrameLayoutButton(R.id.new_tab_button, R.id.icon_plus);
// Drawer stutters otherwise
mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mDrawerRight.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon);
- tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+// TODO Please review this
+// ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon);
+// tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !mShowTabsInDrawer) {
getWindow().setStatusBarColor(Color.BLACK);
@@ -281,31 +268,28 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mHomepage = mPreferences.getHomepage();
- RecyclerView horizontalListView = (RecyclerView) findViewById(R.id.twv_list);
+ final TabsFragment tabsFragment = new TabsFragment();
+ final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container;
+ final Bundle tabsFragmentArguments = new Bundle();
+ tabsFragmentArguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito());
+ tabsFragmentArguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer);
+ tabsFragment.setArguments(tabsFragmentArguments);
+ final BookmarksFragment bookmarksFragment = new BookmarksFragment();
+ final Bundle bookmarksFragmentArguments = new Bundle();
+ bookmarksFragmentArguments.putBoolean(BookmarksFragment.INCOGNITO_MODE, isIncognito());
+ bookmarksFragment.setArguments(bookmarksFragmentArguments);
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ fragmentManager
+ .beginTransaction()
+ .add(containerId, tabsFragment)
+ .add(R.id.right_drawer, bookmarksFragment)
+ .commit();
if (mShowTabsInDrawer) {
- mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, mWebViewList);
- mTabListView = (RecyclerView) findViewById(R.id.left_drawer_list);
- mTabListView.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS);
- RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
- mTabListView.setLayoutManager(layoutManager);
- mTabListView.setHasFixedSize(true);
- mToolbarLayout.removeView(horizontalListView);
- } else {
- mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item_horizontal, mWebViewList);
- mTabListView = horizontalListView;
- mTabListView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft);
- RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
- mTabListView.setLayoutManager(layoutManager);
- mTabListView.setHasFixedSize(true);
+ mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container));
}
- mTabListView.setAdapter(mTabAdapter);
-
- mHistoryDatabase = HistoryDatabase.getInstance();
-
if (actionBar == null)
return;
@@ -336,12 +320,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mProxyUtils = ProxyUtils.getInstance();
- setupFrameLayoutButton(R.id.action_back, R.id.icon_back);
- setupFrameLayoutButton(R.id.action_forward, R.id.icon_forward);
- setupFrameLayoutButton(R.id.action_toggle_desktop, R.id.icon_desktop);
- setupFrameLayoutButton(R.id.action_reading, R.id.icon_reading);
- setupFrameLayoutButton(R.id.action_home, R.id.icon_home);
-
// create the search EditText in the ToolBar
mSearch = (AutoCompleteTextView) customView.findViewById(R.id.search);
mUntitledTitle = getString(R.string.untitled);
@@ -379,7 +357,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath());
}
- initializeTabs();
+ tabsManager.restoreTabs(this, mDarkTheme, isIncognito());
+ // At this point we always have at least a tab in the tab manager
+ showTab(0);
mProxyUtils.checkForProxy(this);
}
@@ -394,8 +374,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
searchTheWeb(mSearch.getText().toString());
- if (mCurrentView != null) {
- mCurrentView.requestFocus();
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.requestFocus();
}
return true;
default:
@@ -416,8 +397,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
searchTheWeb(mSearch.getText().toString());
- if (mCurrentView != null) {
- mCurrentView.requestFocus();
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.requestFocus();
}
return true;
}
@@ -426,11 +408,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public void onFocusChange(View v, final boolean hasFocus) {
- if (!hasFocus && mCurrentView != null) {
- setIsLoading(mCurrentView.getProgress() < 100);
- updateUrl(mCurrentView.getUrl(), true);
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (!hasFocus && currentView != null) {
+ setIsLoading(currentView.getProgress() < 100);
+ updateUrl(currentView.getUrl(), true);
} else if (hasFocus) {
- String url = mCurrentView.getUrl();
+ String url = currentView.getUrl();
if (url.startsWith(Constants.FILE)) {
mSearch.setText("");
} else {
@@ -581,54 +564,17 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
}
- void restoreOrNewTab() {
- mIdGenerator = 0;
-
- String url = null;
- if (getIntent() != null) {
- url = getIntent().getDataString();
- if (url != null) {
- if (url.startsWith(Constants.FILE)) {
- Utils.showSnackbar(this, R.string.message_blocked_local);
- url = null;
- }
- }
- }
- if (mPreferences.getRestoreLostTabsEnabled()) {
- String mem = mPreferences.getMemoryUrl();
- mPreferences.setMemoryUrl("");
- String[] array = Utils.getArray(mem);
- int count = 0;
- for (String urlString : array) {
- if (!urlString.isEmpty()) {
- if (url != null && url.compareTo(urlString) == 0) {
- url = null;
- }
- newTab(urlString, true);
- count++;
- }
- }
- if (url != null) {
- newTab(url, true);
- } else if (count == 0) {
- newTab(null, true);
- }
- } else {
- newTab(url, true);
- }
- }
-
private void initializePreferences() {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentView.getWebView();
mFullScreen = mPreferences.getFullScreenEnabled();
mColorMode = mPreferences.getColorModeEnabled();
mColorMode &= !mDarkTheme;
if (!isIncognito() && !mColorMode && !mDarkTheme && mWebpageBitmap != null) {
changeToolbarBackground(mWebpageBitmap, null);
- mTabAdapter.notifyDataSetChanged();
- } else if (!isIncognito() && mCurrentView != null && !mDarkTheme
- && mCurrentView.getFavicon() != null) {
- changeToolbarBackground(mCurrentView.getFavicon(), null);
- mTabAdapter.notifyDataSetChanged();
+ } else if (!isIncognito() && currentView != null && !mDarkTheme
+ && currentView.getFavicon() != null) {
+ changeToolbarBackground(currentView.getFavicon(), null);
}
if (mFullScreen) {
@@ -638,8 +584,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
height = mToolbarLayout.getMeasuredHeight();
}
- if (mWebView != null)
- mWebView.setTranslationY(height);
+ if (currentWebView != null)
+ currentWebView.setTranslationY(height);
mBrowserFrame.setLayoutTransition(null);
if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) {
mUiLayout.removeView(mToolbarLayout);
@@ -653,8 +599,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mUiLayout.addView(mToolbarLayout, 0);
}
mBrowserFrame.setLayoutTransition(new LayoutTransition());
- if (mWebView != null)
- mWebView.setTranslationY(0);
+ if (currentWebView != null)
+ currentWebView.setTranslationY(0);
}
setFullscreen(mPreferences.getHideStatusBarEnabled(), false);
@@ -731,6 +677,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ final LightningView currentView = tabsManager.getCurrentTab();
// Handle action buttons
switch (item.getItemId()) {
case android.R.id.home:
@@ -739,13 +686,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
return true;
case R.id.action_back:
- if (mCurrentView != null && mCurrentView.canGoBack()) {
- mCurrentView.goBack();
+ if (currentView != null && currentView.canGoBack()) {
+ currentView.goBack();
}
return true;
case R.id.action_forward:
- if (mCurrentView != null && mCurrentView.canGoForward()) {
- mCurrentView.goForward();
+ if (currentView != null && currentView.canGoForward()) {
+ currentView.goForward();
}
return true;
case R.id.action_new_tab:
@@ -756,11 +703,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
overridePendingTransition(R.anim.slide_up_in, R.anim.fade_out_scale);
return true;
case R.id.action_share:
- if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) {
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
- shareIntent.putExtra(Intent.EXTRA_SUBJECT, mCurrentView.getTitle());
- shareIntent.putExtra(Intent.EXTRA_TEXT, mCurrentView.getUrl());
+ shareIntent.putExtra(Intent.EXTRA_SUBJECT, currentView.getTitle());
+ shareIntent.putExtra(Intent.EXTRA_TEXT, currentView.getUrl());
startActivity(Intent.createChooser(shareIntent, getResources().getString(R.string.dialog_title_share)));
}
return true;
@@ -768,9 +715,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
openBookmarks();
return true;
case R.id.action_copy:
- if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) {
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("label", mCurrentView.getUrl());
+ ClipData clip = ClipData.newPlainText("label", currentView.getUrl());
clipboard.setPrimaryClip(clip);
Utils.showSnackbar(this, R.string.message_link_copied);
}
@@ -782,9 +729,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
openHistory();
return true;
case R.id.action_add_bookmark:
- if (mCurrentView != null && !mCurrentView.getUrl().startsWith(Constants.FILE)) {
- mEventBus.post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(),
- mCurrentView.getUrl()));
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
+ mEventBus.post(new BrowserEvents.AddBookmark(currentView.getTitle(),
+ currentView.getUrl()));
}
return true;
case R.id.action_find:
@@ -792,7 +739,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
return true;
case R.id.action_reading_mode:
Intent read = new Intent(this, ReadingActivity.class);
- read.putExtra(Constants.LOAD_READING_URL, mCurrentView.getUrl());
+ read.putExtra(Constants.LOAD_READING_URL, currentView.getUrl());
startActivity(read);
return true;
default:
@@ -824,8 +771,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
private void showSearchInterfaceBar(String text) {
- if (mCurrentView != null) {
- mCurrentView.find(text);
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.find(text);
}
mSearchBar.setVisibility(View.VISIBLE);
@@ -870,66 +818,43 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
builder.show();
}
- /**
- * The click listener for ListView in the navigation drawer
- */
- private class DrawerItemClickListener implements OnClickListener {
-
- @Override
- public void onClick(View v) {
- int position = mTabListView.getChildAdapterPosition(v);
- if (mCurrentView != mWebViewList.get(position)) {
- mIsNewIntent = false;
- showTab(mWebViewList.get(position));
- }
- }
- }
-
- /**
- * long click listener for Navigation Drawer
- */
- private class DrawerItemLongClickListener implements OnLongClickListener {
-
- @Override
- public boolean onLongClick(View v) {
- int position = mTabListView.getChildAdapterPosition(v);
- showCloseDialog(position);
- return true;
- }
- }
-
/**
* displays the WebView contained in the LightningView Also handles the
* removal of previous views
*
- * @param view the LightningView to show
+ * @param position the poition of the tab to display
*/
- private synchronized void showTab(LightningView view) {
+ private synchronized void showTab(final int position) {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentView != null ? currentView.getWebView() : null;
+ final LightningView newView = tabsManager.switchToTab(position);
+ final WebView newWebView = newView != null ? newView.getWebView() : null;
+
// Set the background color so the color mode color doesn't show through
mBrowserFrame.setBackgroundColor(mBackgroundColor);
- if (view == null || (view == mCurrentView && !mCurrentView.isShown())) {
+ if (newView == currentView && !currentView.isShown()) {
return;
}
+ mIsNewIntent = false;
+
final float translation = mToolbarLayout.getTranslationY();
mBrowserFrame.removeAllViews();
- if (mCurrentView != null) {
- mCurrentView.setForegroundTab(false);
- mCurrentView.onPause();
+ if (currentView != null) {
+ currentView.setForegroundTab(false);
+ currentView.onPause();
}
- mCurrentView = view;
- mWebView = view.getWebView();
- mCurrentView.setForegroundTab(true);
- if (mWebView != null) {
- updateUrl(mCurrentView.getUrl(), true);
- updateProgress(mCurrentView.getProgress());
+ newView.setForegroundTab(true);
+ if (currentWebView != null) {
+ updateUrl(newView.getUrl(), true);
+ updateProgress(newView.getProgress());
} else {
updateUrl("", true);
updateProgress(0);
}
- mBrowserFrame.addView(mWebView, MATCH_PARENT);
- mCurrentView.requestFocus();
- mCurrentView.onResume();
+ mBrowserFrame.addView(newWebView, MATCH_PARENT);
+ newView.requestFocus();
+ newView.onResume();
if (mFullScreen) {
// mToolbarLayout has already been removed
@@ -941,10 +866,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
height = mToolbarLayout.getMeasuredHeight();
}
- mWebView.setTranslationY(translation + height);
+ newWebView.setTranslationY(translation + height);
mToolbarLayout.setTranslationY(translation);
} else {
- mWebView.setTranslationY(0);
+ newWebView.setTranslationY(0);
}
showActionBar();
@@ -960,7 +885,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}, 200);
// Should update the bookmark status in BookmarksFragment
- mEventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl()));
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(newView.getUrl()));
// new Handler().postDelayed(new Runnable() {
// @Override
@@ -998,17 +923,20 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
private void loadUrlInCurrentView(final String url) {
- if (mCurrentView == null) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab == null) {
+ // This is a problem, probably an assert will be better than a return
return;
}
- mCurrentView.loadUrl(url);
+ currentTab.loadUrl(url);
mEventBus.post(new BrowserEvents.CurrentPageUrl(url));
}
@Override
public void closeEmptyTab() {
- if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) {
+ final WebView currentWebView = tabsManager.getCurrentWebView();
+ if (currentWebView != null && currentWebView.copyBackForwardList().getSize() == 0) {
closeCurrentTab();
}
}
@@ -1021,99 +949,93 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
public void onTrimMemory(int level) {
if (level > TRIM_MEMORY_MODERATE && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
Log.d(Constants.TAG, "Low Memory, Free Memory");
- for (int n = 0, size = mWebViewList.size(); n < size; n++) {
- mWebViewList.get(n).freeMemory();
- }
+ tabsManager.freeMemory();
}
}
synchronized boolean newTab(String url, boolean show) {
// Limit number of tabs for limited version of app
- if (!Constants.FULL_VERSION && mWebViewList.size() >= 10) {
+ if (!Constants.FULL_VERSION && tabsManager.size() >= 10) {
Utils.showSnackbar(this, R.string.max_tabs);
return false;
}
mIsNewIntent = false;
- LightningView startingTab = new LightningView(this, url, mDarkTheme, isIncognito(), this);
+ LightningView startingTab = tabsManager.newTab(this, url, mDarkTheme, isIncognito());
if (mIdGenerator == 0) {
startingTab.resumeTimers();
}
mIdGenerator++;
- mWebViewList.add(startingTab);
if (show) {
- showTab(startingTab);
+ showTab(tabsManager.size() - 1);
}
- updateTabs();
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- mTabListView.smoothScrollToPosition(mWebViewList.size() - 1);
- }
- }, 300);
+ // TODO Check is this is callable directly from LightningView
+ mEventBus.post(new BrowserEvents.TabsChanged());
+
+// TODO Restore this
+// new Handler().postDelayed(new Runnable() {
+// @Override
+// public void run() {
+// mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1);
+// }
+// }, 300);
return true;
}
private synchronized void deleteTab(int position) {
- if (position >= mWebViewList.size()) {
+ final LightningView tabToDelete = tabsManager.getTabAtPosition(position);
+ final LightningView currentTab = tabsManager.getCurrentTab();
+
+ if (tabToDelete == null) {
return;
}
- int current = mWebViewList.indexOf(mCurrentView);
+// What?
+ int current = tabsManager.positionOf(currentTab);
if (current < 0) {
return;
}
- LightningView reference = mWebViewList.get(position);
- if (reference == null) {
- return;
+ if (!tabToDelete.getUrl().startsWith(Constants.FILE) && !isIncognito()) {
+ mPreferences.setSavedUrl(tabToDelete.getUrl());
}
- if (!reference.getUrl().startsWith(Constants.FILE) && !isIncognito()) {
- mPreferences.setSavedUrl(reference.getUrl());
- }
- boolean isShown = reference.isShown();
+ final boolean isShown = tabToDelete.isShown();
if (isShown) {
mBrowserFrame.setBackgroundColor(mBackgroundColor);
}
if (current > position) {
- mWebViewList.remove(position);
- updateTabs();
- reference.onDestroy();
- } else if (mWebViewList.size() > position + 1) {
+ tabsManager.deleteTab(position);
+ showTab(current - 1);
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ } else if (tabsManager.size() > position + 1) {
if (current == position) {
- showTab(mWebViewList.get(position + 1));
- mWebViewList.remove(position);
- updateTabs();
+ showTab(position + 1);
+ tabsManager.deleteTab(position);
+ showTab(position);
+ mEventBus.post(new BrowserEvents.TabsChanged());
} else {
- mWebViewList.remove(position);
+ tabsManager.deleteTab(position);
}
-
- reference.onDestroy();
- } else if (mWebViewList.size() > 1) {
+ } else if (tabsManager.size() > 1) {
if (current == position) {
- showTab(mWebViewList.get(position - 1));
- mWebViewList.remove(position);
- updateTabs();
+ showTab(position - 1);
+ tabsManager.deleteTab(position);
+ showTab(position - 1);
+ mEventBus.post(new BrowserEvents.TabsChanged());
} else {
- mWebViewList.remove(position);
}
-
- reference.onDestroy();
} else {
- if (mCurrentView.getUrl().startsWith(Constants.FILE) || mCurrentView.getUrl().equals(mHomepage)) {
+ if (currentTab.getUrl().startsWith(Constants.FILE) || currentTab.getUrl().equals(mHomepage)) {
closeActivity();
} else {
- mWebViewList.remove(position);
+ tabsManager.deleteTab(position);
performExitCleanUp();
- reference.pauseTimers();
- reference.onDestroy();
- mCurrentView = null;
- mWebView = null;
- mTabAdapter.notifyDataSetChanged();
+ tabToDelete.pauseTimers();
+ mEventBus.post(new BrowserEvents.TabsChanged());
finish();
}
}
- mTabAdapter.notifyDataSetChanged();
+ mEventBus.post(new BrowserEvents.TabsChanged());
if (mIsNewIntent && isShown) {
mIsNewIntent = false;
@@ -1124,8 +1046,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
private void performExitCleanUp() {
- if (mPreferences.getClearCacheExit() && mCurrentView != null && !isIncognito()) {
- WebUtils.clearCache(mCurrentView.getWebView());
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (mPreferences.getClearCacheExit() && currentTab != null && !isIncognito()) {
+ WebUtils.clearCache(currentTab.getWebView());
Log.d(Constants.TAG, "Cache Cleared");
}
if (mPreferences.getClearHistoryExitEnabled() && !isIncognito()) {
@@ -1146,8 +1069,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
if (keyCode == KeyEvent.KEYCODE_BACK) {
- showCloseDialog(mWebViewList.indexOf(mCurrentView));
+ showCloseDialog(tabsManager.positionOf(currentTab));
}
return true;
}
@@ -1155,38 +1079,32 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private void closeBrowser() {
mBrowserFrame.setBackgroundColor(mBackgroundColor);
performExitCleanUp();
- mCurrentView = null;
- mWebView = null;
- for (int n = 0, size = mWebViewList.size(); n < size; n++) {
- if (mWebViewList.get(n) != null) {
- mWebViewList.get(n).onDestroy();
- }
- }
- mWebViewList.clear();
- mTabAdapter.notifyDataSetChanged();
+ tabsManager.shutdown();
+ mEventBus.post(new BrowserEvents.TabsChanged());
finish();
}
@Override
public void onBackPressed() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) {
mDrawerLayout.closeDrawer(mDrawerLeft);
} else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) {
mEventBus
.post(new BrowserEvents.UserPressedBack());
} else {
- if (mCurrentView != null) {
+ if (currentTab != null) {
Log.d(Constants.TAG, "onBackPressed");
if (mSearch.hasFocus()) {
- mCurrentView.requestFocus();
- } else if (mCurrentView.canGoBack()) {
- if (!mCurrentView.isShown()) {
+ currentTab.requestFocus();
+ } else if (currentTab.canGoBack()) {
+ if (!currentTab.isShown()) {
onHideCustomView();
} else {
- mCurrentView.goBack();
+ currentTab.goBack();
}
} else {
- deleteTab(mWebViewList.indexOf(mCurrentView));
+ deleteTab(tabsManager.positionOf(currentTab));
}
} else {
Log.e(Constants.TAG, "This shouldn't happen ever");
@@ -1198,10 +1116,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
protected void onPause() {
super.onPause();
+ final LightningView currentTab = tabsManager.getCurrentTab();
Log.d(Constants.TAG, "onPause");
- if (mCurrentView != null) {
- mCurrentView.pauseTimers();
- mCurrentView.onPause();
+ if (currentTab != null) {
+ currentTab.pauseTimers();
+ currentTab.onPause();
}
try {
unregisterReceiver(mNetworkReceiver);
@@ -1217,12 +1136,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
void saveOpenTabs() {
if (mPreferences.getRestoreLostTabsEnabled()) {
- StringBuilder s = new StringBuilder(mWebViewList.size() * 50);
- for (int n = 0, size = mWebViewList.size(); n < size; n++) {
- if (!mWebViewList.get(n).getUrl().isEmpty()) {
- s.append(mWebViewList.get(n).getUrl()).append("|$|SEPARATOR|$|");
- }
- }
+ final String s = tabsManager.tabsString();
mPreferences.setMemoryUrl(s.toString());
}
}
@@ -1252,24 +1166,18 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
protected void onResume() {
super.onResume();
+ final LightningView currentTab = tabsManager.getCurrentTab();
Log.d(Constants.TAG, "onResume");
if (mSearchAdapter != null) {
mSearchAdapter.refreshPreferences();
mSearchAdapter.refreshBookmarks();
}
- if (mCurrentView != null) {
- mCurrentView.resumeTimers();
- mCurrentView.onResume();
+ if (currentTab != null) {
+ currentTab.resumeTimers();
+ currentTab.onResume();
}
- mHistoryDatabase = HistoryDatabase.getInstance();
initializePreferences();
- for (int n = 0, size = mWebViewList.size(); n < size; n++) {
- if (mWebViewList.get(n) != null) {
- mWebViewList.get(n).initializePreferences(null, this);
- } else {
- mWebViewList.remove(n);
- }
- }
+ tabsManager.resume(this);
supportInvalidateOptionsMenu();
@@ -1285,173 +1193,18 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
* checks if it is a search, url, etc.
*/
private void searchTheWeb(@NonNull String query) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
if (query.isEmpty()) {
return;
}
String searchUrl = mSearchText + UrlUtils.QUERY_PLACE_HOLDER;
query = query.trim();
- mCurrentView.stopLoading();
- if (mCurrentView != null) {
+ currentTab.stopLoading();
+ if (currentTab != null) {
loadUrlInCurrentView(UrlUtils.smartUrlFilter(query, true, searchUrl));
}
}
- private class LightningViewAdapter extends RecyclerView.Adapter {
-
- private final Context context;
- private final int layoutResourceId;
- private List data = null;
- private final CloseTabListener mExitListener;
- private final Drawable mBackgroundTabDrawable;
- private final Drawable mForegroundTabDrawable;
- private final Bitmap mForegroundTabBitmap;
- private final DrawerItemClickListener mClickListener;
- private final DrawerItemLongClickListener mLongClickListener;
- private ColorMatrix mColorMatrix;
- private Paint mPaint;
- private ColorFilter mFilter;
- private static final float DESATURATED = 0.5f;
-
- public LightningViewAdapter(Context context, int layoutResourceId, List data) {
- this.layoutResourceId = layoutResourceId;
- this.context = context;
- this.data = data;
- this.mExitListener = new CloseTabListener();
- this.mClickListener = new DrawerItemClickListener();
- this.mLongClickListener = new DrawerItemLongClickListener();
-
- if (mShowTabsInDrawer) {
- mBackgroundTabDrawable = null;
- mForegroundTabBitmap = null;
- mForegroundTabDrawable = ThemeUtils.getSelectedBackground(context, mDarkTheme);
- } else {
- int backgroundColor = Utils.mixTwoColors(ThemeUtils.getPrimaryColor(context), Color.BLACK, 0.75f);
- Bitmap backgroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
- Utils.drawTrapezoid(new Canvas(backgroundTabBitmap), backgroundColor, true);
- mBackgroundTabDrawable = new BitmapDrawable(getResources(), backgroundTabBitmap);
-
- int foregroundColor = ThemeUtils.getPrimaryColor(context);
- mForegroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
- Utils.drawTrapezoid(new Canvas(mForegroundTabBitmap), foregroundColor, false);
- mForegroundTabDrawable = null;
- }
- }
-
- @Override
- public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
- LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
- View view = inflater.inflate(layoutResourceId, viewGroup, false);
- return new LightningViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(final LightningViewHolder holder, int position) {
- holder.exitButton.setTag(position);
- holder.exitButton.setOnClickListener(mExitListener);
- holder.layout.setOnClickListener(mClickListener);
- holder.layout.setOnLongClickListener(mLongClickListener);
-
- ViewCompat.jumpDrawablesToCurrentState(holder.exitButton);
-
- LightningView web = data.get(position);
- holder.txtTitle.setText(web.getTitle());
-
- final Bitmap favicon = web.getFavicon();
- if (web.isForegroundTab()) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- holder.txtTitle.setTextAppearance(R.style.boldText);
- } else {
- //noinspection deprecation
- holder.txtTitle.setTextAppearance(context, R.style.boldText);
- }
- Drawable foregroundDrawable;
- if (!mShowTabsInDrawer) {
- foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap);
- if (!isIncognito() && mColorMode) {
- foregroundDrawable.setColorFilter(mCurrentUiColor, PorterDuff.Mode.SRC_IN);
- }
- } else {
- foregroundDrawable = mForegroundTabDrawable;
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- holder.layout.setBackground(foregroundDrawable);
- } else {
- //noinspection deprecation
- holder.layout.setBackgroundDrawable(foregroundDrawable);
- }
- if (!isIncognito() && mColorMode) {
- changeToolbarBackground(favicon, foregroundDrawable);
- }
- holder.favicon.setImageBitmap(favicon);
- } else {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- holder.txtTitle.setTextAppearance(R.style.normalText);
- } else {
- //noinspection deprecation
- holder.txtTitle.setTextAppearance(context, R.style.normalText);
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- holder.layout.setBackground(mBackgroundTabDrawable);
- } else {
- //noinspection deprecation
- holder.layout.setBackgroundDrawable(mBackgroundTabDrawable);
- }
-
- holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon));
- }
- }
-
- @Override
- public int getItemCount() {
- return (data != null) ? data.size() : 0;
- }
-
- public Bitmap getDesaturatedBitmap(Bitmap favicon) {
- Bitmap grayscaleBitmap = Bitmap.createBitmap(favicon.getWidth(),
- favicon.getHeight(), Bitmap.Config.ARGB_8888);
-
- Canvas c = new Canvas(grayscaleBitmap);
- if (mColorMatrix == null || mFilter == null || mPaint == null) {
- mPaint = new Paint();
- mColorMatrix = new ColorMatrix();
- mColorMatrix.setSaturation(DESATURATED);
- mFilter = new ColorMatrixColorFilter(mColorMatrix);
- mPaint.setColorFilter(mFilter);
- }
-
- c.drawBitmap(favicon, 0, 0, mPaint);
- return grayscaleBitmap;
- }
-
- public class LightningViewHolder extends RecyclerView.ViewHolder {
-
- public LightningViewHolder(View view) {
- super(view);
- txtTitle = (TextView) view.findViewById(R.id.textTab);
- favicon = (ImageView) view.findViewById(R.id.faviconTab);
- exit = (ImageView) view.findViewById(R.id.deleteButton);
- layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
- exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
- exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
- }
-
- final TextView txtTitle;
- final ImageView favicon;
- final ImageView exit;
- final FrameLayout exitButton;
- final LinearLayout layout;
- }
- }
-
- private class CloseTabListener implements OnClickListener {
-
- @Override
- public void onClick(View v) {
- deleteTab((int) v.getTag());
- }
-
- }
-
/**
* 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
@@ -1510,6 +1263,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public void updateUrl(String url, boolean shortUrl) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
if (url == null || mSearch == null || mSearch.hasFocus()) {
return;
}
@@ -1525,8 +1279,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mSearch.setText(url);
break;
case 2: // Title, show the page's title
- if (mCurrentView != null && !mCurrentView.getTitle().isEmpty()) {
- mSearch.setText(mCurrentView.getTitle());
+ if (currentTab != null && !currentTab.getTitle().isEmpty()) {
+ mSearch.setText(currentTab.getTitle());
} else {
mSearch.setText(mUntitledTitle);
}
@@ -1551,9 +1305,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public void run() {
try {
- if (mHistoryDatabase == null) {
- mHistoryDatabase = HistoryDatabase.getInstance();
- }
mHistoryDatabase.visitHistoryItem(url, title);
} catch (IllegalStateException e) {
Log.e(Constants.TAG, "IllegalStateException in updateHistory", e);
@@ -1574,7 +1325,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
* previously searched URLs
*/
private void initializeSearchSuggestions(final AutoCompleteTextView getUrl) {
-
+ final LightningView currentTab = tabsManager.getCurrentTab();
getUrl.setThreshold(1);
getUrl.setDropDownWidth(-1);
getUrl.setDropDownAnchor(R.id.toolbar_layout);
@@ -1593,8 +1344,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
searchTheWeb(url);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getUrl.getWindowToken(), 0);
- if (mCurrentView != null) {
- mCurrentView.requestFocus();
+ if (currentTab != null) {
+ currentTab.requestFocus();
}
} catch (NullPointerException e) {
Log.e("Browser Error: ", "NullPointerException on item click");
@@ -1608,11 +1359,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
getUrl.setAdapter(mSearchAdapter);
}
- @Override
- public boolean proxyIsNotReady() {
- return !mProxyUtils.isProxyReady(this);
- }
-
/**
* function that opens the HTML history page in the browser
*/
@@ -1655,36 +1401,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
return super.onCreateOptionsMenu(menu);
}
- /**
- * open the HTML bookmarks page, parameter view is the WebView that should show the page
- */
- @Override
- public void openBookmarkPage(WebView view) {
- if (view == null)
- return;
- Bitmap folderIcon = ThemeUtils.getThemedBitmap(this, R.drawable.ic_folder, false);
- FileOutputStream outputStream = null;
- File image = new File(this.getCacheDir(), "folder.png");
- try {
- outputStream = new FileOutputStream(image);
- folderIcon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
- folderIcon.recycle();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } finally {
- Utils.close(outputStream);
- }
- File bookmarkWebPage = new File(this.getFilesDir(), Constants.BOOKMARKS_FILENAME);
-
- mBookmarkPage.buildBookmarkPage(null, mBookmarkManager.getBookmarksFromFolder(null, true));
- view.loadUrl(Constants.FILE + bookmarkWebPage);
- }
-
- @Override
- public void updateTabs() {
- mTabAdapter.notifyDataSetChanged();
- }
-
/**
* opens a file chooser
* param ValueCallback is the message from the WebView indicating a file chooser
@@ -1789,25 +1505,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
this.startActivityForResult(chooserIntent, 1);
}
- /**
- * handles long presses for the browser, tries to get the
- * url of the item that was clicked and sends it (it can be null)
- * to the click handler that does cool stuff with it
- */
- @Override
- public void onLongPress() {
- if (mClickHandler == null) {
- mClickHandler = new ClickHandler(this);
- }
- Message click = mClickHandler.obtainMessage();
- if (click != null) {
- click.setTarget(mClickHandler);
- mWebView.requestFocusNodeHref(click);
- }
- }
-
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
if (view == null) {
return;
}
@@ -1828,7 +1528,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mFullscreenContainer.addView(mCustomView, COVER_SCREEN_PARAMS);
decor.addView(mFullscreenContainer, COVER_SCREEN_PARAMS);
setFullscreen(true, true);
- mCurrentView.setVisibility(View.GONE);
+ currentTab.setVisibility(View.GONE);
if (view instanceof FrameLayout) {
if (((FrameLayout) view).getFocusedChild() instanceof VideoView) {
mVideoView = (VideoView) ((FrameLayout) view).getFocusedChild();
@@ -1841,11 +1541,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public void onHideCustomView() {
- if (mCustomView == null || mCustomViewCallback == null || mCurrentView == null) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (mCustomView == null || mCustomViewCallback == null || currentTab == null) {
return;
}
Log.d(Constants.TAG, "onHideCustomView");
- mCurrentView.setVisibility(View.VISIBLE);
+ currentTab.setVisibility(View.VISIBLE);
try {
mCustomView.setKeepScreenOn(false);
} catch (SecurityException e) {
@@ -1930,32 +1631,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
}
- /**
- * This interface method is used by the LightningView to obtain an
- * image that is displayed as a placeholder on a video until the video
- * has initialized and can begin loading.
- *
- * @return a Bitmap that can be used as a place holder for videos.
- */
- @Override
- public Bitmap getDefaultVideoPoster() {
- return BitmapFactory.decodeResource(getResources(), android.R.drawable.spinner_background);
- }
-
- /**
- * An interface method so that we can inflate a view to send to
- * a LightningView when it needs to display a video and has to
- * show a loading dialog. Inflates a progress view and returns it.
- *
- * @return A view that should be used to display the state
- * of a video's loading progress.
- */
- @Override
- public View getVideoLoadingProgressView() {
- LayoutInflater inflater = LayoutInflater.from(this);
- return inflater.inflate(R.layout.video_loading_progress, null);
- }
-
/**
* This method handles the JavaScript callback to create a new tab.
* Basically this handles the event that JavaScript needs to create
@@ -1970,8 +1645,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
return;
}
if (newTab("", true)) {
+ // TODO Review this
+ final WebView webView = tabsManager.getTabAtPosition(tabsManager.size() - 1).getWebView();
WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
- transport.setWebView(mWebView);
+ transport.setWebView(webView);
resultMsg.sendToTarget();
}
}
@@ -1986,7 +1663,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Override
public void onCloseWindow(LightningView view) {
- deleteTab(mWebViewList.indexOf(view));
+ deleteTab(tabsManager.positionOf(view));
}
/**
@@ -1996,6 +1673,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Override
public void hideActionBar() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
if (mFullScreen) {
if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) {
mUiLayout.removeView(mToolbarLayout);
@@ -2003,13 +1682,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mToolbarLayout.bringToFront();
Log.d(Constants.TAG, "Move view to browser frame");
mToolbarLayout.setTranslationY(0);
- mWebView.setTranslationY(mToolbarLayout.getHeight());
+ currentWebView.setTranslationY(mToolbarLayout.getHeight());
}
- if (mToolbarLayout == null || mCurrentView == null)
+ if (mToolbarLayout == null || currentTab == null)
return;
final int height = mToolbarLayout.getHeight();
- final WebView view = mWebView;
+ final WebView view = currentWebView;
if (mToolbarLayout.getTranslationY() > -0.01f) {
Animation show = new Animation() {
@Override
@@ -2022,7 +1701,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
};
show.setDuration(250);
show.setInterpolator(new DecelerateInterpolator());
- mWebView.startAnimation(show);
+ currentWebView.startAnimation(show);
}
}
}
@@ -2035,6 +1714,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
@Override
public void showActionBar() {
if (mFullScreen) {
+ final WebView view = tabsManager.getCurrentWebView();
if (mToolbarLayout == null)
return;
@@ -2051,12 +1731,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
mToolbarLayout.bringToFront();
Log.d(Constants.TAG, "Move view to browser frame");
mToolbarLayout.setTranslationY(0);
- mWebView.setTranslationY(height);
+ if (view != null) {
+ view.setTranslationY(height);
}
- if (mCurrentView == null)
+ }
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab == null)
return;
- final WebView view = mWebView;
final int totalHeight = height;
if (mToolbarLayout.getTranslationY() < -(height - 0.01f)) {
Animation show = new Animation() {
@@ -2071,190 +1753,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
};
show.setDuration(250);
show.setInterpolator(new DecelerateInterpolator());
- mWebView.startAnimation(show);
+ if (view != null) {
+ view.startAnimation(show);
}
- }
- }
-
- /**
- * Handle a long-press on the current web page. The WebView provides
- * a URL to this method that it thinks is what the user has long-pressed.
- * This may be different than what the user actually long-pressed, e.g. in
- * the case of an image link you may want to provide options for both the
- * image and the link. This method also handles the event that the WebView
- * was not able to get a URL from the event in which case we need to drill
- * down using {@link HitTestResult} and obtain the URL that is at the root
- * of their press. This method is responsible with delegating the dialog
- * creation to one of the several other methods in this class.
- *
- * @param url the URL that was retrieved from the WebView in
- * the long-press event.
- */
- @Override
- public void longClickPage(final String url) {
- HitTestResult result = null;
- String currentUrl = null;
- if (mWebView != null) {
- result = mWebView.getHitTestResult();
- currentUrl = mWebView.getUrl();
- }
- if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) {
- if (currentUrl.endsWith(HistoryPage.FILENAME)) {
- if (url != null) {
- longPressHistoryLink(url);
- } else if (result != null && result.getExtra() != null) {
- final String newUrl = result.getExtra();
- longPressHistoryLink(newUrl);
- }
- } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) {
- if (url != null) {
- mBookmarksDialogBuilder.showLongPressedDialogForUrl(this, url);
- } else if (result != null && result.getExtra() != null) {
- final String newUrl = result.getExtra();
- mBookmarksDialogBuilder.showLongPressedDialogForUrl(this, newUrl);
}
}
- } else {
- if (url != null) {
- if (result != null) {
- if (result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == HitTestResult.IMAGE_TYPE) {
- longPressImage(url);
- } else {
- longPressLink(url);
- }
- } else {
- longPressLink(url);
- }
- } else if (result != null && result.getExtra() != null) {
- final String newUrl = result.getExtra();
- if (result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == HitTestResult.IMAGE_TYPE) {
- longPressImage(newUrl);
- } else {
- longPressLink(newUrl);
- }
- }
- }
- }
-
- /**
- * Handle the event that the user has long-pressed an item on the {@link HistoryPage}.
- * In this case we wish to present the user with a dialog with a few options:
- * open the history item in a new tab, delete the history item, or open the
- * item in the current tab.
- *
- * @param url the URL of the history item.
- */
- private void longPressHistoryLink(final String url) {
- DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- newTab(url, false);
- mDrawerLayout.closeDrawers();
- break;
-
- case DialogInterface.BUTTON_NEGATIVE:
- mHistoryDatabase.deleteHistoryItem(url);
- openHistory();
- break;
-
- case DialogInterface.BUTTON_NEUTRAL:
- if (mCurrentView != null) {
- loadUrlInCurrentView(url);
- }
- break;
- }
- }
- };
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.action_history)
- .setMessage(R.string.dialog_history_long_press)
- .setCancelable(true)
- .setPositiveButton(R.string.action_new_tab, dialogClickListener)
- .setNegativeButton(R.string.action_delete, dialogClickListener)
- .setNeutralButton(R.string.action_open, dialogClickListener)
- .show();
- }
-
- /**
- * Handle the event that the user has long-pressed on an image link
- * and provide them with various options for things to do with that image.
- * Options include opening the image in a new tab, loading the image in the
- * current tab, or downloading the image.
- *
- * @param url the URL of the image that was retrieved from long-press.
- */
- private void longPressImage(final String url) {
- DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- newTab(url, false);
- break;
-
- case DialogInterface.BUTTON_NEGATIVE:
- loadUrlInCurrentView(url);
- break;
-
- case DialogInterface.BUTTON_NEUTRAL:
- Utils.downloadFile(BrowserActivity.this, url,
- mCurrentView.getUserAgent(), "attachment");
- break;
- }
- }
- };
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(url.replace(Constants.HTTP, ""))
- .setCancelable(true)
- .setMessage(R.string.dialog_image)
- .setPositiveButton(R.string.action_new_tab, dialogClickListener)
- .setNegativeButton(R.string.action_open, dialogClickListener)
- .setNeutralButton(R.string.action_download, dialogClickListener)
- .show();
- }
-
- /**
- * Handle the event that the user has long-pressed a link on a web page.
- * It creates a dialog with a few options on what the user can do with the
- * URL that has been retrieved from their long-press, namely, create a
- * new tab, load the URL in the current tab, or copy the link.
- *
- * @param url the URL that has been retrieved in the long-press event
- */
- private void longPressLink(final String url) {
- DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- newTab(url, false);
- break;
-
- case DialogInterface.BUTTON_NEGATIVE:
- loadUrlInCurrentView(url);
- break;
-
- case DialogInterface.BUTTON_NEUTRAL:
- ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
- ClipData clip = ClipData.newPlainText("label", url);
- clipboard.setPrimaryClip(clip);
- break;
- }
- }
- };
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this); // dialog
- builder.setTitle(url)
- .setCancelable(true)
- .setMessage(R.string.dialog_link)
- .setPositiveButton(R.string.action_new_tab, dialogClickListener)
- .setNegativeButton(R.string.action_open, dialogClickListener)
- .setNeutralButton(R.string.action_copy, dialogClickListener)
- .show();
}
/**
@@ -2275,11 +1778,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
* See setIsFinishedLoading and setIsLoading for displaying the correct icon
*/
private void refreshOrStop() {
- if (mCurrentView != null) {
- if (mCurrentView.getProgress() < 100) {
- mCurrentView.stopLoading();
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.getProgress() < 100) {
+ currentTab.stopLoading();
} else {
- mCurrentView.reload();
+ currentTab.reload();
}
}
}
@@ -2293,57 +1797,36 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Override
public void onClick(View v) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
switch (v.getId()) {
- case R.id.action_back:
- if (mCurrentView != null) {
- if (mCurrentView.canGoBack()) {
- mCurrentView.goBack();
- } else {
- deleteTab(mWebViewList.indexOf(mCurrentView));
- }
- }
- break;
- case R.id.action_forward:
- if (mCurrentView != null) {
- if (mCurrentView.canGoForward()) {
- mCurrentView.goForward();
- }
- }
- break;
case R.id.arrow_button:
if (mSearch != null && mSearch.hasFocus()) {
- mCurrentView.requestFocus();
+ currentTab.requestFocus();
} else if (mShowTabsInDrawer) {
mDrawerLayout.openDrawer(mDrawerLeft);
- } else if (mCurrentView != null) {
- mCurrentView.loadHomepage();
+ } else if (currentTab != null) {
+ currentTab.loadHomepage();
}
break;
- case R.id.new_tab_button:
- newTab(null, true);
- break;
- case R.id.action_home:
- mCurrentView.loadHomepage();
- closeDrawers();
- break;
case R.id.button_next:
- mWebView.findNext(false);
+ currentWebView.findNext(false);
break;
case R.id.button_back:
- mWebView.findNext(true);
+ currentWebView.findNext(true);
break;
case R.id.button_quit:
- mWebView.clearMatches();
+ currentWebView.clearMatches();
mSearchBar.setVisibility(View.GONE);
break;
case R.id.action_reading:
Intent read = new Intent(this, ReadingActivity.class);
- read.putExtra(Constants.LOAD_READING_URL, mCurrentView.getUrl());
+ read.putExtra(Constants.LOAD_READING_URL, currentTab.getUrl());
startActivity(read);
break;
case R.id.action_toggle_desktop:
- mCurrentView.toggleDesktopUA(this);
- mCurrentView.reload();
+ currentTab.toggleDesktopUA(this);
+ currentTab.reload();
closeDrawers();
break;
}
@@ -2361,19 +1844,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Override
public boolean onLongClick(View view) {
- switch (view.getId()) {
- case R.id.new_tab_button:
- String url = mPreferences.getSavedUrl();
- if (url != null) {
- newTab(url, true);
- Utils.showSnackbar(this, R.string.deleted_tab);
- }
- mPreferences.setSavedUrl(null);
- break;
- }
return true;
}
+ // TODO Check if all the calls are relative to TabsFragement
/**
* A utility method that creates a FrameLayout button with the given ID and
* sets the image of the button to the given image ID. The OnClick and OnLongClick
@@ -2386,10 +1860,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
* @param imageId the image to set as the button image
*/
private void setupFrameLayoutButton(@IdRes int buttonId, @IdRes int imageId) {
- View frameButton = findViewById(buttonId);
+ final View frameButton = findViewById(buttonId);
+ final ImageView buttonImage = (ImageView) findViewById(imageId);
frameButton.setOnClickListener(this);
frameButton.setOnLongClickListener(this);
- ImageView buttonImage = (ImageView) findViewById(imageId);
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}
@@ -2405,12 +1879,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
super.onReceive(context, intent);
boolean isConnected = isConnected(context);
Log.d(Constants.TAG, "Network Connected: " + String.valueOf(isConnected));
- for (int n = 0, size = mWebViewList.size(); n < size; n++) {
- WebView view = mWebViewList.get(n).getWebView();
- if (view != null)
- view.setNetworkAvailable(isConnected);
+ tabsManager.notifyConnectioneStatus(isConnected);
}
- }
};
/**
@@ -2431,14 +1901,15 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
private final Object mBusEventListener = new Object() {
/**
- * Load the given bookmark in the current tab, used by the the
- * {@link acr.browser.lightning.fragment.BookmarksFragment}
+ * Load the given url in the current tab, used by the the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment} and by the
+ * {@link LightningDialogBuilder}
*
* @param event Bus event indicating that the user has clicked a bookmark
*/
@Subscribe
- public void loadBookmarkInCurrentTab(final BookmarkEvents.Clicked event) {
- loadUrlInCurrentView(event.bookmark.getUrl());
+ public void loadUrlInCurrentTab(final BrowserEvents.OpenUrlInCurrentTab event) {
+ loadUrlInCurrentView(event.url);
// keep any jank from happening when the drawer is closed after the
// URL starts to load
final Handler handler = new Handler();
@@ -2451,15 +1922,16 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
}
/**
- * Load the given bookmark in a new tab, used by the the
- * {@link acr.browser.lightning.fragment.BookmarksFragment}
+ * Load the given url in a new tab, used by the the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment} and by the
+ * {@link LightningDialogBuilder}
*
* @param event Bus event indicating that the user wishes
* to open a bookmark in a new tab
*/
@Subscribe
- public void loadBookmarkInNewTab(final BookmarkEvents.AsNewTab event) {
- newTab(event.bookmark.getUrl(), true);
+ public void loadUrlInNewTab(final BrowserEvents.OpenUrlInNewTab event) {
+ BrowserActivity.this.newTab(event.url, true);
mDrawerLayout.closeDrawers();
}
@@ -2472,8 +1944,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Subscribe
public void bookmarkCurrentPage(final BookmarkEvents.WantToBookmarkCurrentPage event) {
- if (mCurrentView != null) {
- mEventBus.post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(), mCurrentView.getUrl()));
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.AddBookmark(currentTab.getTitle(), currentTab.getUrl()));
}
}
@@ -2495,12 +1968,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Subscribe
public void bookmarkChanged(final BookmarkEvents.BookmarkChanged event) {
- if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
- && mCurrentView.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
- openBookmarkPage(mWebView);
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE)
+ && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
+ currentTab.loadBookmarkpage();
}
- if (mCurrentView != null) {
- mEventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl()));
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl()));
}
}
@@ -2511,12 +1986,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
*/
@Subscribe
public void bookmarkDeleted(final BookmarkEvents.Deleted event) {
- if (mCurrentView != null && mCurrentView.getUrl().startsWith(Constants.FILE)
- && mCurrentView.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
- openBookmarkPage(mWebView);
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE)
+ && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
+ currentTab.loadBookmarkpage();
}
- if (mCurrentView != null) {
- mEventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl()));
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl()));
}
}
@@ -2532,5 +2009,111 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) {
mDrawerLayout.closeDrawer(mDrawerRight);
}
+
+ /**
+ * The user wants to close a tab
+ *
+ * @param event contains the position inside the tabs adapter
+ */
+ @Subscribe
+ public void closeTab(final TabEvents.CloseTab event) {
+ deleteTab(event.position);
+ }
+
+ /**
+ * The user clicked on a tab, let's show it
+ *
+ * @param event contains the tab position in the tabs adapter
+ */
+ @Subscribe
+ public void showTab(final TabEvents.ShowTab event) {
+ BrowserActivity.this.showTab(event.position);
+ }
+
+ /**
+ * The user long pressed on a tab, ask him if he want to close the tab
+ *
+ * @param event contains the tab position in the tabs adapter
+ */
+ @Subscribe
+ public void showCloseDialog(final TabEvents.ShowCloseDialog event) {
+ BrowserActivity.this.showCloseDialog(event.position);
+ }
+
+ /**
+ * The user wants to create a new tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void newTab(final TabEvents.NewTab event) {
+ BrowserActivity.this.newTab(null, true);
+ }
+
+ /**
+ * The user wants to go back on current tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void goBack(final NavigationEvents.GoBack event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.canGoBack()) {
+ currentTab.goBack();
+ } else {
+ deleteTab(tabsManager.positionOf(currentTab));
+ }
+ }
+ }
+
+ /**
+ * The user wants to go forward on current tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void goForward(final NavigationEvents.GoForward event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.canGoForward()) {
+ currentTab.goForward();
+ }
+ }
+ }
+
+ @Subscribe
+ public void goHome(final NavigationEvents.GoHome event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ currentTab.loadHomepage();
+ closeDrawers();
+ }
+ }
+
+ /**
+ * The user long pressed the new tab button
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void newTabLongPress(final TabEvents.NewTabLongPress event) {
+ String url = mPreferences.getSavedUrl();
+ if (url != null) {
+ BrowserActivity.this.newTab(url, true);
+
+ Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab);
+ }
+ mPreferences.setSavedUrl(null);
+ }
+
+ @Subscribe
+ public void displayInSnackbar(final BrowserEvents.ShowSnackBarMessage event) {
+ if (event.message != null) {
+ Utils.showSnackbar(BrowserActivity.this, event.message);
+ } else {
+ Utils.showSnackbar(BrowserActivity.this, event.stringRes);
+ }
+ }
};
}
diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig
new file mode 100644
index 0000000..7e0fa1d
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig
@@ -0,0 +1,2129 @@
+/*
+ * Copyright 2015 Anthony Restaino
+ */
+
+package acr.browser.lightning.activity;
+
+import android.animation.ArgbEvaluator;
+import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.MediaStore;
+import android.support.annotation.IdRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.graphics.Palette;
+import android.support.v7.graphics.drawable.DrawerArrowDrawable;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnKeyListener;
+import android.view.View.OnLongClickListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Transformation;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient.CustomViewCallback;
+import android.webkit.WebIconDatabase;
+import android.webkit.WebView;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+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.IOException;
+import java.util.ArrayList;
+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.bus.NavigationEvents;
+import acr.browser.lightning.bus.TabEvents;
+import acr.browser.lightning.constant.BookmarkPage;
+import acr.browser.lightning.constant.Constants;
+import acr.browser.lightning.constant.HistoryPage;
+import acr.browser.lightning.controller.BrowserController;
+import acr.browser.lightning.database.BookmarkManager;
+import acr.browser.lightning.database.HistoryDatabase;
+import acr.browser.lightning.dialog.LightningDialogBuilder;
+import acr.browser.lightning.fragment.BookmarksFragment;
+import acr.browser.lightning.fragment.TabsFragment;
+import acr.browser.lightning.object.SearchAdapter;
+import acr.browser.lightning.preference.PreferenceManager;
+import acr.browser.lightning.receiver.NetworkReceiver;
+import acr.browser.lightning.utils.PermissionsManager;
+import acr.browser.lightning.utils.ProxyUtils;
+import acr.browser.lightning.utils.ThemeUtils;
+import acr.browser.lightning.utils.UrlUtils;
+import acr.browser.lightning.utils.Utils;
+import acr.browser.lightning.utils.WebUtils;
+import acr.browser.lightning.view.AnimatedProgressBar;
+import acr.browser.lightning.view.LightningView;
+import butterknife.Bind;
+import butterknife.ButterKnife;
+
+public abstract class BrowserActivity extends ThemableBrowserActivity implements BrowserController, OnClickListener, OnLongClickListener {
+
+ // Static Layout
+ @Bind(R.id.drawer_layout)
+ DrawerLayout mDrawerLayout;
+
+ @Bind(R.id.content_frame)
+ FrameLayout mBrowserFrame;
+
+ @Bind(R.id.left_drawer)
+ ViewGroup mDrawerLeft;
+
+ @Bind(R.id.right_drawer)
+ ViewGroup mDrawerRight;
+
+ @Bind(R.id.ui_layout)
+ ViewGroup mUiLayout;
+
+ @Bind(R.id.toolbar_layout)
+ ViewGroup mToolbarLayout;
+
+ @Bind(R.id.progress_view)
+ AnimatedProgressBar mProgressBar;
+
+ @Bind(R.id.search_bar)
+ RelativeLayout mSearchBar;
+
+
+ // Toolbar Views
+ private AutoCompleteTextView mSearch;
+ private ImageView mArrowImage;
+
+ // Full Screen Video Views
+ private FrameLayout mFullscreenContainer;
+ private VideoView mVideoView;
+ private View mCustomView;
+
+ // Adapter
+ private SearchAdapter mSearchAdapter;
+
+ // Callback
+ private CustomViewCallback mCustomViewCallback;
+ private ValueCallback mUploadMessage;
+ private ValueCallback mFilePathCallback;
+
+ // Primatives
+ private boolean mFullScreen, mColorMode, mDarkTheme,
+ mIsNewIntent = false,
+ mIsFullScreen = false,
+ mIsImmersive = false,
+ mShowTabsInDrawer;
+ private int mOriginalOrientation, mBackgroundColor, mIdGenerator, mIconColor,
+ mCurrentUiColor = Color.BLACK;
+ private String mSearchText, mUntitledTitle, mHomepage, mCameraPhotoPath;
+
+ // The singleton BookmarkManager
+ @Inject
+ BookmarkManager mBookmarkManager;
+
+ // Event bus
+ @Inject
+ Bus mEventBus;
+
+ @Inject
+ BookmarkPage mBookmarkPage;
+
+ @Inject
+ LightningDialogBuilder bookmarksDialogBuilder;
+
+ @Inject
+ TabsManager tabsManager;
+
+ // Preference manager was moved on ThemeableBrowserActivity
+
+ @Inject
+ HistoryDatabase mHistoryDatabase;
+
+ // Image
+ private Bitmap mWebpageBitmap;
+ private final ColorDrawable mBackground = new ColorDrawable();
+ private Drawable mDeleteIcon, mRefreshIcon, mClearIcon, mIcon;
+ private DrawerArrowDrawable mArrowDrawable;
+
+ // Proxy
+ private ProxyUtils mProxyUtils;
+
+ // Constant
+ private static final int API = android.os.Build.VERSION.SDK_INT;
+ private static final String NETWORK_BROADCAST_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+ private static final LayoutParams MATCH_PARENT = new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT);
+ private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ public abstract boolean isIncognito();
+
+// abstract void initializeTabs();
+
+ abstract void closeActivity();
+
+ public abstract void updateHistory(final String title, final String url);
+
+ abstract void updateCookiePreference();
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ BrowserApp.getAppComponent().inject(this);
+ setContentView(R.layout.activity_main);
+ ButterKnife.bind(this);
+ initialize();
+ }
+
+ private synchronized void initialize() {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ ActionBar actionBar = getSupportActionBar();
+
+ //TODO make sure dark theme flag gets set correctly
+ mDarkTheme = mPreferences.getUseTheme() != 0 || isIncognito();
+ mIconColor = mDarkTheme ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this);
+ mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet());
+
+
+ // initialize background ColorDrawable
+ mBackground.setColor(((ColorDrawable) mToolbarLayout.getBackground()).getColor());
+
+ // Drawer stutters otherwise
+ mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mDrawerRight.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+// TODO Please review this
+// ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon);
+// tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !mShowTabsInDrawer) {
+ getWindow().setStatusBarColor(Color.BLACK);
+ }
+
+ setNavigationDrawerWidth();
+ mDrawerLayout.setDrawerListener(new DrawerLocker());
+
+ mWebpageBitmap = ThemeUtils.getThemedBitmap(this, R.drawable.ic_webpage, mDarkTheme);
+
+ mHomepage = mPreferences.getHomepage();
+
+ final TabsFragment tabsFragment = new TabsFragment();
+ final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container;
+ final Bundle tabsFragmentArguments = new Bundle();
+ tabsFragmentArguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito());
+ tabsFragmentArguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer);
+ tabsFragment.setArguments(tabsFragmentArguments);
+
+ final BookmarksFragment bookmarksFragment = new BookmarksFragment();
+ final Bundle bookmarksFragmentArguments = new Bundle();
+ bookmarksFragmentArguments.putBoolean(BookmarksFragment.INCOGNITO_MODE, isIncognito());
+ bookmarksFragment.setArguments(bookmarksFragmentArguments);
+
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ fragmentManager
+ .beginTransaction()
+ .add(containerId, tabsFragment)
+ .add(R.id.right_drawer, bookmarksFragment)
+ .commit();
+ if (mShowTabsInDrawer) {
+ mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container));
+ }
+
+ if (actionBar == null)
+ return;
+
+ // set display options of the ActionBar
+ actionBar.setDisplayShowTitleEnabled(false);
+ actionBar.setDisplayShowHomeEnabled(false);
+ actionBar.setDisplayShowCustomEnabled(true);
+ actionBar.setCustomView(R.layout.toolbar_content);
+
+ View customView = actionBar.getCustomView();
+ LayoutParams lp = customView.getLayoutParams();
+ lp.width = LayoutParams.MATCH_PARENT;
+ lp.height = LayoutParams.MATCH_PARENT;
+ customView.setLayoutParams(lp);
+
+ mArrowImage = (ImageView) customView.findViewById(R.id.arrow);
+ FrameLayout arrowButton = (FrameLayout) customView.findViewById(R.id.arrow_button);
+ if (mShowTabsInDrawer) {
+ // Use hardware acceleration for the animation
+ mArrowDrawable = new DrawerArrowDrawable(this);
+ mArrowImage.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mArrowImage.setImageDrawable(mArrowDrawable);
+ } else {
+ mArrowImage.setImageResource(R.drawable.ic_action_home);
+ mArrowImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+ }
+ arrowButton.setOnClickListener(this);
+
+ mProxyUtils = ProxyUtils.getInstance();
+
+<<<<<<< HEAD
+=======
+ setupFrameLayoutButton(R.id.action_back, R.id.icon_back);
+ setupFrameLayoutButton(R.id.action_forward, R.id.icon_forward);
+ setupFrameLayoutButton(R.id.action_toggle_desktop, R.id.icon_desktop);
+ setupFrameLayoutButton(R.id.action_reading, R.id.icon_reading);
+ setupFrameLayoutButton(R.id.action_home, R.id.icon_home);
+
+>>>>>>> d3867d29bd4002682fc3c0a15d6f10cb1869c137
+ // create the search EditText in the ToolBar
+ mSearch = (AutoCompleteTextView) customView.findViewById(R.id.search);
+ mUntitledTitle = getString(R.string.untitled);
+ mBackgroundColor = ContextCompat.getColor(this, R.color.primary_color);
+ mDeleteIcon = ThemeUtils.getLightThemedDrawable(this, R.drawable.ic_action_delete);
+ mRefreshIcon = ThemeUtils.getLightThemedDrawable(this, R.drawable.ic_action_refresh);
+ mClearIcon = ThemeUtils.getLightThemedDrawable(this, R.drawable.ic_action_delete);
+
+ int iconBounds = Utils.dpToPx(30);
+ mDeleteIcon.setBounds(0, 0, iconBounds, iconBounds);
+ mRefreshIcon.setBounds(0, 0, iconBounds, iconBounds);
+ mClearIcon.setBounds(0, 0, iconBounds, iconBounds);
+ mIcon = mRefreshIcon;
+ SearchListenerClass search = new SearchListenerClass();
+ mSearch.setCompoundDrawables(null, null, mRefreshIcon, null);
+ mSearch.setOnKeyListener(search);
+ mSearch.setOnFocusChangeListener(search);
+ mSearch.setOnEditorActionListener(search);
+ mSearch.setOnTouchListener(search);
+
+ new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ initializeSearchSuggestions(mSearch);
+ }
+
+ }).run();
+
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_right_shadow, GravityCompat.END);
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_left_shadow, GravityCompat.START);
+
+ if (API <= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ //noinspection deprecation
+ WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath());
+ }
+
+ tabsManager.restoreTabs(this, mDarkTheme, isIncognito());
+ // At this point we always have at least a tab in the tab manager
+ showTab(0);
+
+ mProxyUtils.checkForProxy(this);
+ }
+
+ private class SearchListenerClass implements OnKeyListener, OnEditorActionListener, OnFocusChangeListener, OnTouchListener {
+
+ @Override
+ public boolean onKey(View arg0, int arg1, KeyEvent arg2) {
+
+ switch (arg1) {
+ case KeyEvent.KEYCODE_ENTER:
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
+ searchTheWeb(mSearch.getText().toString());
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.requestFocus();
+ }
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) {
+ // hide the keyboard and search the web when the enter key
+ // button is pressed
+ if (actionId == EditorInfo.IME_ACTION_GO || actionId == EditorInfo.IME_ACTION_DONE
+ || actionId == EditorInfo.IME_ACTION_NEXT
+ || actionId == EditorInfo.IME_ACTION_SEND
+ || actionId == EditorInfo.IME_ACTION_SEARCH
+ || (arg2.getAction() == KeyEvent.KEYCODE_ENTER)) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
+ searchTheWeb(mSearch.getText().toString());
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.requestFocus();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onFocusChange(View v, final boolean hasFocus) {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (!hasFocus && currentView != null) {
+ setIsLoading(currentView.getProgress() < 100);
+ updateUrl(currentView.getUrl(), true);
+ } else if (hasFocus) {
+ String url = currentView.getUrl();
+ if (url.startsWith(Constants.FILE)) {
+ mSearch.setText("");
+ } else {
+ mSearch.setText(url);
+ }
+ ((AutoCompleteTextView) v).selectAll(); // Hack to make sure
+ // the text gets
+ // selected
+ mIcon = mClearIcon;
+ mSearch.setCompoundDrawables(null, null, mClearIcon, null);
+ }
+ final Animation anim = new Animation() {
+
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ if (!hasFocus) {
+ mArrowDrawable.setProgress(1.0f - interpolatedTime);
+ } else {
+ mArrowDrawable.setProgress(interpolatedTime);
+ }
+ }
+
+ @Override
+ public boolean willChangeBounds() {
+ return true;
+ }
+
+ };
+ anim.setDuration(300);
+ anim.setInterpolator(new DecelerateInterpolator());
+ anim.setAnimationListener(new AnimationListener() {
+
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ if (!hasFocus) {
+ mArrowDrawable.setProgress(0.0f);
+ } else {
+ mArrowDrawable.setProgress(1.0f);
+ }
+ }
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
+
+ });
+ new Handler().postDelayed(new Runnable() {
+
+ @Override
+ public void run() {
+ if (mArrowDrawable != null) {
+ mArrowImage.startAnimation(anim);
+ }
+ }
+
+ }, 100);
+
+ if (!hasFocus) {
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
+ }
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (mSearch.getCompoundDrawables()[2] != null) {
+ boolean tappedX = event.getX() > (mSearch.getWidth()
+ - mSearch.getPaddingRight() - mIcon.getIntrinsicWidth());
+ if (tappedX) {
+ if (event.getAction() == MotionEvent.ACTION_UP) {
+ if (mSearch.hasFocus()) {
+ mSearch.setText("");
+ } else {
+ refreshOrStop();
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ private class DrawerLocker implements DrawerListener {
+
+ @Override
+ public void onDrawerClosed(View v) {
+ if (v == mDrawerRight && mShowTabsInDrawer) {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerLeft);
+ } else {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, mDrawerRight);
+ }
+ }
+
+ @Override
+ public void onDrawerOpened(View v) {
+ if (v == mDrawerRight) {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft);
+ } else {
+ mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerRight);
+ }
+ }
+
+ @Override
+ public void onDrawerSlide(View v, float arg) {
+ }
+
+ @Override
+ public void onDrawerStateChanged(int arg) {
+ }
+
+ }
+
+ private void setNavigationDrawerWidth() {
+ int width = getResources().getDisplayMetrics().widthPixels - Utils.dpToPx(56);
+ int maxWidth;
+ if (isTablet()) {
+ maxWidth = Utils.dpToPx(320);
+ } else {
+ maxWidth = Utils.dpToPx(300);
+ }
+ if (width > maxWidth) {
+ DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft
+ .getLayoutParams();
+ params.width = maxWidth;
+ mDrawerLeft.setLayoutParams(params);
+ mDrawerLeft.requestLayout();
+ DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight
+ .getLayoutParams();
+ paramsRight.width = maxWidth;
+ mDrawerRight.setLayoutParams(paramsRight);
+ mDrawerRight.requestLayout();
+ } else {
+ DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerLeft
+ .getLayoutParams();
+ params.width = width;
+ mDrawerLeft.setLayoutParams(params);
+ mDrawerLeft.requestLayout();
+ DrawerLayout.LayoutParams paramsRight = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerRight
+ .getLayoutParams();
+ paramsRight.width = width;
+ mDrawerRight.setLayoutParams(paramsRight);
+ mDrawerRight.requestLayout();
+ }
+ }
+
+ private void initializePreferences() {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentView.getWebView();
+ mFullScreen = mPreferences.getFullScreenEnabled();
+ mColorMode = mPreferences.getColorModeEnabled();
+ mColorMode &= !mDarkTheme;
+ if (!isIncognito() && !mColorMode && !mDarkTheme && mWebpageBitmap != null) {
+ changeToolbarBackground(mWebpageBitmap, null);
+ } else if (!isIncognito() && currentView != null && !mDarkTheme
+ && currentView.getFavicon() != null) {
+ changeToolbarBackground(currentView.getFavicon(), null);
+ }
+
+ if (mFullScreen) {
+ mToolbarLayout.setTranslationY(0);
+ int height = mToolbarLayout.getHeight();
+ if (height == 0) {
+ mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mToolbarLayout.getMeasuredHeight();
+ }
+ if (currentWebView != null)
+ currentWebView.setTranslationY(height);
+ mBrowserFrame.setLayoutTransition(null);
+ if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) {
+ mUiLayout.removeView(mToolbarLayout);
+ mBrowserFrame.addView(mToolbarLayout);
+ mToolbarLayout.bringToFront();
+ }
+ } else {
+ mToolbarLayout.setTranslationY(0);
+ if (mBrowserFrame.findViewById(R.id.toolbar_layout) != null) {
+ mBrowserFrame.removeView(mToolbarLayout);
+ mUiLayout.addView(mToolbarLayout, 0);
+ }
+ mBrowserFrame.setLayoutTransition(new LayoutTransition());
+ if (currentWebView != null)
+ currentWebView.setTranslationY(0);
+ }
+ setFullscreen(mPreferences.getHideStatusBarEnabled(), false);
+
+ switch (mPreferences.getSearchChoice()) {
+ case 0:
+ mSearchText = mPreferences.getSearchUrl();
+ if (!mSearchText.startsWith(Constants.HTTP)
+ && !mSearchText.startsWith(Constants.HTTPS)) {
+ mSearchText = Constants.GOOGLE_SEARCH;
+ }
+ break;
+ case 1:
+ mSearchText = Constants.GOOGLE_SEARCH;
+ break;
+ case 2:
+ mSearchText = Constants.ASK_SEARCH;
+ break;
+ case 3:
+ mSearchText = Constants.BING_SEARCH;
+ break;
+ case 4:
+ mSearchText = Constants.YAHOO_SEARCH;
+ break;
+ case 5:
+ mSearchText = Constants.STARTPAGE_SEARCH;
+ break;
+ case 6:
+ mSearchText = Constants.STARTPAGE_MOBILE_SEARCH;
+ break;
+ case 7:
+ mSearchText = Constants.DUCK_SEARCH;
+ break;
+ case 8:
+ mSearchText = Constants.DUCK_LITE_SEARCH;
+ break;
+ case 9:
+ mSearchText = Constants.BAIDU_SEARCH;
+ break;
+ case 10:
+ mSearchText = Constants.YANDEX_SEARCH;
+ break;
+ }
+
+ updateCookiePreference();
+ mProxyUtils.updateProxySettings(this);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (mSearch.hasFocus()) {
+ searchTheWeb(mSearch.getText().toString());
+ }
+ } else if ((keyCode == KeyEvent.KEYCODE_MENU)
+ && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN)
+ && (Build.MANUFACTURER.compareTo("LGE") == 0)) {
+ // Workaround for stupid LG devices that crash
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
+ if ((keyCode == KeyEvent.KEYCODE_MENU)
+ && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN)
+ && (Build.MANUFACTURER.compareTo("LGE") == 0)) {
+ // Workaround for stupid LG devices that crash
+ openOptionsMenu();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ // Handle action buttons
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ if (mDrawerLayout.isDrawerOpen(mDrawerRight)) {
+ mDrawerLayout.closeDrawer(mDrawerRight);
+ }
+ return true;
+ case R.id.action_back:
+ if (currentView != null && currentView.canGoBack()) {
+ currentView.goBack();
+ }
+ return true;
+ case R.id.action_forward:
+ if (currentView != null && currentView.canGoForward()) {
+ currentView.goForward();
+ }
+ return true;
+ case R.id.action_new_tab:
+ newTab(null, true);
+ return true;
+ case R.id.action_incognito:
+ startActivity(new Intent(this, IncognitoActivity.class));
+ overridePendingTransition(R.anim.slide_up_in, R.anim.fade_out_scale);
+ return true;
+ case R.id.action_share:
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
+ Intent shareIntent = new Intent(Intent.ACTION_SEND);
+ shareIntent.setType("text/plain");
+ shareIntent.putExtra(Intent.EXTRA_SUBJECT, currentView.getTitle());
+ shareIntent.putExtra(Intent.EXTRA_TEXT, currentView.getUrl());
+ startActivity(Intent.createChooser(shareIntent, getResources().getString(R.string.dialog_title_share)));
+ }
+ return true;
+ case R.id.action_bookmarks:
+ openBookmarks();
+ return true;
+ case R.id.action_copy:
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
+ ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("label", currentView.getUrl());
+ clipboard.setPrimaryClip(clip);
+ Utils.showSnackbar(this, R.string.message_link_copied);
+ }
+ return true;
+ case R.id.action_settings:
+ startActivity(new Intent(this, SettingsActivity.class));
+ return true;
+ case R.id.action_history:
+ openHistory();
+ return true;
+ case R.id.action_add_bookmark:
+ if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) {
+ mEventBus.post(new BrowserEvents.AddBookmark(currentView.getTitle(),
+ currentView.getUrl()));
+ }
+ return true;
+ case R.id.action_find:
+ findInPage();
+ return true;
+ case R.id.action_reading_mode:
+ Intent read = new Intent(this, ReadingActivity.class);
+ read.putExtra(Constants.LOAD_READING_URL, currentView.getUrl());
+ startActivity(read);
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ /**
+ * method that shows a dialog asking what string the user wishes to search
+ * for. It highlights the text entered.
+ */
+ private void findInPage() {
+ final AlertDialog.Builder finder = new AlertDialog.Builder(this);
+ finder.setTitle(getResources().getString(R.string.action_find));
+ final EditText getHome = new EditText(this);
+ getHome.setHint(getResources().getString(R.string.search_hint));
+ finder.setView(getHome);
+ finder.setPositiveButton(getResources().getString(R.string.search_hint),
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String query = getHome.getText().toString();
+ if (!query.isEmpty())
+ showSearchInterfaceBar(query);
+ }
+ });
+ finder.show();
+ }
+
+ private void showSearchInterfaceBar(String text) {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ if (currentView != null) {
+ currentView.find(text);
+ }
+ mSearchBar.setVisibility(View.VISIBLE);
+
+ TextView tw = (TextView) findViewById(R.id.search_query);
+ tw.setText('\'' + text + '\'');
+
+ ImageButton up = (ImageButton) findViewById(R.id.button_next);
+ up.setOnClickListener(this);
+
+ ImageButton down = (ImageButton) findViewById(R.id.button_back);
+ down.setOnClickListener(this);
+
+ ImageButton quit = (ImageButton) findViewById(R.id.button_quit);
+ quit.setOnClickListener(this);
+ }
+
+ private void showCloseDialog(final int position) {
+ if (position < 0) {
+ return;
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_dropdown_item_1line);
+ adapter.add(this.getString(R.string.close_tab));
+ adapter.add(this.getString(R.string.close_all_tabs));
+ builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case 0:
+ deleteTab(position);
+ break;
+ case 1:
+ closeBrowser();
+ break;
+ default:
+ break;
+ }
+ }
+ });
+ builder.show();
+ }
+
+ /**
+ * displays the WebView contained in the LightningView Also handles the
+ * removal of previous views
+ *
+ * @param position the poition of the tab to display
+ */
+ private synchronized void showTab(final int position) {
+ final LightningView currentView = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentView != null ? currentView.getWebView() : null;
+ final LightningView newView = tabsManager.switchToTab(position);
+ final WebView newWebView = newView != null ? newView.getWebView() : null;
+
+ // Set the background color so the color mode color doesn't show through
+ mBrowserFrame.setBackgroundColor(mBackgroundColor);
+ if (newView == currentView && !currentView.isShown()) {
+ return;
+ }
+ mIsNewIntent = false;
+
+ final float translation = mToolbarLayout.getTranslationY();
+ mBrowserFrame.removeAllViews();
+ if (currentView != null) {
+ currentView.setForegroundTab(false);
+ currentView.onPause();
+ }
+ newView.setForegroundTab(true);
+ if (currentWebView != null) {
+ updateUrl(newView.getUrl(), true);
+ updateProgress(newView.getProgress());
+ } else {
+ updateUrl("", true);
+ updateProgress(0);
+ }
+
+ mBrowserFrame.addView(newWebView, MATCH_PARENT);
+ newView.requestFocus();
+ newView.onResume();
+
+ if (mFullScreen) {
+ // mToolbarLayout has already been removed
+ mBrowserFrame.addView(mToolbarLayout);
+ mToolbarLayout.bringToFront();
+ Log.d(Constants.TAG, "Move view to browser frame");
+ int height = mToolbarLayout.getHeight();
+ if (height == 0) {
+ mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mToolbarLayout.getMeasuredHeight();
+ }
+ newWebView.setTranslationY(translation + height);
+ mToolbarLayout.setTranslationY(translation);
+ } else {
+ newWebView.setTranslationY(0);
+ }
+
+ showActionBar();
+
+ // Use a delayed handler to make the transition smooth
+ // otherwise it will get caught up with the showTab code
+ // and cause a janky motion
+ new Handler().postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ mDrawerLayout.closeDrawers();
+ }
+ }, 200);
+
+ // Should update the bookmark status in BookmarksFragment
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(newView.getUrl()));
+
+// new Handler().postDelayed(new Runnable() {
+// @Override
+// public void run() {
+ // Remove browser frame background to reduce overdraw
+ //TODO evaluate performance
+// mBrowserFrame.setBackgroundColor(Color.TRANSPARENT);
+// }
+// }, 300);
+
+ }
+
+ void handleNewIntent(Intent intent) {
+
+ String url = null;
+ if (intent != null) {
+ url = intent.getDataString();
+ }
+ int num = 0;
+ String source = null;
+ if (intent != null && intent.getExtras() != null) {
+ num = intent.getExtras().getInt(getPackageName() + ".Origin");
+ source = intent.getExtras().getString("SOURCE");
+ }
+ if (num == 1) {
+ loadUrlInCurrentView(url);
+ } else if (url != null) {
+ if (url.startsWith(Constants.FILE)) {
+ Utils.showSnackbar(this, R.string.message_blocked_local);
+ url = null;
+ }
+ newTab(url, true);
+ mIsNewIntent = (source == null);
+ }
+ }
+
+ private void loadUrlInCurrentView(final String url) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab == null) {
+ // This is a problem, probably an assert will be better than a return
+ return;
+ }
+
+ currentTab.loadUrl(url);
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(url));
+ }
+
+ @Override
+ public void closeEmptyTab() {
+ final WebView currentWebView = tabsManager.getCurrentWebView();
+ if (currentWebView != null && currentWebView.copyBackForwardList().getSize() == 0) {
+ closeCurrentTab();
+ }
+ }
+
+ private void closeCurrentTab() {
+ // don't delete the tab because the browser will close and mess stuff up
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ if (level > TRIM_MEMORY_MODERATE && Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+ Log.d(Constants.TAG, "Low Memory, Free Memory");
+ tabsManager.freeMemory();
+ }
+ }
+
+ synchronized boolean newTab(String url, boolean show) {
+ // Limit number of tabs for limited version of app
+ if (!Constants.FULL_VERSION && tabsManager.size() >= 10) {
+ Utils.showSnackbar(this, R.string.max_tabs);
+ return false;
+ }
+ mIsNewIntent = false;
+ LightningView startingTab = tabsManager.newTab(this, url, mDarkTheme, isIncognito());
+ if (mIdGenerator == 0) {
+ startingTab.resumeTimers();
+ }
+ mIdGenerator++;
+
+ if (show) {
+ showTab(tabsManager.size() - 1);
+ }
+ // TODO Check is this is callable directly from LightningView
+ mEventBus.post(new BrowserEvents.TabsChanged());
+
+// TODO Restore this
+// new Handler().postDelayed(new Runnable() {
+// @Override
+// public void run() {
+// mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1);
+// }
+// }, 300);
+
+ return true;
+ }
+
+ private synchronized void deleteTab(int position) {
+ final LightningView tabToDelete = tabsManager.getTabAtPosition(position);
+ final LightningView currentTab = tabsManager.getCurrentTab();
+
+ if (tabToDelete == null) {
+ return;
+ }
+
+// What?
+ int current = tabsManager.positionOf(currentTab);
+ if (current < 0) {
+ return;
+ }
+ if (!tabToDelete.getUrl().startsWith(Constants.FILE) && !isIncognito()) {
+ mPreferences.setSavedUrl(tabToDelete.getUrl());
+ }
+ final boolean isShown = tabToDelete.isShown();
+ if (isShown) {
+ mBrowserFrame.setBackgroundColor(mBackgroundColor);
+ }
+ if (current > position) {
+ tabsManager.deleteTab(position);
+ showTab(current - 1);
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ } else if (tabsManager.size() > position + 1) {
+ if (current == position) {
+ showTab(position + 1);
+ tabsManager.deleteTab(position);
+ showTab(position);
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ } else {
+ tabsManager.deleteTab(position);
+ }
+ } else if (tabsManager.size() > 1) {
+ if (current == position) {
+ showTab(position - 1);
+ tabsManager.deleteTab(position);
+ showTab(position - 1);
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ } else {
+ }
+ } else {
+ if (currentTab.getUrl().startsWith(Constants.FILE) || currentTab.getUrl().equals(mHomepage)) {
+ closeActivity();
+ } else {
+ tabsManager.deleteTab(position);
+ performExitCleanUp();
+ tabToDelete.pauseTimers();
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ finish();
+ }
+ }
+ mEventBus.post(new BrowserEvents.TabsChanged());
+
+ if (mIsNewIntent && isShown) {
+ mIsNewIntent = false;
+ closeActivity();
+ }
+
+ Log.d(Constants.TAG, "deleted tab");
+ }
+
+ private void performExitCleanUp() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (mPreferences.getClearCacheExit() && currentTab != null && !isIncognito()) {
+ WebUtils.clearCache(currentTab.getWebView());
+ Log.d(Constants.TAG, "Cache Cleared");
+ }
+ if (mPreferences.getClearHistoryExitEnabled() && !isIncognito()) {
+ WebUtils.clearHistory(this);
+ Log.d(Constants.TAG, "History Cleared");
+ }
+ if (mPreferences.getClearCookiesExitEnabled() && !isIncognito()) {
+ WebUtils.clearCookies(this);
+ Log.d(Constants.TAG, "Cookies Cleared");
+ }
+ if (mPreferences.getClearWebStorageExitEnabled() && !isIncognito()) {
+ WebUtils.clearWebStorage();
+ Log.d(Constants.TAG, "WebStorage Cleared");
+ } else if (isIncognito()) {
+ WebUtils.clearWebStorage(); // We want to make sure incognito mode is secure
+ }
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ showCloseDialog(tabsManager.positionOf(currentTab));
+ }
+ return true;
+ }
+
+ private void closeBrowser() {
+ mBrowserFrame.setBackgroundColor(mBackgroundColor);
+ performExitCleanUp();
+ tabsManager.shutdown();
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) {
+ mDrawerLayout.closeDrawer(mDrawerLeft);
+ } else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) {
+ mEventBus
+ .post(new BrowserEvents.UserPressedBack());
+ } else {
+ if (currentTab != null) {
+ Log.d(Constants.TAG, "onBackPressed");
+ if (mSearch.hasFocus()) {
+ currentTab.requestFocus();
+ } else if (currentTab.canGoBack()) {
+ if (!currentTab.isShown()) {
+ onHideCustomView();
+ } else {
+ currentTab.goBack();
+ }
+ } else {
+ deleteTab(tabsManager.positionOf(currentTab));
+ }
+ } else {
+ Log.e(Constants.TAG, "This shouldn't happen ever");
+ super.onBackPressed();
+ }
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ Log.d(Constants.TAG, "onPause");
+ if (currentTab != null) {
+ currentTab.pauseTimers();
+ currentTab.onPause();
+ }
+ try {
+ unregisterReceiver(mNetworkReceiver);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ if (isIncognito() && isFinishing()) {
+ overridePendingTransition(R.anim.fade_in_scale, R.anim.slide_down_out);
+ }
+
+ mEventBus.unregister(mBusEventListener);
+ }
+
+ void saveOpenTabs() {
+ if (mPreferences.getRestoreLostTabsEnabled()) {
+ final String s = tabsManager.tabsString();
+ mPreferences.setMemoryUrl(s.toString());
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mProxyUtils.onStop();
+ }
+
+ @Override
+ protected void onDestroy() {
+ Log.d(Constants.TAG, "onDestroy");
+ if (mHistoryDatabase != null) {
+ mHistoryDatabase.close();
+ mHistoryDatabase = null;
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mProxyUtils.onStart(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ Log.d(Constants.TAG, "onResume");
+ if (mSearchAdapter != null) {
+ mSearchAdapter.refreshPreferences();
+ mSearchAdapter.refreshBookmarks();
+ }
+ if (currentTab != null) {
+ currentTab.resumeTimers();
+ currentTab.onResume();
+ }
+ initializePreferences();
+ tabsManager.resume(this);
+
+ supportInvalidateOptionsMenu();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(NETWORK_BROADCAST_ACTION);
+ registerReceiver(mNetworkReceiver, filter);
+
+ mEventBus.register(mBusEventListener);
+ }
+
+ /**
+ * searches the web for the query fixing any and all problems with the input
+ * checks if it is a search, url, etc.
+ */
+ private void searchTheWeb(@NonNull String query) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (query.isEmpty()) {
+ return;
+ }
+ String searchUrl = mSearchText + UrlUtils.QUERY_PLACE_HOLDER;
+ query = query.trim();
+ currentTab.stopLoading();
+ if (currentTab != null) {
+ loadUrlInCurrentView(UrlUtils.smartUrlFilter(query, true, searchUrl));
+ }
+ }
+
+ /**
+ * 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.
+ *
+ * @param favicon the Bitmap to extract the color from
+ * @param tabBackground the optional LinearLayout to color
+ */
+ private void changeToolbarBackground(@NonNull Bitmap favicon, @Nullable final Drawable tabBackground) {
+ final int defaultColor = ContextCompat.getColor(this, R.color.primary_color);
+ if (mCurrentUiColor == Color.BLACK) {
+ mCurrentUiColor = defaultColor;
+ }
+ Palette.from(favicon).generate(new Palette.PaletteAsyncListener() {
+ @Override
+ public void onGenerated(Palette palette) {
+
+ // OR with opaque black to remove transparency glitches
+ int color = 0xff000000 | palette.getVibrantColor(defaultColor);
+
+ int finalColor; // Lighten up the dark color if it is
+ // too dark
+ if (!mShowTabsInDrawer || Utils.isColorTooDark(color)) {
+ finalColor = Utils.mixTwoColors(defaultColor, color, 0.25f);
+ } else {
+ finalColor = color;
+ }
+
+ ValueAnimator anim = ValueAnimator.ofInt(mCurrentUiColor, finalColor);
+ anim.setEvaluator(new ArgbEvaluator());
+ final Window window = getWindow();
+ if (!mShowTabsInDrawer) {
+ window.setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+ }
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final int color = (Integer) animation.getAnimatedValue();
+ if (mShowTabsInDrawer) {
+ mBackground.setColor(color);
+ window.setBackgroundDrawable(mBackground);
+ } else if (tabBackground != null) {
+ tabBackground.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ mCurrentUiColor = color;
+ mToolbarLayout.setBackgroundColor(color);
+ }
+
+ });
+ anim.setDuration(300);
+ anim.start();
+ }
+ });
+ }
+
+ @Override
+ public void updateUrl(String url, boolean shortUrl) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (url == null || mSearch == null || mSearch.hasFocus()) {
+ return;
+ }
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(url));
+ if (shortUrl && !url.startsWith(Constants.FILE)) {
+ switch (mPreferences.getUrlBoxContentChoice()) {
+ case 0: // Default, show only the domain
+ url = url.replaceFirst(Constants.HTTP, "");
+ url = Utils.getDomainName(url);
+ mSearch.setText(url);
+ break;
+ case 1: // URL, show the entire URL
+ mSearch.setText(url);
+ break;
+ case 2: // Title, show the page's title
+ if (currentTab != null && !currentTab.getTitle().isEmpty()) {
+ mSearch.setText(currentTab.getTitle());
+ } else {
+ mSearch.setText(mUntitledTitle);
+ }
+ break;
+ }
+ } else {
+ if (url.startsWith(Constants.FILE)) {
+ url = "";
+ }
+ mSearch.setText(url);
+ }
+ }
+
+ @Override
+ public void updateProgress(int n) {
+ setIsLoading(n < 100);
+ mProgressBar.setProgress(n);
+ }
+
+ void addItemToHistory(final String title, final String url) {
+ Runnable update = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mHistoryDatabase.visitHistoryItem(url, title);
+ } catch (IllegalStateException e) {
+ Log.e(Constants.TAG, "IllegalStateException in updateHistory", e);
+ } catch (NullPointerException e) {
+ Log.e(Constants.TAG, "NullPointerException in updateHistory", e);
+ } catch (SQLiteException e) {
+ Log.e(Constants.TAG, "SQLiteException in updateHistory", e);
+ }
+ }
+ };
+ if (url != null && !url.startsWith(Constants.FILE)) {
+ new Thread(update).start();
+ }
+ }
+
+ /**
+ * method to generate search suggestions for the AutoCompleteTextView from
+ * previously searched URLs
+ */
+ private void initializeSearchSuggestions(final AutoCompleteTextView getUrl) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ getUrl.setThreshold(1);
+ getUrl.setDropDownWidth(-1);
+ getUrl.setDropDownAnchor(R.id.toolbar_layout);
+ getUrl.setOnItemClickListener(new OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView> arg0, View arg1, int arg2, long arg3) {
+ try {
+ String url;
+ url = ((TextView) arg1.findViewById(R.id.url)).getText().toString();
+ if (url.startsWith(BrowserActivity.this.getString(R.string.suggestion))) {
+ url = ((TextView) arg1.findViewById(R.id.title)).getText().toString();
+ } else {
+ getUrl.setText(url);
+ }
+ searchTheWeb(url);
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(getUrl.getWindowToken(), 0);
+ if (currentTab != null) {
+ currentTab.requestFocus();
+ }
+ } catch (NullPointerException e) {
+ Log.e("Browser Error: ", "NullPointerException on item click");
+ }
+ }
+
+ });
+
+ getUrl.setSelectAllOnFocus(true);
+ mSearchAdapter = new SearchAdapter(this, mDarkTheme, isIncognito());
+ getUrl.setAdapter(mSearchAdapter);
+ }
+
+ /**
+ * function that opens the HTML history page in the browser
+ */
+ private void openHistory() {
+ // use a thread so that history retrieval doesn't block the UI
+ Thread history = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+ loadUrlInCurrentView(HistoryPage.getHistoryPage(BrowserActivity.this));
+ mSearch.setText("");
+ }
+
+ });
+ history.run();
+ }
+
+ /**
+ * helper function that opens the bookmark drawer
+ */
+ private void openBookmarks() {
+ if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) {
+ mDrawerLayout.closeDrawers();
+ }
+ mDrawerLayout.openDrawer(mDrawerRight);
+ }
+
+ void closeDrawers() {
+ mDrawerLayout.closeDrawers();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuItem back = menu.findItem(R.id.action_back);
+ MenuItem forward = menu.findItem(R.id.action_forward);
+ if (back != null && back.getIcon() != null)
+ back.getIcon().setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+ if (forward != null && forward.getIcon() != null)
+ forward.getIcon().setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+ return super.onCreateOptionsMenu(menu);
+ }
+
+ /**
+ * opens a file chooser
+ * param ValueCallback is the message from the WebView indicating a file chooser
+ * should be opened
+ */
+ @Override
+ public void openFileChooser(ValueCallback uploadMsg) {
+ mUploadMessage = uploadMsg;
+ Intent i = new Intent(Intent.ACTION_GET_CONTENT);
+ i.addCategory(Intent.CATEGORY_OPENABLE);
+ i.setType("*/*");
+ startActivityForResult(Intent.createChooser(i, getString(R.string.title_file_chooser)), 1);
+ }
+
+ /**
+ * used to allow uploading into the browser
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
+ if (API < Build.VERSION_CODES.LOLLIPOP) {
+ if (requestCode == 1) {
+ if (null == mUploadMessage) {
+ return;
+ }
+ Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
+ mUploadMessage.onReceiveValue(result);
+ mUploadMessage = null;
+
+ }
+ }
+
+ if (requestCode != 1 || mFilePathCallback == null) {
+ super.onActivityResult(requestCode, resultCode, intent);
+ return;
+ }
+
+ Uri[] results = null;
+
+ // Check that the response is a good one
+ if (resultCode == Activity.RESULT_OK) {
+ if (intent == null) {
+ // If there is not data, then we may have taken a photo
+ if (mCameraPhotoPath != null) {
+ results = new Uri[]{Uri.parse(mCameraPhotoPath)};
+ }
+ } else {
+ String dataString = intent.getDataString();
+ if (dataString != null) {
+ results = new Uri[]{Uri.parse(dataString)};
+ }
+ }
+ }
+
+ mFilePathCallback.onReceiveValue(results);
+ mFilePathCallback = null;
+ }
+
+ @Override
+ public void showFileChooser(ValueCallback filePathCallback) {
+ if (mFilePathCallback != null) {
+ mFilePathCallback.onReceiveValue(null);
+ }
+ mFilePathCallback = filePathCallback;
+
+ Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+ if (takePictureIntent.resolveActivity(this.getPackageManager()) != null) {
+ // Create the File where the photo should go
+ File photoFile = null;
+ try {
+ photoFile = Utils.createImageFile();
+ takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
+ } catch (IOException ex) {
+ // Error occurred while creating the File
+ Log.e(Constants.TAG, "Unable to create Image File", ex);
+ }
+
+ // Continue only if the File was successfully created
+ if (photoFile != null) {
+ mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
+ takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
+ } else {
+ takePictureIntent = null;
+ }
+ }
+
+ Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
+ contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
+ contentSelectionIntent.setType("*/*");
+
+ Intent[] intentArray;
+ if (takePictureIntent != null) {
+ intentArray = new Intent[]{takePictureIntent};
+ } else {
+ intentArray = new Intent[0];
+ }
+
+ Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
+ chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
+ chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
+ chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
+
+ this.startActivityForResult(chooserIntent, 1);
+ }
+
+ @Override
+ public void onShowCustomView(View view, CustomViewCallback callback) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (view == null) {
+ return;
+ }
+ if (mCustomView != null && callback != null) {
+ callback.onCustomViewHidden();
+ return;
+ }
+ try {
+ view.setKeepScreenOn(true);
+ } catch (SecurityException e) {
+ Log.e(Constants.TAG, "WebView is not allowed to keep the screen on");
+ }
+ mOriginalOrientation = getRequestedOrientation();
+ FrameLayout decor = (FrameLayout) getWindow().getDecorView();
+ mFullscreenContainer = new FrameLayout(this);
+ mFullscreenContainer.setBackgroundColor(ContextCompat.getColor(this, android.R.color.black));
+ mCustomView = view;
+ mFullscreenContainer.addView(mCustomView, COVER_SCREEN_PARAMS);
+ decor.addView(mFullscreenContainer, COVER_SCREEN_PARAMS);
+ setFullscreen(true, true);
+ currentTab.setVisibility(View.GONE);
+ if (view instanceof FrameLayout) {
+ if (((FrameLayout) view).getFocusedChild() instanceof VideoView) {
+ mVideoView = (VideoView) ((FrameLayout) view).getFocusedChild();
+ mVideoView.setOnErrorListener(new VideoCompletionListener());
+ mVideoView.setOnCompletionListener(new VideoCompletionListener());
+ }
+ }
+ mCustomViewCallback = callback;
+ }
+
+ @Override
+ public void onHideCustomView() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (mCustomView == null || mCustomViewCallback == null || currentTab == null) {
+ return;
+ }
+ Log.d(Constants.TAG, "onHideCustomView");
+ currentTab.setVisibility(View.VISIBLE);
+ try {
+ mCustomView.setKeepScreenOn(false);
+ } catch (SecurityException e) {
+ Log.e(Constants.TAG, "WebView is not allowed to keep the screen on");
+ }
+ setFullscreen(mPreferences.getHideStatusBarEnabled(), false);
+ FrameLayout decor = (FrameLayout) getWindow().getDecorView();
+ if (decor != null) {
+ decor.removeView(mFullscreenContainer);
+ }
+
+ if (API < Build.VERSION_CODES.KITKAT) {
+ try {
+ mCustomViewCallback.onCustomViewHidden();
+ } catch (Throwable ignored) {
+
+ }
+ }
+ mFullscreenContainer = null;
+ mCustomView = null;
+ if (mVideoView != null) {
+ mVideoView.setOnErrorListener(null);
+ mVideoView.setOnCompletionListener(null);
+ mVideoView = null;
+ }
+ setRequestedOrientation(mOriginalOrientation);
+ }
+
+ private class VideoCompletionListener implements MediaPlayer.OnCompletionListener,
+ MediaPlayer.OnErrorListener {
+
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ return false;
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ onHideCustomView();
+ }
+
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus) {
+ setFullscreen(mIsFullScreen, mIsImmersive);
+ }
+ }
+
+ /**
+ * This method sets whether or not the activity will display
+ * in full-screen mode (i.e. the ActionBar will be hidden) and
+ * whether or not immersive mode should be set. This is used to
+ * set both parameters correctly as during a full-screen video,
+ * both need to be set, but other-wise we leave it up to user
+ * preference.
+ *
+ * @param enabled true to enable full-screen, false otherwise
+ * @param immersive true to enable immersive mode, false otherwise
+ */
+ private void setFullscreen(boolean enabled, boolean immersive) {
+ mIsFullScreen = enabled;
+ mIsImmersive = immersive;
+ Window window = getWindow();
+ View decor = window.getDecorView();
+ if (enabled) {
+ window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ if (immersive) {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ }
+ } else {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ }
+ }
+
+ /**
+ * This method handles the JavaScript callback to create a new tab.
+ * Basically this handles the event that JavaScript needs to create
+ * a popup.
+ *
+ * @param resultMsg the transport message used to send the URL to
+ * the newly created WebView.
+ */
+ @Override
+ public void onCreateWindow(Message resultMsg) {
+ if (resultMsg == null) {
+ return;
+ }
+ if (newTab("", true)) {
+ // TODO Review this
+ final WebView webView = tabsManager.getTabAtPosition(tabsManager.size() - 1).getWebView();
+ WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
+ transport.setWebView(webView);
+ resultMsg.sendToTarget();
+ }
+ }
+
+ /**
+ * Closes the specified {@link LightningView}. This implements
+ * the JavaScript callback that asks the tab to close itself and
+ * is especially helpful when a page creates a redirect and does
+ * not need the tab to stay open any longer.
+ *
+ * @param view the LightningView to close, delete it.
+ */
+ @Override
+ public void onCloseWindow(LightningView view) {
+ deleteTab(tabsManager.positionOf(view));
+ }
+
+ /**
+ * Hide the ActionBar using an animation if we are in full-screen
+ * mode. This method also re-parents the ActionBar if its parent is
+ * incorrect so that the animation can happen correctly.
+ */
+ @Override
+ public void hideActionBar() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ if (mFullScreen) {
+ if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) {
+ mUiLayout.removeView(mToolbarLayout);
+ mBrowserFrame.addView(mToolbarLayout);
+ mToolbarLayout.bringToFront();
+ Log.d(Constants.TAG, "Move view to browser frame");
+ mToolbarLayout.setTranslationY(0);
+ currentWebView.setTranslationY(mToolbarLayout.getHeight());
+ }
+ if (mToolbarLayout == null || currentTab == null)
+ return;
+
+ final int height = mToolbarLayout.getHeight();
+ final WebView view = currentWebView;
+ if (mToolbarLayout.getTranslationY() > -0.01f) {
+ Animation show = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ float trans = (1.0f - interpolatedTime) * height;
+ mToolbarLayout.setTranslationY(trans - height);
+ if (view != null)
+ view.setTranslationY(trans);
+ }
+ };
+ show.setDuration(250);
+ show.setInterpolator(new DecelerateInterpolator());
+ currentWebView.startAnimation(show);
+ }
+ }
+ }
+
+ /**
+ * Display the ActionBar using an animation if we are in full-screen
+ * mode. This method also re-parents the ActionBar if its parent is
+ * incorrect so that the animation can happen correctly.
+ */
+ @Override
+ public void showActionBar() {
+ if (mFullScreen) {
+ final WebView view = tabsManager.getCurrentWebView();
+
+ if (mToolbarLayout == null)
+ return;
+
+ int height = mToolbarLayout.getHeight();
+ if (height == 0) {
+ mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ height = mToolbarLayout.getMeasuredHeight();
+ }
+
+ if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) {
+ mUiLayout.removeView(mToolbarLayout);
+ mBrowserFrame.addView(mToolbarLayout);
+ mToolbarLayout.bringToFront();
+ Log.d(Constants.TAG, "Move view to browser frame");
+ mToolbarLayout.setTranslationY(0);
+ if (view != null) {
+ view.setTranslationY(height);
+ }
+ }
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab == null)
+ return;
+
+ final int totalHeight = height;
+ if (mToolbarLayout.getTranslationY() < -(height - 0.01f)) {
+ Animation show = new Animation() {
+ @Override
+ protected void applyTransformation(float interpolatedTime, Transformation t) {
+ float trans = interpolatedTime * totalHeight;
+ mToolbarLayout.setTranslationY(trans - totalHeight);
+ // null pointer here on close
+ if (view != null)
+ view.setTranslationY(trans);
+ }
+ };
+ show.setDuration(250);
+ show.setInterpolator(new DecelerateInterpolator());
+ if (view != null) {
+ view.startAnimation(show);
+ }
+ }
+ }
+ }
+
+ /**
+ * This method lets the search bar know that the page is currently loading
+ * and that it should display the stop icon to indicate to the user that
+ * pressing it stops the page from loading
+ */
+ private void setIsLoading(boolean isLoading) {
+ if (!mSearch.hasFocus()) {
+ mIcon = isLoading ? mDeleteIcon : mRefreshIcon;
+ mSearch.setCompoundDrawables(null, null, mIcon, null);
+ }
+ }
+
+ /**
+ * handle presses on the refresh icon in the search bar, if the page is
+ * loading, stop the page, if it is done loading refresh the page.
+ * See setIsFinishedLoading and setIsLoading for displaying the correct icon
+ */
+ private void refreshOrStop() {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.getProgress() < 100) {
+ currentTab.stopLoading();
+ } else {
+ currentTab.reload();
+ }
+ }
+ }
+
+ /**
+ * Handle the click event for the views that are using
+ * this class as a click listener. This method should
+ * distinguish between the various views using their IDs.
+ *
+ * @param v the view that the user has clicked
+ */
+ @Override
+ public void onClick(View v) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ switch (v.getId()) {
+ case R.id.arrow_button:
+ if (mSearch != null && mSearch.hasFocus()) {
+ currentTab.requestFocus();
+ } else if (mShowTabsInDrawer) {
+ mDrawerLayout.openDrawer(mDrawerLeft);
+ } else if (currentTab != null) {
+ currentTab.loadHomepage();
+ }
+ break;
+<<<<<<< HEAD
+=======
+ case R.id.new_tab_button:
+ newTab(null, true);
+ break;
+ case R.id.action_home:
+ mCurrentView.loadHomepage();
+ closeDrawers();
+ break;
+>>>>>>> d3867d29bd4002682fc3c0a15d6f10cb1869c137
+ case R.id.button_next:
+ currentWebView.findNext(false);
+ break;
+ case R.id.button_back:
+ currentWebView.findNext(true);
+ break;
+ case R.id.button_quit:
+ currentWebView.clearMatches();
+ mSearchBar.setVisibility(View.GONE);
+ break;
+ case R.id.action_reading:
+ Intent read = new Intent(this, ReadingActivity.class);
+ read.putExtra(Constants.LOAD_READING_URL, currentTab.getUrl());
+ startActivity(read);
+ break;
+ case R.id.action_toggle_desktop:
+ currentTab.toggleDesktopUA(this);
+ currentTab.reload();
+ closeDrawers();
+ break;
+ }
+ }
+
+ /**
+ * Handle long presses on views that use this class
+ * as their OnLongClickListener. This method should
+ * distinguish between the IDs of the views that are
+ * getting clicked.
+ *
+ * @param view the view that has been long pressed
+ * @return returns true since the method handles the long press
+ * event
+ */
+ @Override
+ public boolean onLongClick(View view) {
+ return true;
+ }
+
+ // TODO Check if all the calls are relative to TabsFragement
+ /**
+ * A utility method that creates a FrameLayout button with the given ID and
+ * sets the image of the button to the given image ID. The OnClick and OnLongClick
+ * listeners are set to this class, so BrowserActivity should handle those events
+ * there. Additionally, it tints the images according to the current theme.
+ * This method only is a convenience so that this code does not have to be repeated
+ * for the several "Buttons" that use this.
+ *
+ * @param buttonId the view id of the button
+ * @param imageId the image to set as the button image
+ */
+ private void setupFrameLayoutButton(@IdRes int buttonId, @IdRes int imageId) {
+ final View frameButton = findViewById(buttonId);
+ final ImageView buttonImage = (ImageView) findViewById(imageId);
+ frameButton.setOnClickListener(this);
+ frameButton.setOnLongClickListener(this);
+ buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+ }
+
+ /**
+ * This NetworkReceiver notifies each of the WebViews in the browser whether
+ * the network is currently connected or not. This is important because some
+ * JavaScript properties rely on the WebView knowing the current network state.
+ * It is used to help the browser be compliant with the HTML5 spec, sec. 5.7.7
+ */
+ private final NetworkReceiver mNetworkReceiver = new NetworkReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ super.onReceive(context, intent);
+ boolean isConnected = isConnected(context);
+ Log.d(Constants.TAG, "Network Connected: " + String.valueOf(isConnected));
+ tabsManager.notifyConnectioneStatus(isConnected);
+ }
+ };
+
+ /**
+ * Handle the callback that permissions requested have been granted or not.
+ * This method should act upon the results of the permissions request.
+ *
+ * @param requestCode the request code sent when initially making the request
+ * @param permissions the array of the permissions that was requested
+ * @param grantResults the results of the permissions requests that provides
+ * information on whether the request was granted or not
+ */
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ PermissionsManager.getInstance().notifyPermissionsChange(permissions);
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ private final Object mBusEventListener = new Object() {
+
+ /**
+ * Load the given url in the current tab, used by the the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment} and by the
+ * {@link LightningDialogBuilder}
+ *
+ * @param event Bus event indicating that the user has clicked a bookmark
+ */
+ @Subscribe
+ public void loadUrlInCurrentTab(final BrowserEvents.OpenUrlInCurrentTab event) {
+ loadUrlInCurrentView(event.url);
+ // 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 url in a new tab, used by the the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment} and by the
+ * {@link LightningDialogBuilder}
+ *
+ * @param event Bus event indicating that the user wishes
+ * to open a bookmark in a new tab
+ */
+ @Subscribe
+ public void loadUrlInNewTab(final BrowserEvents.OpenUrlInNewTab event) {
+ BrowserActivity.this.newTab(event.url, 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 an event that the user wishes to bookmark the current page
+ */
+ @Subscribe
+ public void bookmarkCurrentPage(final BookmarkEvents.WantToBookmarkCurrentPage event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.AddBookmark(currentTab.getTitle(), currentTab.getUrl()));
+ }
+ }
+
+ /**
+ * This message is received when a bookmark was added by the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment}
+ *
+ * @param event the event that a bookmark has been added
+ */
+ @Subscribe
+ public void bookmarkAdded(final BookmarkEvents.Added event) {
+ mSearchAdapter.refreshBookmarks();
+ }
+
+ /**
+ * This method is called when the user edits a bookmark.
+ *
+ * @param event the event that the bookmark has changed.
+ */
+ @Subscribe
+ public void bookmarkChanged(final BookmarkEvents.BookmarkChanged event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE)
+ && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
+ currentTab.loadBookmarkpage();
+ }
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl()));
+ }
+ }
+
+ /**
+ * Notify the browser that a bookmark was deleted.
+ *
+ * @param event the event that the bookmark has been deleted
+ */
+ @Subscribe
+ public void bookmarkDeleted(final BookmarkEvents.Deleted event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ final WebView currentWebView = currentTab.getWebView();
+ if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE)
+ && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) {
+ currentTab.loadBookmarkpage();
+ }
+ if (currentTab != null) {
+ mEventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.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 an event notifying the browser that the bookmark drawer
+ * should be closed.
+ */
+ @Subscribe
+ public void closeBookmarks(final BookmarkEvents.CloseBookmarks event) {
+ mDrawerLayout.closeDrawer(mDrawerRight);
+ }
+
+ /**
+ * The user wants to close a tab
+ *
+ * @param event contains the position inside the tabs adapter
+ */
+ @Subscribe
+ public void closeTab(final TabEvents.CloseTab event) {
+ deleteTab(event.position);
+ }
+
+ /**
+ * The user clicked on a tab, let's show it
+ *
+ * @param event contains the tab position in the tabs adapter
+ */
+ @Subscribe
+ public void showTab(final TabEvents.ShowTab event) {
+ BrowserActivity.this.showTab(event.position);
+ }
+
+ /**
+ * The user long pressed on a tab, ask him if he want to close the tab
+ *
+ * @param event contains the tab position in the tabs adapter
+ */
+ @Subscribe
+ public void showCloseDialog(final TabEvents.ShowCloseDialog event) {
+ BrowserActivity.this.showCloseDialog(event.position);
+ }
+
+ /**
+ * The user wants to create a new tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void newTab(final TabEvents.NewTab event) {
+ BrowserActivity.this.newTab(null, true);
+ }
+
+ /**
+ * The user wants to go back on current tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void goBack(final NavigationEvents.GoBack event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.canGoBack()) {
+ currentTab.goBack();
+ } else {
+ deleteTab(tabsManager.positionOf(currentTab));
+ }
+ }
+ }
+
+ /**
+ * The user wants to go forward on current tab
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void goForward(final NavigationEvents.GoForward event) {
+ final LightningView currentTab = tabsManager.getCurrentTab();
+ if (currentTab != null) {
+ if (currentTab.canGoForward()) {
+ currentTab.goForward();
+ }
+ }
+ }
+
+ /**
+ * The user long pressed the new tab button
+ *
+ * @param event a marker
+ */
+ @Subscribe
+ public void newTabLongPress(final TabEvents.NewTabLongPress event) {
+ String url = mPreferences.getSavedUrl();
+ if (url != null) {
+ BrowserActivity.this.newTab(url, true);
+
+ Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab);
+ }
+ mPreferences.setSavedUrl(null);
+ }
+
+ @Subscribe
+ public void displayInSnackbar(final BrowserEvents.ShowSnackBarMessage event) {
+ if (event.message != null) {
+ Utils.showSnackbar(BrowserActivity.this, event.message);
+ } else {
+ Utils.showSnackbar(BrowserActivity.this, event.stringRes);
+ }
+ }
+ };
+}
diff --git a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
index b7be9d3..b46e42f 100644
--- a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
@@ -18,13 +18,13 @@ public class IncognitoActivity extends BrowserActivity {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(this);
}
- cookieManager.setAcceptCookie(PreferenceManager.getInstance().getIncognitoCookiesEnabled());
+ cookieManager.setAcceptCookie(mPreferences.getIncognitoCookiesEnabled());
}
- @Override
- public synchronized void initializeTabs() {
- newTab(null, true);
- }
+// @Override
+// public synchronized void initializeTabs() {
+// newTab(null, true);
+// }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
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 68d6022..808ea0c 100644
--- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java
@@ -18,14 +18,14 @@ public class MainActivity extends BrowserActivity {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(this);
}
- cookieManager.setAcceptCookie(PreferenceManager.getInstance().getCookiesEnabled());
+ cookieManager.setAcceptCookie(mPreferences.getCookiesEnabled());
}
- @Override
- public synchronized void initializeTabs() {
- restoreOrNewTab();
- // if incognito mode use newTab(null, true); instead
- }
+// @Override
+// public synchronized void initializeTabs() {
+// // restoreOrNewTab();
+// // if incognito mode use newTab(null, true); instead
+// }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
diff --git a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
index 8474e85..e1847b6 100644
--- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
@@ -22,6 +22,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import acr.browser.lightning.R;
+import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.reading.HtmlFetcher;
@@ -49,7 +50,7 @@ public class ReadingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
overridePendingTransition(R.anim.slide_in_from_right, R.anim.fade_out_scale);
- mPreferences = PreferenceManager.getInstance();
+ mPreferences = BrowserApp.getAppComponent().getPreferenceManager();
mInvert = mPreferences.getInvertColors();
final int color;
if (mInvert) {
diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java
new file mode 100644
index 0000000..19f159b
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java
@@ -0,0 +1,222 @@
+package acr.browser.lightning.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.webkit.WebView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import acr.browser.lightning.controller.BrowserController;
+import acr.browser.lightning.preference.PreferenceManager;
+import acr.browser.lightning.utils.Utils;
+import acr.browser.lightning.view.LightningView;
+
+/**
+ * @author Stefano Pacifici
+ * @date 2015/09/14
+ */
+@Singleton
+public class TabsManager {
+
+ private final List mWebViewList = new ArrayList<>();
+ private LightningView mCurrentTab;
+
+ @Inject
+ PreferenceManager mPreferenceManager;
+
+ @Inject
+ public TabsManager() {
+ }
+
+ public void restoreTabs(BrowserActivity activity, boolean darkTheme, boolean incognito) {
+ mWebViewList.clear();
+ mCurrentTab = null;
+ if (!incognito && mPreferenceManager.getRestoreLostTabsEnabled()) {
+ final String mem = mPreferenceManager.getMemoryUrl();
+ mPreferenceManager.setMemoryUrl("");
+ String[] array = Utils.getArray(mem);
+ int count = 0;
+ for (String urlString : array) {
+ if (!urlString.isEmpty()) {
+ newTab(activity, urlString, darkTheme, incognito);
+ }
+ }
+ }
+ if (mWebViewList.size() == 0) {
+ newTab(activity, null, darkTheme, incognito);
+ }
+ // mCurrentTab = mWebViewList.get(0);
+ }
+
+ /**
+ * Return a clone of the current tabs list. The list will not be updated, the user has to fetch
+ * a new copy when notified.
+ *
+ * @return a copy of the current tabs list
+ */
+ public List getTabsList() {
+ return new ArrayList<>(mWebViewList);
+ }
+
+ /**
+ * Return the tab at the given position in tabs list, or null if position is not in tabs list
+ * range.
+ *
+ * @param position the index in tabs list
+ * @return the corespondent {@link LightningView}, or null if the index is invalid
+ */
+ @Nullable
+ public LightningView getTabAtPosition(final int position) {
+ if (position < 0 || position >= mWebViewList.size()) {
+ return null;
+ }
+
+ return mWebViewList.get(position);
+ }
+
+ /**
+ * Try to low memory pressure
+ */
+ public void freeMemory() {
+ for (LightningView tab: mWebViewList) {
+ tab.freeMemory();
+ }
+ }
+
+ /**
+ * Shutdown the manager
+ */
+ public synchronized void shutdown() {
+ for (LightningView tab: mWebViewList) {
+ tab.onDestroy();
+ }
+ mWebViewList.clear();
+ }
+
+ /**
+ * Resume the tabs
+ *
+ * @param context
+ */
+ public synchronized void resume(final Context context) {
+ for (LightningView tab: mWebViewList) {
+ tab.initializePreferences(null, context);
+ }
+ }
+
+ /**
+ * Forward network connection status to the webviews.
+ *
+ * @param isConnected
+ */
+ public synchronized void notifyConnectioneStatus(final boolean isConnected) {
+ for (LightningView tab: mWebViewList) {
+ final WebView webView = tab.getWebView();
+ if (webView != null) {
+ webView.setNetworkAvailable(isConnected);
+ }
+ }
+ }
+ /**
+ * @return The number of currently opened tabs
+ */
+ public int size() {
+ return mWebViewList.size();
+ }
+
+ /**
+ * Create and return a new tab. The tab is automatically added to the tabs list.
+ *
+ * @param activity
+ * @param url
+ * @param darkTheme
+ * @param isIncognito
+ * @return
+ */
+ public synchronized LightningView newTab(final BrowserActivity activity,
+ final String url, final boolean darkTheme,
+ final boolean isIncognito) {
+ final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito);
+ mWebViewList.add(tab);
+ return tab;
+ }
+
+ /**
+ * Remove a tab and return its reference or null if the position is not in tabs range
+ *
+ * @param position The position of the tab to remove
+ * @return The removed tab reference or null
+ */
+ @Nullable
+ public synchronized LightningView deleteTab(final int position) {
+ if (position >= mWebViewList.size()) {
+ return null;
+ }
+ final LightningView tab = mWebViewList.remove(position);
+ tab.onDestroy();
+ return tab;
+ }
+
+ /**
+ * Return the position of the given tab
+ * @param tab
+ * @return
+ */
+ public int positionOf(final LightningView tab) {
+ return mWebViewList.indexOf(tab);
+ }
+
+ /**
+ * @return A string representation of the currently opened tabs
+ */
+ public String tabsString() {
+ final StringBuilder builder = new StringBuilder();
+ for (LightningView tab: mWebViewList) {
+ final String url = tab.getUrl();
+ if (url != null && !url.isEmpty()) {
+ builder.append(url).append("|$|SEPARATOR|$|");
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Return the {@link WebView} associated to the current tab, or null if there is no current tab
+ * @return a {@link WebView} or null
+ */
+ @Nullable
+ public WebView getCurrentWebView() {
+ return mCurrentTab != null ? mCurrentTab.getWebView() : null;
+ }
+
+ /**
+ * TODO We should remove also this, but probably not
+ * @return
+ */
+ public LightningView getCurrentTab() {
+ return mCurrentTab;
+ }
+
+ /**
+ * Switch the current tab to the one at the given position. It returns the selected. After this
+ * call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if
+ * position is valid.
+ *
+ * @return the selected tab or null if position is out of tabs range
+ */
+ @Nullable
+ public LightningView switchToTab(final int position) {
+ if (position < 0 || position >= mWebViewList.size()) {
+ return null;
+ } else {
+ final LightningView tab = mWebViewList.get(position);
+ mCurrentTab = tab;
+ return tab;
+ }
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java
index 88a01dc..13f210e 100644
--- a/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java
@@ -5,18 +5,25 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
+import javax.inject.Inject;
+
import acr.browser.lightning.R;
+import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
public abstract class ThemableBrowserActivity extends AppCompatActivity {
+ @Inject
+ PreferenceManager mPreferences;
+
private int mTheme;
private boolean mShowTabsInDrawer;
@Override
protected void onCreate(Bundle savedInstanceState) {
- mTheme = PreferenceManager.getInstance().getUseTheme();
- mShowTabsInDrawer = PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet());
+ BrowserApp.getAppComponent().inject(this);
+ mTheme = mPreferences.getUseTheme();
+ mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet());
// set the theme
if (mTheme == 1) {
@@ -30,8 +37,8 @@ public abstract class ThemableBrowserActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
- int theme = PreferenceManager.getInstance().getUseTheme();
- boolean drawerTabs = PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet());
+ int theme = mPreferences.getUseTheme();
+ boolean drawerTabs = mPreferences.getShowTabsInDrawer(!isTablet());
if (theme != mTheme || mShowTabsInDrawer != drawerTabs) {
restart();
}
diff --git a/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
index c5a4573..475c0ee 100644
--- a/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
+++ b/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
@@ -4,6 +4,7 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import acr.browser.lightning.R;
+import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ThemeUtils;
@@ -13,7 +14,7 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi
@Override
protected void onCreate(Bundle savedInstanceState) {
- mTheme = PreferenceManager.getInstance().getUseTheme();
+ mTheme = BrowserApp.getAppComponent().getPreferenceManager().getUseTheme();
// set the theme
if (mTheme == 0) {
@@ -32,7 +33,7 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi
@Override
protected void onResume() {
super.onResume();
- if (PreferenceManager.getInstance().getUseTheme() != mTheme) {
+ if (BrowserApp.getAppComponent().getPreferenceManager().getUseTheme() != mTheme) {
restart();
}
}
diff --git a/app/src/main/java/acr/browser/lightning/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java
index dbaf0bc..6be83ca 100644
--- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java
+++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java
@@ -1,13 +1,23 @@
package acr.browser.lightning.app;
+import android.content.Context;
+
+import com.squareup.otto.Bus;
+
import javax.inject.Singleton;
import acr.browser.lightning.activity.BrowserActivity;
+import acr.browser.lightning.activity.ThemableBrowserActivity;
import acr.browser.lightning.constant.BookmarkPage;
-import acr.browser.lightning.dialog.BookmarksDialogBuilder;
+import acr.browser.lightning.database.HistoryDatabase;
+import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.fragment.BookmarkSettingsFragment;
import acr.browser.lightning.fragment.BookmarksFragment;
+import acr.browser.lightning.fragment.LightningPreferenceFragment;
+import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.SearchAdapter;
+import acr.browser.lightning.preference.PreferenceManager;
+import acr.browser.lightning.view.LightningView;
import dagger.Component;
/**
@@ -25,7 +35,25 @@ public interface AppComponent {
void inject(SearchAdapter adapter);
- void inject(BookmarksDialogBuilder builder);
+ void inject(LightningDialogBuilder builder);
void inject(BookmarkPage bookmarkPage);
+
+ void inject(TabsFragment fragment);
+
+ PreferenceManager getPreferenceManager();
+
+ void inject(LightningPreferenceFragment fragment);
+
+ BookmarkPage getBookmarkPage();
+
+ Bus getBus();
+
+ HistoryDatabase getHistoryDatabase();
+
+ Context getApplicationContext();
+
+ void inject(LightningView lightningView);
+
+ void inject(ThemableBrowserActivity activity);
}
diff --git a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
index 3331eb7..1bff1cb 100644
--- a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
+++ b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
@@ -11,28 +11,6 @@ public final class 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
*/
@@ -61,13 +39,6 @@ public final class BookmarkEvents {
}
}
- /**
- * 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}
diff --git a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
index 15ff373..478dbce 100644
--- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
+++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
@@ -1,5 +1,7 @@
package acr.browser.lightning.bus;
+import android.support.annotation.StringRes;
+
/**
* Created by Stefano Pacifici on 26/08/15.
*/
@@ -24,9 +26,8 @@ public final class BrowserEvents {
}
/**
- * 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.
+ * Notify the current page has a new url. This is generally used to update the
+ * {@link acr.browser.lightning.fragment.BookmarksFragment} interface.
*/
public static class CurrentPageUrl {
public final String url;
@@ -41,4 +42,55 @@ public final class BrowserEvents {
*/
public static class UserPressedBack {
}
+
+ /**
+ * Notify that the user closed or opened a tab
+ */
+ public static class TabsChanged {
+ }
+
+ /**
+ *
+ */
+
+ /**
+ * Notify the Browser to display a SnackBar in the main activity
+ */
+ public static class ShowSnackBarMessage {
+ public final String message;
+ @StringRes
+ public final int stringRes;
+
+ public ShowSnackBarMessage(final String message) {
+ this.message = message;
+ this.stringRes = -1;
+ }
+
+ public ShowSnackBarMessage(@StringRes final int stringRes) {
+ this.message = null;
+ this.stringRes = stringRes;
+ }
+ }
+
+ /**
+ * The user want to open the given url in the current tab
+ */
+ public final static class OpenUrlInCurrentTab {
+ public final String url;
+
+ public OpenUrlInCurrentTab(final String url) {
+ this.url = url;
+ }
+ }
+
+ /**
+ * The user ask to open the given url as new tab
+ */
+ public final static class OpenUrlInNewTab {
+ public final String url;
+
+ public OpenUrlInNewTab(final String url) {
+ this.url = url;
+ }
+ }
}
diff --git a/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java b/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java
new file mode 100644
index 0000000..5f7519f
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java
@@ -0,0 +1,34 @@
+package acr.browser.lightning.bus;
+
+/**
+ * Collections of navigation events, like go back or go forward
+ *
+ * @author Stefano Pacifici
+ * @date 2015/09/15
+ */
+public class NavigationEvents {
+ private NavigationEvents() {
+ // No instances please
+ }
+
+ /**
+ * Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses back
+ * button.
+ */
+ public static class GoBack {
+ }
+
+ /**
+ * Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses forward
+ * button.
+ */
+ public static class GoForward {
+ }
+
+ /**
+ * Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses the home
+ * button.
+ */
+ public static class GoHome {
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java
new file mode 100644
index 0000000..a2bac5c
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java
@@ -0,0 +1,65 @@
+package acr.browser.lightning.bus;
+
+/**
+ * A collection of events been sent by {@link acr.browser.lightning.fragment.TabsFragment}
+ *
+ * @author Stefano Pacifici
+ * @date 2015/09/14
+ */
+public final class TabEvents {
+
+ private TabEvents() {
+ // No instances
+ }
+
+
+ /**
+ * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the
+ * tab exit button
+ */
+ public static class CloseTab {
+ public final int position;
+
+ public CloseTab(int position) {
+ this.position = position;
+ }
+ }
+
+ /**
+ * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the
+ * tab itself.
+ */
+ public static class ShowTab {
+ public final int position;
+
+ public ShowTab(int position) {
+ this.position = position;
+ }
+ }
+
+ /**
+ * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user long press on the
+ * tab itself.
+ */
+ public static class ShowCloseDialog {
+ public final int position;
+
+ public ShowCloseDialog(int position) {
+ this.position = position;
+ }
+ }
+
+ /**
+ * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user want to create a
+ * new tab.
+ */
+ public static class NewTab {
+ }
+
+ /**
+ * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user long presses on
+ * new tab button.
+ */
+ public static class NewTabLongPress {
+ }
+}
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 67c1765..1355844 100644
--- a/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java
+++ b/app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java
@@ -62,7 +62,8 @@ public final class BookmarkPage {
CACHE_DIR = context.getCacheDir();
}
- public void buildBookmarkPage(final String folder, final List list) {
+ public void buildBookmarkPage(final String folder) {
+ final List list = manager.getBookmarksFromFolder(folder, true);
final File bookmarkWebPage;
if (folder == null || folder.isEmpty()) {
bookmarkWebPage = new File(FILES_DIR, Constants.BOOKMARKS_FILENAME);
@@ -83,7 +84,7 @@ public final class BookmarkPage {
new Thread(new Runnable() {
@Override
public void run() {
- buildBookmarkPage(item.getTitle(), manager.getBookmarksFromFolder(item.getTitle(), true));
+ buildBookmarkPage(item.getTitle());
}
}).run();
} else {
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 41dc907..8e7d936 100644
--- a/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java
+++ b/app/src/main/java/acr/browser/lightning/constant/HistoryPage.java
@@ -66,7 +66,7 @@ public class HistoryPage {
}
private static List getWebHistory(Context context) {
- HistoryDatabase databaseHandler = HistoryDatabase.getInstance();
+ HistoryDatabase databaseHandler = BrowserApp.getAppComponent().getHistoryDatabase();
return databaseHandler.getLastHundredItems();
}
}
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 35b5453..f640023 100644
--- a/app/src/main/java/acr/browser/lightning/constant/StartPage.java
+++ b/app/src/main/java/acr/browser/lightning/constant/StartPage.java
@@ -57,11 +57,12 @@ public class StartPage {
StringBuilder homepageBuilder = new StringBuilder(StartPage.HEAD);
String icon;
String searchUrl;
- switch (PreferenceManager.getInstance().getSearchChoice()) {
+ final PreferenceManager preferenceManager = BrowserApp.getAppComponent().getPreferenceManager();
+ switch (preferenceManager.getSearchChoice()) {
case 0:
// CUSTOM SEARCH
icon = "file:///android_asset/lightning.png";
- searchUrl = PreferenceManager.getInstance().getSearchUrl();
+ searchUrl = preferenceManager.getSearchUrl();
break;
case 1:
// GOOGLE_SEARCH;
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 73c8e7f..a454386 100644
--- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java
+++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java
@@ -23,18 +23,12 @@ public interface BrowserController {
void openFileChooser(ValueCallback uploadMsg);
- void updateTabs();
-
- void onLongPress();
+// void onLongPress();
void onShowCustomView(View view, CustomViewCallback callback);
void onHideCustomView();
- Bitmap getDefaultVideoPoster();
-
- View getVideoLoadingProgressView();
-
void onCreateWindow(Message resultMsg);
void onCloseWindow(LightningView view);
@@ -43,16 +37,12 @@ public interface BrowserController {
void showActionBar();
- void longClickPage(String url);
-
- void openBookmarkPage(WebView view);
+ // void longClickPage(String url);
void showFileChooser(ValueCallback filePathCallback);
void closeEmptyTab();
- boolean proxyIsNotReady();
-
// void updateBookmarkIndicator(String url);
}
diff --git a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
index 82801c5..36498fb 100644
--- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
+++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
@@ -12,9 +12,13 @@ import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
import java.util.List;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
+@Singleton
public class HistoryDatabase extends SQLiteOpenHelper {
// All Static variables
@@ -39,14 +43,8 @@ public class HistoryDatabase extends SQLiteOpenHelper {
private boolean mLock;
- public static HistoryDatabase getInstance() {
- if (mInstance == null || mInstance.isClosed()) {
- mInstance = new HistoryDatabase(BrowserApp.getAppContext());
- }
- return mInstance;
- }
-
- private HistoryDatabase(Context context) {
+ @Inject
+ public HistoryDatabase(Context context) {
super(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION);
mDatabase = this.getWritableDatabase();
}
@@ -91,7 +89,7 @@ public class HistoryDatabase extends SQLiteOpenHelper {
}
private void openIfNecessary() {
- if (mDatabase == null) {
+ if (isClosed()) {
mDatabase = this.getWritableDatabase();
}
}
diff --git a/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java
similarity index 60%
rename from app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java
rename to app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java
index ec8282c..923472a 100644
--- a/app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java
+++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java
@@ -1,8 +1,13 @@
package acr.browser.lightning.dialog;
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.ArrayAdapter;
@@ -19,24 +24,32 @@ 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.Constants;
+import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.database.BookmarkManager;
+import acr.browser.lightning.database.HistoryDatabase;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.utils.Utils;
/**
+ * TODO Rename this class it doesn't build dialogs only for bookmarks
+ *
* Created by Stefano Pacifici on 02/09/15, based on Anthony C. Restaino's code.
*/
-public class BookmarksDialogBuilder {
+public class LightningDialogBuilder {
@Inject
BookmarkManager bookmarkManager;
+ @Inject
+ HistoryDatabase mHistoryDatabase;
+
@Inject
Bus eventBus;
@Inject
- public BookmarksDialogBuilder() {
+ public LightningDialogBuilder() {
BrowserApp.getAppComponent().inject(this);
}
@@ -46,7 +59,7 @@ public class BookmarksDialogBuilder {
* @param context used to show the dialog
* @param url the long pressed url
*/
- public void showLongPressedDialogForUrl(final Context context, final String url) {
+ public void showLongPressedDialogForBookmarkUrl(final Context context, final String url) {
final HistoryItem item;
if (url.startsWith(Constants.FILE) && url.endsWith(Constants.BOOKMARKS_FILENAME)) {
// TODO hacky, make a better bookmark mechanism in the future
@@ -65,19 +78,19 @@ public class BookmarksDialogBuilder {
if (item.isFolder()) {
showBookmarkFolderLongPressedDialog(context, item);
} else {
- showLongPressedDialogForUrl(context, item);
+ showLongPressedDialogForBookmarkUrl(context, item);
}
}
}
- public void showLongPressedDialogForUrl(final Context context, final HistoryItem item) {
+ public void showLongPressedDialogForBookmarkUrl(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));
+ eventBus.post(new BrowserEvents.OpenUrlInNewTab(item.getUrl()));
break;
case DialogInterface.BUTTON_NEGATIVE:
if (bookmarkManager.deleteBookmark(item)) {
@@ -197,4 +210,103 @@ public class BookmarksDialogBuilder {
});
editFolderDialog.show();
}
+
+ public void showLongPressedHistoryLinkDialog(final Context context, final String url) {
+ DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ eventBus.post(new BrowserEvents.OpenUrlInNewTab(url));
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ mHistoryDatabase.deleteHistoryItem(url);
+ // openHistory();
+ eventBus.post(new BrowserEvents.OpenUrlInCurrentTab(HistoryPage.getHistoryPage(context)));
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ eventBus.post(new BrowserEvents.OpenUrlInCurrentTab(url));
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.action_history)
+ .setMessage(R.string.dialog_history_long_press)
+ .setCancelable(true)
+ .setPositiveButton(R.string.action_new_tab, dialogClickListener)
+ .setNegativeButton(R.string.action_delete, dialogClickListener)
+ .setNeutralButton(R.string.action_open, dialogClickListener)
+ .show();
+ }
+
+ // TODO There should be a way in which we do not need an activity reference to dowload a file
+ public void showLongPressImageDialog(@NonNull final Activity activity, @NonNull final String url,
+ @NonNull final String userAgent) {
+ DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ eventBus.post(new BrowserEvents.OpenUrlInNewTab(url));
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ eventBus.post(new BrowserEvents.OpenUrlInCurrentTab(url));
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ if (Build.VERSION.SDK_INT > 8) {
+ // Should be better to send an event on the bus here
+ Utils.downloadFile(activity, url,
+ userAgent, "attachment");
+ }
+ break;
+ }
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ builder.setTitle(url.replace(Constants.HTTP, ""))
+ .setCancelable(true)
+ .setMessage(R.string.dialog_image)
+ .setPositiveButton(R.string.action_new_tab, dialogClickListener)
+ .setNegativeButton(R.string.action_open, dialogClickListener)
+ .setNeutralButton(R.string.action_download, dialogClickListener)
+ .show();
+ }
+
+ public void showLongPressLinkDialog(final Context context, final String url) {
+ DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ eventBus.post(new BrowserEvents.OpenUrlInNewTab(url));
+ break;
+
+ case DialogInterface.BUTTON_NEGATIVE:
+ eventBus.post(new BrowserEvents.OpenUrlInCurrentTab(url));
+ break;
+
+ case DialogInterface.BUTTON_NEUTRAL:
+ ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText("label", url);
+ clipboard.setPrimaryClip(clip);
+ break;
+ }
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context); // dialog
+ builder.setTitle(url)
+ .setCancelable(true)
+ .setMessage(R.string.dialog_link)
+ .setPositiveButton(R.string.action_new_tab, dialogClickListener)
+ .setNegativeButton(R.string.action_open, dialogClickListener)
+ .setNeutralButton(R.string.action_copy, dialogClickListener)
+ .show();
+ }
+
}
diff --git a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
index 82d25aa..e182811 100644
--- a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
+++ b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
@@ -3,10 +3,8 @@
*/
package acr.browser.lightning.download;
-import android.app.Activity;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -19,13 +17,17 @@ import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.URLUtil;
+import com.squareup.otto.Bus;
+
import java.io.File;
import java.io.IOException;
+import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.R;
+import acr.browser.lightning.activity.MainActivity;
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
-import acr.browser.lightning.preference.PreferenceManager;
-import acr.browser.lightning.utils.Utils;
/**
* Handle download requests
@@ -44,13 +46,13 @@ public class DownloadHandler {
* Notify the host application a download should be done, or that the data
* should be streamed if a streaming viewer is available.
*
- * @param activity Activity requesting the download.
- * @param url The full url to the content that should be downloaded
- * @param userAgent User agent of the downloading application.
- * @param contentDisposition Content-disposition http header, if present.
- * @param mimetype The mimetype of the content reported by the server
+ * @param context The context in which the download was requested.
+ * @param url The full url to the content that should be downloaded
+ * @param userAgent User agent of the downloading application.
+ * @param contentDisposition Content-disposition http header, if present.
+ * @param mimetype The mimetype of the content reported by the server
*/
- public static void onDownloadStart(Activity activity, String url, String userAgent,
+ public static void onDownloadStart(Context context, String url, String userAgent,
String contentDisposition, String mimetype) {
// if we're dealing wih A/V content that's not explicitly marked
// for download, check if it's streamable.
@@ -61,18 +63,17 @@ public class DownloadHandler {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimetype);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ResolveInfo info = activity.getPackageManager().resolveActivity(intent,
+ ResolveInfo info = context.getPackageManager().resolveActivity(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (info != null) {
- ComponentName myName = activity.getComponentName();
// If we resolved to ourselves, we don't want to attempt to
// load the url only to try and download it again.
- if (!myName.getPackageName().equals(info.activityInfo.packageName)
- || !myName.getClassName().equals(info.activityInfo.name)) {
+ if (BuildConfig.APPLICATION_ID.equals(info.activityInfo.packageName)
+ || MainActivity.class.getName().equals(info.activityInfo.name)) {
// someone (other than us) knows how to handle this mime
// type with this scheme, don't download.
try {
- activity.startActivity(intent);
+ context.startActivity(intent);
return;
} catch (ActivityNotFoundException ex) {
// Best behavior is to fall back to a download in this
@@ -81,8 +82,7 @@ public class DownloadHandler {
}
}
}
- onDownloadStartNoStream(activity, url, userAgent, contentDisposition, mimetype
- );
+ onDownloadStartNoStream(context, url, userAgent, contentDisposition, mimetype);
}
// This is to work around the fact that java.net.URI throws Exceptions
@@ -119,17 +119,17 @@ public class DownloadHandler {
* Notify the host application a download should be done, even if there is a
* streaming viewer available for thise type.
*
- * @param activity Activity requesting the download.
+ * @param context The context in which the download is requested.
* @param url The full url to the content that should be downloaded
* @param userAgent User agent of the downloading application.
* @param contentDisposition Content-disposition http header, if present.
* @param mimetype The mimetype of the content reported by the server
*/
/* package */
- private static void onDownloadStartNoStream(final Activity activity, String url, String userAgent,
+ private static void onDownloadStartNoStream(final Context context, String url, String userAgent,
String contentDisposition, String mimetype) {
-
- String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
+ final Bus eventBus = BrowserApp.getAppComponent().getBus();
+ final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
// Check to see if we have an SDCard
String status = Environment.getExternalStorageState();
@@ -139,14 +139,14 @@ public class DownloadHandler {
// Check to see if the SDCard is busy, same as the music app
if (status.equals(Environment.MEDIA_SHARED)) {
- msg = activity.getString(R.string.download_sdcard_busy_dlg_msg);
+ msg = context.getString(R.string.download_sdcard_busy_dlg_msg);
title = R.string.download_sdcard_busy_dlg_title;
} else {
- msg = activity.getString(R.string.download_no_sdcard_dlg_msg, filename);
+ msg = context.getString(R.string.download_no_sdcard_dlg_msg, filename);
title = R.string.download_no_sdcard_dlg_title;
}
- new AlertDialog.Builder(activity).setTitle(title)
+ new AlertDialog.Builder(context).setTitle(title)
.setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg)
.setPositiveButton(R.string.action_ok, null).show();
return;
@@ -162,7 +162,7 @@ public class DownloadHandler {
// This only happens for very bad urls, we want to catch the
// exception here
Log.e(TAG, "Exception while trying to parse url '" + url + '\'', e);
- Utils.showSnackbar(activity, R.string.problem_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_download));
return;
}
@@ -172,7 +172,7 @@ public class DownloadHandler {
try {
request = new DownloadManager.Request(uri);
} catch (IllegalArgumentException e) {
- Utils.showSnackbar(activity, R.string.cannot_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.cannot_download));
return;
}
request.setMimeType(mimetype);
@@ -180,7 +180,7 @@ public class DownloadHandler {
// or, should it be set to one of several Environment.DIRECTORY* dirs
// depending on mimetype?
- String location = PreferenceManager.getInstance().getDownloadDirectory();
+ String location = BrowserApp.getAppComponent().getPreferenceManager().getDownloadDirectory();
Uri downloadFolder;
if (location != null) {
location = addNecessarySlashes(location);
@@ -188,18 +188,18 @@ public class DownloadHandler {
} else {
location = addNecessarySlashes(DEFAULT_DOWNLOAD_PATH);
downloadFolder = Uri.parse(location);
- PreferenceManager.getInstance().setDownloadDirectory(location);
+ BrowserApp.getAppComponent().getPreferenceManager().setDownloadDirectory(location);
}
File dir = new File(downloadFolder.getPath());
if (!dir.isDirectory() && !dir.mkdirs()) {
// Cannot make the directory
- Utils.showSnackbar(activity, R.string.problem_location_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
return;
}
if (!isWriteAccessAvailable(downloadFolder)) {
- Utils.showSnackbar(activity, R.string.problem_location_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
return;
}
request.setDestinationUri(Uri.parse(Constants.FILE + location + filename));
@@ -219,9 +219,9 @@ public class DownloadHandler {
}
// We must have long pressed on a link or image to download it. We
// are not sure of the mimetype in this case, so do a head request
- new FetchUrlMimeType(activity, request, addressString, cookies, userAgent).start();
+ new FetchUrlMimeType(context, request, addressString, cookies, userAgent).start();
} else {
- final DownloadManager manager = (DownloadManager) activity
+ final DownloadManager manager = (DownloadManager) context
.getSystemService(Context.DOWNLOAD_SERVICE);
new Thread() {
@Override
@@ -231,15 +231,16 @@ public class DownloadHandler {
} catch (IllegalArgumentException e) {
// Probably got a bad URL or something
e.printStackTrace();
- Utils.showSnackbar(activity, R.string.cannot_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.cannot_download));
} catch (SecurityException e) {
// TODO write a download utility that downloads files rather than rely on the system
// because the system can only handle Environment.getExternal... as a path
- Utils.showSnackbar(activity, R.string.problem_location_download);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
}
}
}.start();
- Utils.showSnackbar(activity, activity.getString(R.string.download_pending) + ' ' + filename);
+ eventBus.post(new BrowserEvents.ShowSnackBarMessage(
+ context.getString(R.string.download_pending) + ' ' + filename));
}
}
@@ -320,12 +321,12 @@ public class DownloadHandler {
} catch (IOException ignored) {
return false;
}
- }
+ }
public static String addNecessarySlashes(String originalPath) {
if (originalPath == null || originalPath.length() == 0) {
return "/";
- }
+ }
if (originalPath.charAt(originalPath.length() - 1) != '/') {
originalPath = originalPath + '/';
}
diff --git a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
index 39da66f..80d5995 100644
--- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
+++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
@@ -3,18 +3,21 @@
*/
package acr.browser.lightning.download;
-import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.os.Environment;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
+import com.squareup.otto.Bus;
+
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import acr.browser.lightning.R;
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.utils.Utils;
/**
@@ -27,7 +30,7 @@ import acr.browser.lightning.utils.Utils;
*/
class FetchUrlMimeType extends Thread {
- private final Activity mActivity;
+ private final Context mContext;
private final DownloadManager.Request mRequest;
@@ -37,9 +40,9 @@ class FetchUrlMimeType extends Thread {
private final String mUserAgent;
- public FetchUrlMimeType(Activity activity, DownloadManager.Request request, String uri,
+ public FetchUrlMimeType(Context context, DownloadManager.Request request, String uri,
String cookies, String userAgent) {
- mActivity = activity;
+ mContext = context;
mRequest = request;
mUri = uri;
mCookies = cookies;
@@ -50,6 +53,7 @@ class FetchUrlMimeType extends Thread {
public void run() {
// User agent is likely to be null, though the AndroidHttpClient
// seems ok with that.
+ final Bus evenBus = BrowserApp.getAppComponent().getBus();
String mimeType = null;
String contentDisposition = null;
HttpURLConnection connection = null;
@@ -101,9 +105,9 @@ class FetchUrlMimeType extends Thread {
}
// Start the download
- DownloadManager manager = (DownloadManager) mActivity
+ DownloadManager manager = (DownloadManager) mContext
.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(mRequest);
- Utils.showSnackbar(mActivity, mActivity.getString(R.string.download_pending) + ' ' + filename);
+ evenBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + filename));
}
}
diff --git a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
index 72f3ab8..6d6b7a1 100644
--- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
+++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
@@ -3,7 +3,7 @@
*/
package acr.browser.lightning.download;
-import android.app.Activity;
+import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log;
@@ -15,10 +15,10 @@ import acr.browser.lightning.constant.Constants;
public class LightningDownloadListener implements DownloadListener {
- private final Activity mActivity;
+ private final Context mContext;
- public LightningDownloadListener(Activity activity) {
- mActivity = activity;
+ public LightningDownloadListener(Context context) {
+ mContext = context;
}
@Override
@@ -30,7 +30,7 @@ public class LightningDownloadListener implements DownloadListener {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
- DownloadHandler.onDownloadStart(mActivity, url, userAgent,
+ DownloadHandler.onDownloadStart(mContext, url, userAgent,
contentDisposition, mimetype);
break;
@@ -40,12 +40,12 @@ public class LightningDownloadListener implements DownloadListener {
}
};
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext); // dialog
builder.setTitle(fileName)
- .setMessage(mActivity.getResources().getString(R.string.dialog_download))
- .setPositiveButton(mActivity.getResources().getString(R.string.action_download),
+ .setMessage(mContext.getResources().getString(R.string.dialog_download))
+ .setPositiveButton(mContext.getResources().getString(R.string.action_download),
dialogClickListener)
- .setNegativeButton(mActivity.getResources().getString(R.string.action_cancel),
+ .setNegativeButton(mContext.getResources().getString(R.string.action_cancel),
dialogClickListener).show();
Log.i(Constants.TAG, "Downloading" + fileName);
diff --git a/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
index 4f4b7a6..a7a4b1c 100644
--- a/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
+++ b/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
@@ -8,7 +8,6 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
-import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import java.util.Arrays;
@@ -16,9 +15,8 @@ import java.util.List;
import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants;
-import acr.browser.lightning.preference.PreferenceManager;
-public class AdvancedSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
+public class AdvancedSettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_NEWWINDOW = "allow_new_window";
private static final String SETTINGS_ENABLECOOKIES = "allow_cookies";
@@ -29,7 +27,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
private static final String SETTINGS_TEXTENCODING = "text_encoding";
private Activity mActivity;
- private PreferenceManager mPreferences;
private CheckBoxPreference cbAllowPopups, cbenablecookies, cbcookiesInkognito, cbrestoreTabs;
private Preference renderingmode, urlcontent, textEncoding;
private CharSequence[] mUrlOptions;
@@ -46,8 +43,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
}
private void initPrefs() {
- // mPreferences storage
- mPreferences = PreferenceManager.getInstance();
renderingmode = findPreference(SETTINGS_RENDERINGMODE);
textEncoding = findPreference(SETTINGS_TEXTENCODING);
@@ -65,7 +60,7 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
cbcookiesInkognito.setOnPreferenceChangeListener(this);
cbrestoreTabs.setOnPreferenceChangeListener(this);
- switch (mPreferences.getRenderingMode()) {
+ switch (mPreferenceManager.getRenderingMode()) {
case 0:
renderingmode.setSummary(getString(R.string.name_normal));
break;
@@ -80,16 +75,16 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
break;
}
- textEncoding.setSummary(mPreferences.getTextEncoding());
+ textEncoding.setSummary(mPreferenceManager.getTextEncoding());
mUrlOptions = getResources().getStringArray(R.array.url_content_array);
- int option = mPreferences.getUrlBoxContentChoice();
+ int option = mPreferenceManager.getUrlBoxContentChoice();
urlcontent.setSummary(mUrlOptions[option]);
- cbAllowPopups.setChecked(mPreferences.getPopupsEnabled());
- cbenablecookies.setChecked(mPreferences.getCookiesEnabled());
- cbcookiesInkognito.setChecked(mPreferences.getIncognitoCookiesEnabled());
- cbrestoreTabs.setChecked(mPreferences.getRestoreLostTabsEnabled());
+ cbAllowPopups.setChecked(mPreferenceManager.getPopupsEnabled());
+ cbenablecookies.setChecked(mPreferenceManager.getCookiesEnabled());
+ cbcookiesInkognito.setChecked(mPreferenceManager.getIncognitoCookiesEnabled());
+ cbrestoreTabs.setChecked(mPreferenceManager.getRestoreLostTabsEnabled());
}
@Override
@@ -114,19 +109,19 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
// switch preferences
switch (preference.getKey()) {
case SETTINGS_NEWWINDOW:
- mPreferences.setPopupsEnabled((Boolean) newValue);
+ mPreferenceManager.setPopupsEnabled((Boolean) newValue);
cbAllowPopups.setChecked((Boolean) newValue);
return true;
case SETTINGS_ENABLECOOKIES:
- mPreferences.setCookiesEnabled((Boolean) newValue);
+ mPreferenceManager.setCookiesEnabled((Boolean) newValue);
cbenablecookies.setChecked((Boolean) newValue);
return true;
case SETTINGS_COOKIESINKOGNITO:
- mPreferences.setIncognitoCookiesEnabled((Boolean) newValue);
+ mPreferenceManager.setIncognitoCookiesEnabled((Boolean) newValue);
cbcookiesInkognito.setChecked((Boolean) newValue);
return true;
case SETTINGS_RESTORETABS:
- mPreferences.setRestoreLostTabsEnabled((Boolean) newValue);
+ mPreferenceManager.setRestoreLostTabsEnabled((Boolean) newValue);
cbrestoreTabs.setChecked((Boolean) newValue);
return true;
default:
@@ -142,12 +137,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
mActivity.getString(R.string.name_grayscale),
mActivity.getString(R.string.name_inverted_grayscale)};
- int n = mPreferences.getRenderingMode();
+ int n = mPreferenceManager.getRenderingMode();
picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setRenderingMode(which);
+ mPreferenceManager.setRenderingMode(which);
switch (which) {
case 0:
renderingmode.setSummary(getString(R.string.name_normal));
@@ -172,12 +167,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.text_encoding));
final List textEncodingList = Arrays.asList(Constants.TEXT_ENCODINGS);
- int n = textEncodingList.indexOf(mPreferences.getTextEncoding());
+ int n = textEncodingList.indexOf(mPreferenceManager.getTextEncoding());
picker.setSingleChoiceItems(Constants.TEXT_ENCODINGS, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setTextEncoding(Constants.TEXT_ENCODINGS[which]);
+ mPreferenceManager.setTextEncoding(Constants.TEXT_ENCODINGS[which]);
textEncoding.setSummary(Constants.TEXT_ENCODINGS[which]);
}
});
@@ -189,12 +184,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.url_contents));
- int n = mPreferences.getUrlBoxContentChoice();
+ int n = mPreferenceManager.getUrlBoxContentChoice();
picker.setSingleChoiceItems(mUrlOptions, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setUrlBoxContentChoice(which);
+ mPreferenceManager.setUrlBoxContentChoice(which);
if (which < mUrlOptions.length) {
urlcontent.setSummary(mUrlOptions[which]);
}
diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
index 80aa3f9..28f9a4f 100644
--- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
+++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
@@ -1,6 +1,5 @@
package acr.browser.lightning.fragment;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
@@ -43,7 +42,7 @@ 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.dialog.LightningDialogBuilder;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.async.ImageDownloadTask;
import acr.browser.lightning.utils.ThemeUtils;
@@ -53,6 +52,10 @@ import acr.browser.lightning.utils.ThemeUtils;
*/
public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
+ private final static String TAG = BookmarksFragment.class.getSimpleName();
+
+ public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE";
+
// Managers
@Inject
BookmarkManager mBookmarkManager;
@@ -63,7 +66,10 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
// Dialog builder
@Inject
- BookmarksDialogBuilder mBookmarksDialogBuilder;
+ LightningDialogBuilder mBookmarksDialogBuilder;
+
+ @Inject
+ PreferenceManager mPreferenceManager;
// Adapter
private BookmarkViewAdapter mBookmarkAdapter;
@@ -81,6 +87,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
// Colors
private int mIconColor, mScrollIndex;
+ private boolean mIsIncognito;
+
// Init asynchronously the bookmark manager
private final Runnable mInitBookmarkManager = new Runnable() {
@Override
@@ -96,6 +104,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BrowserApp.getAppComponent().inject(this);
+ final Bundle arguments = getArguments();
+ final Context context = getContext();
+ mIsIncognito = arguments.getBoolean(INCOGNITO_MODE, false);
+ boolean darkTheme = mPreferenceManager.getUseTheme() != 0 || mIsIncognito;
+ mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
+ mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme);
+ mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) :
+ ThemeUtils.getIconLightThemeColor(context);
}
// Handle bookmark click
@@ -107,7 +123,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
mScrollIndex = mBookmarksListView.getFirstVisiblePosition();
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), true);
} else {
- mEventBus.post(new BookmarkEvents.Clicked(item));
+ mEventBus.post(new BrowserEvents.OpenUrlInCurrentTab(item.getUrl()));
}
}
};
@@ -135,6 +151,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
mBookmarksListView.setOnItemClickListener(mItemClickListener);
mBookmarksListView.setOnItemLongClickListener(mItemLongClickListener);
mBookmarkTitleImage = (ImageView) view.findViewById(R.id.starIcon);
+ mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
mBookmarkImage = (ImageView) view.findViewById(R.id.icon_star);
final View backView = view.findViewById(R.id.bookmark_back_button);
backView.setOnClickListener(new View.OnClickListener() {
@@ -154,20 +171,6 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
return view;
}
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- // TODO remove dependency on BrowserActivity
- super.onActivityCreated(savedInstanceState);
- final Activity activity = getActivity();
- final PreferenceManager preferenceManager = PreferenceManager.getInstance();
- boolean darkTheme = preferenceManager.getUseTheme() != 0 || ((BrowserActivity) 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);
- mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
- }
-
@Override
public void onStart() {
super.onStart();
@@ -229,8 +232,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
if (event.item.isFolder()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
} else {
- mBookmarkAdapter.notifyDataSetChanged();
- }
+ mBookmarkAdapter.notifyDataSetChanged();
+ }
}
private void setBookmarkDataSet(List items, boolean animate) {
@@ -295,7 +298,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
if (item.isFolder()) {
mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item);
} else {
- mBookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item);
+ mBookmarksDialogBuilder.showLongPressLinkDialog(getContext(), item.getUrl());
}
}
diff --git a/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
index 23180e9..a5ddaa1 100644
--- a/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
+++ b/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
@@ -8,7 +8,6 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
-import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -19,9 +18,8 @@ import android.widget.SeekBar;
import android.widget.TextView;
import acr.browser.lightning.R;
-import acr.browser.lightning.preference.PreferenceManager;
-public class DisplaySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
+public class DisplaySettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_HIDESTATUSBAR = "fullScreenOption";
private static final String SETTINGS_FULLSCREEN = "fullscreen";
@@ -38,7 +36,6 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
private static final float XSMALL = 10.0f;
private Activity mActivity;
- private PreferenceManager mPreferences;
private CheckBoxPreference cbstatus, cbfullscreen, cbviewport, cboverview, cbreflow;
private Preference theme;
private String[] mThemeOptions;
@@ -57,9 +54,8 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
private void initPrefs() {
// mPreferences storage
- mPreferences = PreferenceManager.getInstance();
mThemeOptions = this.getResources().getStringArray(R.array.themes);
- mCurrentTheme = mPreferences.getUseTheme();
+ mCurrentTheme = mPreferenceManager.getUseTheme();
theme = findPreference(SETTINGS_THEME);
Preference textsize = findPreference(SETTINGS_TEXTSIZE);
@@ -77,13 +73,13 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
cboverview.setOnPreferenceChangeListener(this);
cbreflow.setOnPreferenceChangeListener(this);
- cbstatus.setChecked(mPreferences.getHideStatusBarEnabled());
- cbfullscreen.setChecked(mPreferences.getFullScreenEnabled());
- cbviewport.setChecked(mPreferences.getUseWideViewportEnabled());
- cboverview.setChecked(mPreferences.getOverviewModeEnabled());
- cbreflow.setChecked(mPreferences.getTextReflowEnabled());
+ cbstatus.setChecked(mPreferenceManager.getHideStatusBarEnabled());
+ cbfullscreen.setChecked(mPreferenceManager.getFullScreenEnabled());
+ cbviewport.setChecked(mPreferenceManager.getUseWideViewportEnabled());
+ cboverview.setChecked(mPreferenceManager.getOverviewModeEnabled());
+ cbreflow.setChecked(mPreferenceManager.getTextReflowEnabled());
- theme.setSummary(mThemeOptions[mPreferences.getUseTheme()]);
+ theme.setSummary(mThemeOptions[mPreferenceManager.getUseTheme()]);
}
@Override
@@ -105,23 +101,23 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
// switch preferences
switch (preference.getKey()) {
case SETTINGS_HIDESTATUSBAR:
- mPreferences.setHideStatusBarEnabled((Boolean) newValue);
+ mPreferenceManager.setHideStatusBarEnabled((Boolean) newValue);
cbstatus.setChecked((Boolean) newValue);
return true;
case SETTINGS_FULLSCREEN:
- mPreferences.setFullScreenEnabled((Boolean) newValue);
+ mPreferenceManager.setFullScreenEnabled((Boolean) newValue);
cbfullscreen.setChecked((Boolean) newValue);
return true;
case SETTINGS_VIEWPORT:
- mPreferences.setUseWideViewportEnabled((Boolean) newValue);
+ mPreferenceManager.setUseWideViewportEnabled((Boolean) newValue);
cbviewport.setChecked((Boolean) newValue);
return true;
case SETTINGS_OVERVIEWMODE:
- mPreferences.setOverviewModeEnabled((Boolean) newValue);
+ mPreferenceManager.setOverviewModeEnabled((Boolean) newValue);
cboverview.setChecked((Boolean) newValue);
return true;
case SETTINGS_REFLOW:
- mPreferences.setTextReflowEnabled((Boolean) newValue);
+ mPreferenceManager.setTextReflowEnabled((Boolean) newValue);
cbreflow.setChecked((Boolean) newValue);
return true;
default:
@@ -142,14 +138,14 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
bar.setOnSeekBarChangeListener(new TextSeekBarListener(sample));
final int MAX = 5;
bar.setMax(MAX);
- bar.setProgress(MAX - mPreferences.getTextSize());
+ bar.setProgress(MAX - mPreferenceManager.getTextSize());
builder.setView(view);
builder.setTitle(R.string.title_text_size);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
- mPreferences.setTextSize(MAX - bar.getProgress());
+ mPreferenceManager.setTextSize(MAX - bar.getProgress());
}
});
@@ -179,12 +175,12 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.theme));
- int n = mPreferences.getUseTheme();
+ int n = mPreferenceManager.getUseTheme();
picker.setSingleChoiceItems(mThemeOptions, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setUseTheme(which);
+ mPreferenceManager.setUseTheme(which);
if (which < mThemeOptions.length) {
theme.setSummary(mThemeOptions[which]);
}
@@ -195,7 +191,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
- if (mCurrentTheme != mPreferences.getUseTheme()) {
+ if (mCurrentTheme != mPreferenceManager.getUseTheme()) {
getActivity().onBackPressed();
}
}
@@ -203,7 +199,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
picker.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
- if (mCurrentTheme != mPreferences.getUseTheme()) {
+ if (mCurrentTheme != mPreferenceManager.getUseTheme()) {
getActivity().onBackPressed();
}
}
diff --git a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
index aa7080f..37d53de 100644
--- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
+++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
@@ -9,7 +9,6 @@ import android.os.Bundle;
import android.os.Environment;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
-import android.preference.PreferenceFragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
@@ -28,7 +27,7 @@ import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
-public class GeneralSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
+public class GeneralSettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_PROXY = "proxy";
private static final String SETTINGS_FLASH = "cb_flash";
@@ -45,7 +44,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private Activity mActivity;
private static final int API = android.os.Build.VERSION.SDK_INT;
- private PreferenceManager mPreferences;
private CharSequence[] mProxyChoices;
private Preference proxy, useragent, downloadloc, home, searchengine;
private String mDownloadLocation;
@@ -65,9 +63,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
}
private void initPrefs() {
- // mPreferences storage
- mPreferences = PreferenceManager.getInstance();
-
proxy = findPreference(SETTINGS_PROXY);
useragent = findPreference(SETTINGS_USERAGENT);
downloadloc = findPreference(SETTINGS_DOWNLOAD);
@@ -95,23 +90,23 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
cbgooglesuggest.setOnPreferenceChangeListener(this);
cbDrawerTabs.setOnPreferenceChangeListener(this);
- mAgentChoice = mPreferences.getUserAgentChoice();
- mHomepage = mPreferences.getHomepage();
- mDownloadLocation = mPreferences.getDownloadDirectory();
+ mAgentChoice = mPreferenceManager.getUserAgentChoice();
+ mHomepage = mPreferenceManager.getHomepage();
+ mDownloadLocation = mPreferenceManager.getDownloadDirectory();
mProxyChoices = getResources().getStringArray(R.array.proxy_choices_array);
- int choice = mPreferences.getProxyChoice();
+ int choice = mPreferenceManager.getProxyChoice();
if (choice == Constants.PROXY_MANUAL) {
- proxy.setSummary(mPreferences.getProxyHost() + ':' + mPreferences.getProxyPort());
+ proxy.setSummary(mPreferenceManager.getProxyHost() + ':' + mPreferenceManager.getProxyPort());
} else {
proxy.setSummary(mProxyChoices[choice]);
}
if (API >= 19) {
- mPreferences.setFlashSupport(0);
+ mPreferenceManager.setFlashSupport(0);
}
- setSearchEngineSummary(mPreferences.getSearchChoice());
+ setSearchEngineSummary(mPreferenceManager.getSearchChoice());
downloadloc.setSummary(mDownloadLocation);
@@ -139,9 +134,9 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
useragent.setSummary(getResources().getString(R.string.agent_custom));
}
- int flashNum = mPreferences.getFlashSupport();
- boolean imagesBool = mPreferences.getBlockImagesEnabled();
- boolean enableJSBool = mPreferences.getJavaScriptEnabled();
+ int flashNum = mPreferenceManager.getFlashSupport();
+ boolean imagesBool = mPreferenceManager.getBlockImagesEnabled();
+ boolean enableJSBool = mPreferenceManager.getJavaScriptEnabled();
cbAds.setEnabled(Constants.FULL_VERSION);
cbFlash.setEnabled(API < 19);
@@ -149,17 +144,17 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
cbImages.setChecked(imagesBool);
cbJsScript.setChecked(enableJSBool);
cbFlash.setChecked(flashNum > 0);
- cbAds.setChecked(Constants.FULL_VERSION && mPreferences.getAdBlockEnabled());
- cbColorMode.setChecked(mPreferences.getColorModeEnabled());
- cbgooglesuggest.setChecked(mPreferences.getGoogleSearchSuggestionsEnabled());
- cbDrawerTabs.setChecked(mPreferences.getShowTabsInDrawer(true));
+ cbAds.setChecked(Constants.FULL_VERSION && mPreferenceManager.getAdBlockEnabled());
+ cbColorMode.setChecked(mPreferenceManager.getColorModeEnabled());
+ cbgooglesuggest.setChecked(mPreferenceManager.getGoogleSearchSuggestionsEnabled());
+ cbDrawerTabs.setChecked(mPreferenceManager.getShowTabsInDrawer(true));
}
private void searchUrlPicker() {
final AlertDialog.Builder urlPicker = new AlertDialog.Builder(mActivity);
urlPicker.setTitle(getResources().getString(R.string.custom_url));
final EditText getSearchUrl = new EditText(mActivity);
- String mSearchUrl = mPreferences.getSearchUrl();
+ String mSearchUrl = mPreferenceManager.getSearchUrl();
getSearchUrl.setText(mSearchUrl);
urlPicker.setView(getSearchUrl);
urlPicker.setPositiveButton(getResources().getString(R.string.action_ok),
@@ -167,7 +162,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getSearchUrl.getText().toString();
- mPreferences.setSearchUrl(text);
+ mPreferenceManager.setSearchUrl(text);
searchengine.setSummary(getResources().getString(R.string.custom_url) + ": "
+ text);
}
@@ -184,7 +179,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
- mPreferences.setFlashSupport(1);
+ mPreferenceManager.setFlashSupport(1);
}
})
.setNegativeButton(getResources().getString(R.string.action_auto),
@@ -192,13 +187,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setFlashSupport(2);
+ mPreferenceManager.setFlashSupport(2);
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
- mPreferences.setFlashSupport(0);
+ mPreferenceManager.setFlashSupport(0);
}
});
@@ -209,7 +204,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void proxyChoicePicker() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.http_proxy));
- picker.setSingleChoiceItems(mProxyChoices, mPreferences.getProxyChoice(),
+ picker.setSingleChoiceItems(mProxyChoices, mPreferenceManager.getProxyChoice(),
new DialogInterface.OnClickListener() {
@Override
@@ -234,7 +229,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
break;
}
- mPreferences.setProxyChoice(choice);
+ mPreferenceManager.setProxyChoice(choice);
if (choice < mProxyChoices.length)
proxy.setSummary(mProxyChoices[choice]);
}
@@ -252,8 +247,8 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
filterArray[0] = new InputFilter.LengthFilter(maxCharacters - 1);
eProxyPort.setFilters(filterArray);
- eProxyHost.setText(mPreferences.getProxyHost());
- eProxyPort.setText(Integer.toString(mPreferences.getProxyPort()));
+ eProxyHost.setText(mPreferenceManager.getProxyHost());
+ eProxyPort.setText(Integer.toString(mPreferenceManager.getProxyPort()));
new AlertDialog.Builder(mActivity)
.setTitle(R.string.manual_proxy)
@@ -268,10 +263,10 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
// larger than max integer
proxyPort = Integer.parseInt(eProxyPort.getText().toString());
} catch (NumberFormatException ignored) {
- proxyPort = mPreferences.getProxyPort();
+ proxyPort = mPreferenceManager.getProxyPort();
}
- mPreferences.setProxyHost(proxyHost);
- mPreferences.setProxyPort(proxyPort);
+ mPreferenceManager.setProxyHost(proxyHost);
+ mPreferenceManager.setProxyPort(proxyPort);
proxy.setSummary(proxyHost + ':' + proxyPort);
}
}).show();
@@ -285,13 +280,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
"DuckDuckGo (Privacy)", "DuckDuckGo Lite (Privacy)", "Baidu (Chinese)",
"Yandex (Russian)"};
- int n = mPreferences.getSearchChoice();
+ int n = mPreferenceManager.getSearchChoice();
picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setSearchChoice(which);
+ mPreferenceManager.setSearchChoice(which);
setSearchEngineSummary(which);
}
});
@@ -302,7 +297,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void homepageDialog() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.home));
- mHomepage = mPreferences.getHomepage();
+ mHomepage = mPreferenceManager.getHomepage();
int n;
if (mHomepage.contains("about:home")) {
n = 1;
@@ -320,15 +315,15 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
switch (which + 1) {
case 1:
- mPreferences.setHomepage("about:home");
+ mPreferenceManager.setHomepage("about:home");
home.setSummary(getResources().getString(R.string.action_homepage));
break;
case 2:
- mPreferences.setHomepage("about:blank");
+ mPreferenceManager.setHomepage("about:blank");
home.setSummary(getResources().getString(R.string.action_blank));
break;
case 3:
- mPreferences.setHomepage("about:bookmarks");
+ mPreferenceManager.setHomepage("about:bookmarks");
home.setSummary(getResources().getString(R.string.action_bookmarks));
break;
case 4:
@@ -345,7 +340,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
final AlertDialog.Builder homePicker = new AlertDialog.Builder(mActivity);
homePicker.setTitle(getResources().getString(R.string.title_custom_homepage));
final EditText getHome = new EditText(mActivity);
- mHomepage = mPreferences.getHomepage();
+ mHomepage = mPreferenceManager.getHomepage();
if (!mHomepage.startsWith("about:")) {
getHome.setText(mHomepage);
} else {
@@ -357,7 +352,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getHome.getText().toString();
- mPreferences.setHomepage(text);
+ mPreferenceManager.setHomepage(text);
home.setSummary(text);
}
});
@@ -367,7 +362,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void downloadLocDialog() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.title_download_location));
- mDownloadLocation = mPreferences.getDownloadDirectory();
+ mDownloadLocation = mPreferenceManager.getDownloadDirectory();
int n;
if (mDownloadLocation.contains(Environment.DIRECTORY_DOWNLOADS)) {
n = 0;
@@ -381,7 +376,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
- mPreferences.setDownloadDirectory(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
+ mPreferenceManager.setDownloadDirectory(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
downloadloc.setSummary(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
break;
case 1:
@@ -397,12 +392,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void agentDialog() {
AlertDialog.Builder agentPicker = new AlertDialog.Builder(mActivity);
agentPicker.setTitle(getResources().getString(R.string.title_user_agent));
- mAgentChoice = mPreferences.getUserAgentChoice();
+ mAgentChoice = mPreferenceManager.getUserAgentChoice();
agentPicker.setSingleChoiceItems(R.array.user_agent, mAgentChoice - 1,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- mPreferences.setUserAgentChoice(which + 1);
+ mPreferenceManager.setUserAgentChoice(which + 1);
switch (which + 1) {
case 1:
useragent.setSummary(getResources().getString(R.string.agent_default));
@@ -434,7 +429,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getAgent.getText().toString();
- mPreferences.setUserAgentString(text);
+ mPreferenceManager.setUserAgentString(text);
useragent.setSummary(getResources().getString(R.string.agent_custom));
}
});
@@ -448,12 +443,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
final EditText getDownload = new EditText(mActivity);
getDownload.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
- getDownload.setText(PreferenceManager.getInstance().getDownloadDirectory());
+ getDownload.setText(mPreferenceManager.getDownloadDirectory());
final int errorColor = ContextCompat.getColor(getActivity(), R.color.error_red);
final int regularColor = ThemeUtils.getTextColor(getActivity());
getDownload.setTextColor(regularColor);
getDownload.addTextChangedListener(new DownloadLocationTextWatcher(getDownload, errorColor, regularColor));
- getDownload.setText(mPreferences.getDownloadDirectory());
+ getDownload.setText(mPreferenceManager.getDownloadDirectory());
layout.addView(getDownload);
downLocationPicker.setView(layout);
@@ -463,7 +458,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
String text = getDownload.getText().toString();
text = DownloadHandler.addNecessarySlashes(text);
- mPreferences.setDownloadDirectory(text);
+ mPreferenceManager.setDownloadDirectory(text);
downloadloc.setSummary(text);
}
});
@@ -538,37 +533,37 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
if (cbFlash.isChecked()) {
getFlashChoice();
} else {
- mPreferences.setFlashSupport(0);
+ mPreferenceManager.setFlashSupport(0);
}
if (!Utils.isFlashInstalled(mActivity) && cbFlash.isChecked()) {
Utils.createInformativeDialog(mActivity, R.string.title_warning, R.string.dialog_adobe_not_installed);
cbFlash.setEnabled(false);
- mPreferences.setFlashSupport(0);
+ mPreferenceManager.setFlashSupport(0);
}
cbFlash.setChecked((Boolean) newValue);
return true;
case SETTINGS_ADS:
- mPreferences.setAdBlockEnabled((Boolean) newValue);
+ mPreferenceManager.setAdBlockEnabled((Boolean) newValue);
cbAds.setChecked((Boolean) newValue);
return true;
case SETTINGS_IMAGES:
- mPreferences.setBlockImagesEnabled((Boolean) newValue);
+ mPreferenceManager.setBlockImagesEnabled((Boolean) newValue);
cbImages.setChecked((Boolean) newValue);
return true;
case SETTINGS_JAVASCRIPT:
- mPreferences.setJavaScriptEnabled((Boolean) newValue);
+ mPreferenceManager.setJavaScriptEnabled((Boolean) newValue);
cbJsScript.setChecked((Boolean) newValue);
return true;
case SETTINGS_COLORMODE:
- mPreferences.setColorModeEnabled((Boolean) newValue);
+ mPreferenceManager.setColorModeEnabled((Boolean) newValue);
cbColorMode.setChecked((Boolean) newValue);
return true;
case SETTINGS_GOOGLESUGGESTIONS:
- mPreferences.setGoogleSearchSuggestionsEnabled((Boolean) newValue);
+ mPreferenceManager.setGoogleSearchSuggestionsEnabled((Boolean) newValue);
cbgooglesuggest.setChecked((Boolean) newValue);
return true;
case SETTINGS_DRAWERTABS:
- mPreferences.setShowTabsInDrawer((Boolean) newValue);
+ mPreferenceManager.setShowTabsInDrawer((Boolean) newValue);
cbDrawerTabs.setChecked((Boolean) newValue);
default:
return false;
diff --git a/app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java b/app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java
new file mode 100644
index 0000000..ab7c48d
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java
@@ -0,0 +1,27 @@
+package acr.browser.lightning.fragment;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+import javax.inject.Inject;
+
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.preference.PreferenceManager;
+
+/**
+ * Simplify {@link PreferenceManager} inject in all the PreferenceFragments
+ *
+ * @author Stefano Pacifici
+ * @date 2015/09/16
+ */
+public class LightningPreferenceFragment extends PreferenceFragment {
+
+ @Inject
+ PreferenceManager mPreferenceManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ BrowserApp.getAppComponent().inject(this);
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
index 9fc225c..2ea48aa 100644
--- a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
+++ b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
@@ -11,16 +11,14 @@ import android.os.Handler;
import android.os.Message;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
-import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
import acr.browser.lightning.R;
-import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.utils.WebUtils;
-public class PrivacySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
+public class PrivacySettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_LOCATION = "location";
private static final String SETTINGS_THIRDPCOOKIES = "third_party";
@@ -35,7 +33,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
private static final String SETTINGS_WEBSTORAGEEXIT = "clear_webstorage_exit";
private Activity mActivity;
- private PreferenceManager mPreferences;
private CheckBoxPreference cblocation, cb3cookies, cbsavepasswords, cbcacheexit, cbhistoryexit,
cbcookiesexit, cbwebstorageexit;
private Handler messageHandler;
@@ -52,9 +49,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
}
private void initPrefs() {
- // mPreferences storage
- mPreferences = PreferenceManager.getInstance();
-
Preference clearcache = findPreference(SETTINGS_CLEARCACHE);
Preference clearhistory = findPreference(SETTINGS_CLEARHISTORY);
Preference clearcookies = findPreference(SETTINGS_CLEARCOOKIES);
@@ -81,13 +75,13 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
cbcookiesexit.setOnPreferenceChangeListener(this);
cbwebstorageexit.setOnPreferenceChangeListener(this);
- cblocation.setChecked(mPreferences.getLocationEnabled());
- cbsavepasswords.setChecked(mPreferences.getSavePasswordsEnabled());
- cbcacheexit.setChecked(mPreferences.getClearCacheExit());
- cbhistoryexit.setChecked(mPreferences.getClearHistoryExitEnabled());
- cbcookiesexit.setChecked(mPreferences.getClearCookiesExitEnabled());
- cb3cookies.setChecked(mPreferences.getBlockThirdPartyCookiesEnabled());
- cbwebstorageexit.setChecked(mPreferences.getClearWebStorageExitEnabled());
+ cblocation.setChecked(mPreferenceManager.getLocationEnabled());
+ cbsavepasswords.setChecked(mPreferenceManager.getSavePasswordsEnabled());
+ cbcacheexit.setChecked(mPreferenceManager.getClearCacheExit());
+ cbhistoryexit.setChecked(mPreferenceManager.getClearHistoryExitEnabled());
+ cbcookiesexit.setChecked(mPreferenceManager.getClearCookiesExitEnabled());
+ cb3cookies.setChecked(mPreferenceManager.getBlockThirdPartyCookiesEnabled());
+ cbwebstorageexit.setChecked(mPreferenceManager.getClearWebStorageExitEnabled());
cb3cookies.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
@@ -203,31 +197,31 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
// switch preferences
switch (preference.getKey()) {
case SETTINGS_LOCATION:
- mPreferences.setLocationEnabled((Boolean) newValue);
+ mPreferenceManager.setLocationEnabled((Boolean) newValue);
cblocation.setChecked((Boolean) newValue);
return true;
case SETTINGS_THIRDPCOOKIES:
- mPreferences.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
+ mPreferenceManager.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
cb3cookies.setChecked((Boolean) newValue);
return true;
case SETTINGS_SAVEPASSWORD:
- mPreferences.setSavePasswordsEnabled((Boolean) newValue);
+ mPreferenceManager.setSavePasswordsEnabled((Boolean) newValue);
cbsavepasswords.setChecked((Boolean) newValue);
return true;
case SETTINGS_CACHEEXIT:
- mPreferences.setClearCacheExit((Boolean) newValue);
+ mPreferenceManager.setClearCacheExit((Boolean) newValue);
cbcacheexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_HISTORYEXIT:
- mPreferences.setClearHistoryExitEnabled((Boolean) newValue);
+ mPreferenceManager.setClearHistoryExitEnabled((Boolean) newValue);
cbhistoryexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_COOKIEEXIT:
- mPreferences.setClearCookiesExitEnabled((Boolean) newValue);
+ mPreferenceManager.setClearCookiesExitEnabled((Boolean) newValue);
cbcookiesexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_WEBSTORAGEEXIT:
- mPreferences.setClearWebStorageExitEnabled((Boolean) newValue);
+ mPreferenceManager.setClearWebStorageExitEnabled((Boolean) newValue);
cbwebstorageexit.setChecked((Boolean) newValue);
return true;
default:
diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java
new file mode 100644
index 0000000..a0945ad
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java
@@ -0,0 +1,417 @@
+package acr.browser.lightning.fragment;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+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.support.v7.graphics.Palette;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.LayoutManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.squareup.otto.Bus;
+import com.squareup.otto.Subscribe;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import acr.browser.lightning.R;
+import acr.browser.lightning.activity.TabsManager;
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
+import acr.browser.lightning.bus.NavigationEvents;
+import acr.browser.lightning.bus.TabEvents;
+import acr.browser.lightning.preference.PreferenceManager;
+import acr.browser.lightning.utils.ThemeUtils;
+import acr.browser.lightning.utils.Utils;
+import acr.browser.lightning.view.LightningView;
+
+/**
+ * @author Stefano Pacifici based on Anthony C. Restaino's code
+ * @date 2015/09/14
+ */
+public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
+
+ private static final String TAG = TabsFragment.class.getSimpleName();
+
+ /**
+ * Arguments boolean to tell the fragment it is displayed in the drawner or on the tab strip
+ * If true, the fragment is in the left drawner in the strip otherwise.
+ */
+ public static final String VERTICAL_MODE = TAG + ".VERTICAL_MODE";
+ public static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO";
+
+ private boolean mIsIncognito, mDarkTheme;
+ private int mIconColor;
+ private boolean mColorMode = true;
+ private boolean mShowInNavigationDrawer;
+ private int mCurrentUiColor = Color.BLACK; // TODO Only temporary
+
+ private RecyclerView mRecyclerView;
+ private LightningViewAdapter mTabsAdapter;
+
+ @Inject
+ TabsManager tabsManager;
+
+ @Inject
+ Bus bus;
+
+ @Inject
+ PreferenceManager mPreferences;
+
+ public TabsFragment() {
+ BrowserApp.getAppComponent().inject(this);
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final Bundle arguments = getArguments();
+ final Context context = getContext();
+ mIsIncognito = arguments.getBoolean(IS_INCOGNITO, false);
+ mShowInNavigationDrawer = arguments.getBoolean(VERTICAL_MODE, true);
+ mDarkTheme = mPreferences.getUseTheme() != 0 || mIsIncognito;
+ mColorMode = mPreferences.getColorModeEnabled();
+ mColorMode &= !mDarkTheme;
+ mIconColor = mDarkTheme ?
+ ThemeUtils.getIconDarkThemeColor(context) :
+ ThemeUtils.getIconLightThemeColor(context);
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ final Bundle arguments = getArguments();
+ final View view;
+ final LayoutManager layoutManager;
+ if (mShowInNavigationDrawer) {
+ view = inflater.inflate(R.layout.tab_drawer, container, false);
+ layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
+ setupFrameLayoutButton(view, R.id.new_tab_button, R.id.icon_plus);
+ setupFrameLayoutButton(view, R.id.action_back, R.id.icon_back);
+ setupFrameLayoutButton(view, R.id.action_forward, R.id.icon_forward);
+ setupFrameLayoutButton(view, R.id.action_home, R.id.icon_home);
+ } else {
+ view = inflater.inflate(R.layout.tab_strip, container, false);
+ layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
+ }
+ mRecyclerView = (RecyclerView) view.findViewById(R.id.tabs_list);
+ mRecyclerView.setLayoutManager(layoutManager);
+ mTabsAdapter = new LightningViewAdapter(mShowInNavigationDrawer);
+ mRecyclerView.setAdapter(mTabsAdapter);
+ mRecyclerView.setHasFixedSize(true);
+ return view;
+ }
+
+ private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int buttonId,
+ @IdRes final int imageId) {
+ final View frameButton = root.findViewById(buttonId);
+ final ImageView buttonImage = (ImageView) root.findViewById(imageId);
+ frameButton.setOnClickListener(this);
+ frameButton.setOnLongClickListener(this);
+ buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ mRecyclerView = null;
+ mTabsAdapter = null;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ bus.register(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ // Force adapter refresh
+ mTabsAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ bus.unregister(this);
+ }
+
+ @Subscribe
+ public void tabsChanged(final BrowserEvents.TabsChanged event) {
+ if (mTabsAdapter != null) {
+ mTabsAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.new_tab_button:
+ bus.post(new TabEvents.NewTab());
+ break;
+ case R.id.action_back:
+ bus.post(new NavigationEvents.GoBack());
+ break;
+ case R.id.action_forward:
+ bus.post(new NavigationEvents.GoForward());
+ break;
+ case R.id.action_home:
+ bus.post(new NavigationEvents.GoHome());
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ switch (v.getId()) {
+ case R.id.action_new_tab:
+ bus.post(new TabEvents.NewTabLongPress());
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ public class LightningViewAdapter extends RecyclerView.Adapter {
+
+ private final int layoutResourceId;
+ private final Drawable mBackgroundTabDrawable;
+ private final Drawable mForegroundTabDrawable;
+ private final Bitmap mForegroundTabBitmap;
+ private ColorMatrix mColorMatrix;
+ private Paint mPaint;
+ private ColorFilter mFilter;
+ private static final float DESATURATED = 0.5f;
+
+ private final boolean vertical;
+
+ public LightningViewAdapter(final boolean vertical) {
+ this.layoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal;
+ this.vertical = vertical;
+
+ if (vertical) {
+ mBackgroundTabDrawable = null;
+ mForegroundTabBitmap = null;
+ mForegroundTabDrawable = ThemeUtils.getSelectedBackground(getContext(), mDarkTheme);
+ } else {
+ int backgroundColor = Utils.mixTwoColors(ThemeUtils.getPrimaryColor(getContext()), Color.BLACK, 0.75f);
+ Bitmap backgroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
+ Utils.drawTrapezoid(new Canvas(backgroundTabBitmap), backgroundColor, true);
+ mBackgroundTabDrawable = new BitmapDrawable(getResources(), backgroundTabBitmap);
+
+ int foregroundColor = ThemeUtils.getPrimaryColor(getContext());
+ mForegroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
+ Utils.drawTrapezoid(new Canvas(mForegroundTabBitmap), foregroundColor, false);
+ mForegroundTabDrawable = null;
+ }
+ }
+
+ @Override
+ public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
+ LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
+ View view = inflater.inflate(layoutResourceId, viewGroup, false);
+ return new LightningViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(final LightningViewHolder holder, int position) {
+ holder.exitButton.setTag(position);
+
+ ViewCompat.jumpDrawablesToCurrentState(holder.exitButton);
+
+ LightningView web = tabsManager.getTabAtPosition(position);
+ holder.txtTitle.setText(web.getTitle());
+
+ final Bitmap favicon = web.getFavicon();
+ if (web.isForegroundTab()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ holder.txtTitle.setTextAppearance(R.style.boldText);
+ } else {
+ holder.txtTitle.setTextAppearance(getContext(), R.style.boldText);
+ }
+ Drawable foregroundDrawable;
+ if (!vertical) {
+ foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap);
+ if (!mIsIncognito && mColorMode) {
+ foregroundDrawable.setColorFilter(mCurrentUiColor, PorterDuff.Mode.SRC_IN);
+ }
+ } else {
+ foregroundDrawable = mForegroundTabDrawable;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ holder.layout.setBackground(foregroundDrawable);
+ } else {
+ holder.layout.setBackgroundDrawable(foregroundDrawable);
+ }
+ if (!mIsIncognito && mColorMode) {
+ changeToolbarBackground(favicon, foregroundDrawable);
+ }
+ holder.favicon.setImageBitmap(favicon);
+ } else {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ holder.txtTitle.setTextAppearance(R.style.normalText);
+ } else {
+ holder.txtTitle.setTextAppearance(getContext(), R.style.normalText);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ holder.layout.setBackground(mBackgroundTabDrawable);
+ } else {
+ holder.layout.setBackgroundDrawable(mBackgroundTabDrawable);
+ }
+ holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon));
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return tabsManager.size();
+ }
+
+ public Bitmap getDesaturatedBitmap(Bitmap favicon) {
+ Bitmap grayscaleBitmap = Bitmap.createBitmap(favicon.getWidth(),
+ favicon.getHeight(), Bitmap.Config.ARGB_8888);
+
+ Canvas c = new Canvas(grayscaleBitmap);
+ if (mColorMatrix == null || mFilter == null || mPaint == null) {
+ mPaint = new Paint();
+ mColorMatrix = new ColorMatrix();
+ mColorMatrix.setSaturation(DESATURATED);
+ mFilter = new ColorMatrixColorFilter(mColorMatrix);
+ mPaint.setColorFilter(mFilter);
+ }
+
+ c.drawBitmap(favicon, 0, 0, mPaint);
+ return grayscaleBitmap;
+ }
+
+ /**
+ * 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.
+ *
+ * @param favicon the Bitmap to extract the color from
+ * @param tabBackground the optional LinearLayout to color
+ */
+ private void changeToolbarBackground(@NonNull Bitmap favicon, @Nullable final Drawable tabBackground) {
+ if (mShowInNavigationDrawer) {
+ return;
+ }
+
+ final int defaultColor;
+ final Resources resources = getResources();
+ final ColorDrawable mBackground = new ColorDrawable();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ defaultColor = resources.getColor(R.color.primary_color, null);
+ } else {
+ defaultColor = resources.getColor(R.color.primary_color);
+ }
+ if (mCurrentUiColor == Color.BLACK) {
+ mCurrentUiColor = defaultColor;
+ }
+ Palette.from(favicon).generate(new Palette.PaletteAsyncListener() {
+ @Override
+ public void onGenerated(Palette palette) {
+
+ // OR with opaque black to remove transparency glitches
+ int color = 0xff000000 | palette.getVibrantColor(defaultColor);
+
+ int finalColor = Utils.mixTwoColors(defaultColor, color, 0.25f);
+
+ ValueAnimator anim = ValueAnimator.ofInt(mCurrentUiColor, finalColor);
+ anim.setEvaluator(new ArgbEvaluator());
+ // final Window window = getWindow();
+ // TODO Check this
+ // if (!mShowInNavigationDrawer) {
+ // window.setBackgroundDrawable(new ColorDrawable(Color.BLACK));
+ // }
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final int color = (Integer) animation.getAnimatedValue();
+ if (tabBackground != null) {
+ tabBackground.setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ mCurrentUiColor = color;
+ }
+
+ });
+ anim.setDuration(300);
+ anim.start();
+ }
+ });
+ }
+
+ public class LightningViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
+
+ public LightningViewHolder(View view) {
+ super(view);
+ txtTitle = (TextView) view.findViewById(R.id.textTab);
+ favicon = (ImageView) view.findViewById(R.id.faviconTab);
+ exit = (ImageView) view.findViewById(R.id.deleteButton);
+ layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
+ exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
+ exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
+
+ exitButton.setOnClickListener(this);
+ layout.setOnClickListener(this);
+ layout.setOnLongClickListener(this);
+ }
+
+ final TextView txtTitle;
+ final ImageView favicon;
+ final ImageView exit;
+ final FrameLayout exitButton;
+ final LinearLayout layout;
+
+ @Override
+ public void onClick(View v) {
+ if (v == exitButton) {
+ // Close tab
+ bus.post(new TabEvents.CloseTab(getAdapterPosition()));
+ }
+ if (v == layout) {
+ bus.post(new TabEvents.ShowTab(getAdapterPosition()));
+ }
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ // Show close dialog
+ bus.post(new TabEvents.ShowCloseDialog(getAdapterPosition()));
+ return true;
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/object/ClickHandler.java b/app/src/main/java/acr/browser/lightning/object/ClickHandler.java
deleted file mode 100644
index 841c03f..0000000
--- a/app/src/main/java/acr/browser/lightning/object/ClickHandler.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2014 A.C.R. Development
- */
-package acr.browser.lightning.object;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Message;
-
-import acr.browser.lightning.controller.BrowserController;
-
-public class ClickHandler extends Handler {
-
- private BrowserController mBrowserController;
-
- public ClickHandler(Context context) {
- try {
- mBrowserController = (BrowserController) context;
- } catch (ClassCastException e) {
- throw new ClassCastException(context + " must implement BrowserController");
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- String url = msg.getData().getString("url");
- mBrowserController.longClickPage(url);
- }
-}
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 6db5ef1..5789f9e 100644
--- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java
+++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java
@@ -56,14 +56,11 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
private final List mFilteredList = new ArrayList<>(5);
private final List mAllBookmarks = new ArrayList<>(5);
private final Object mLock = new Object();
- private HistoryDatabase mDatabaseHandler;
private final Context mContext;
private boolean mUseGoogle = true;
private boolean mIsExecuting = false;
private final boolean mDarkTheme;
private final boolean mIncognito;
- @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;
@@ -75,11 +72,19 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
private final Drawable mHistoryDrawable;
private final Drawable mBookmarkDrawable;
+ @Inject
+ HistoryDatabase mDatabaseHandler;
+
+ @Inject
+ BookmarkManager mBookmarkManager;
+
+ @Inject
+ PreferenceManager mPreferenceManager;
+
public SearchAdapter(Context context, boolean dark, boolean incognito) {
BrowserApp.getAppComponent().inject(this);
- mDatabaseHandler = HistoryDatabase.getInstance();
mAllBookmarks.addAll(mBookmarkManager.getAllBookmarks(true));
- mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
+ mUseGoogle = mPreferenceManager.getGoogleSearchSuggestionsEnabled();
mContext = context;
mSearchSubtitle = mContext.getString(R.string.suggestion);
mDarkTheme = dark || incognito;
@@ -114,13 +119,12 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
}
public void refreshPreferences() {
- mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
+ mUseGoogle = mPreferenceManager.getGoogleSearchSuggestionsEnabled();
if (!mUseGoogle) {
synchronized (mSuggestions) {
mSuggestions.clear();
}
}
- mDatabaseHandler = HistoryDatabase.getInstance();
}
public void refreshBookmarks() {
@@ -244,13 +248,10 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
mBookmarks.add(mAllBookmarks.get(n));
counter++;
}
-
}
}
}
- if (mDatabaseHandler == null || mDatabaseHandler.isClosed()) {
- mDatabaseHandler = HistoryDatabase.getInstance();
- }
+
List historyList = mDatabaseHandler.findItemsContaining(constraint.toString());
synchronized (mHistory) {
mHistory.clear();
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 0fda30e..f087ea5 100644
--- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
+++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
@@ -1,11 +1,16 @@
package acr.browser.lightning.preference;
+import android.content.Context;
import android.content.SharedPreferences;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
+@Singleton
public class PreferenceManager {
private static class Name {
@@ -56,20 +61,13 @@ public class PreferenceManager {
public static final String INITIAL_CHECK_FOR_I2P = "checkForI2P";
}
- private static PreferenceManager mInstance;
private final SharedPreferences mPrefs;
private static final String PREFERENCES = "settings";
- public static PreferenceManager getInstance() {
- if (mInstance == null) {
- mInstance = new PreferenceManager();
- }
- return mInstance;
- }
-
- private PreferenceManager() {
- mPrefs = BrowserApp.getAppContext().getSharedPreferences(PREFERENCES, 0);
+ @Inject
+ PreferenceManager(final Context context) {
+ mPrefs = context.getSharedPreferences(PREFERENCES, 0);
}
public boolean getAdBlockEnabled() {
diff --git a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java
index 706596f..c434c33 100644
--- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java
+++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java
@@ -13,6 +13,7 @@ import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
+import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
@@ -44,11 +45,11 @@ public class AdBlock {
if (mBlockedDomainsList.isEmpty() && Constants.FULL_VERSION) {
loadHostsFile(context);
}
- mBlockAds = PreferenceManager.getInstance().getAdBlockEnabled();
+ mBlockAds = BrowserApp.getAppComponent().getPreferenceManager().getAdBlockEnabled();
}
public void updatePreference() {
- mBlockAds = PreferenceManager.getInstance().getAdBlockEnabled();
+ mBlockAds = BrowserApp.getAppComponent().getPreferenceManager().getAdBlockEnabled();
}
private void loadBlockedDomainsList(final Context context) {
diff --git a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
index 21e6791..dcb9d6b 100644
--- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
+++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
@@ -2,6 +2,7 @@ package acr.browser.lightning.utils;
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
diff --git a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java
index a5e5fd8..f05f2ae 100644
--- a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java
+++ b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java
@@ -10,6 +10,7 @@ import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
+import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.database.HistoryDatabase;
/**
@@ -34,7 +35,7 @@ public class WebUtils {
}
public static void clearHistory(@NonNull Context context) {
- HistoryDatabase.getInstance().deleteHistory();
+ BrowserApp.getAppComponent().getHistoryDatabase().deleteHistory();
WebViewDatabase m = WebViewDatabase.getInstance(context);
m.clearFormData();
m.clearHttpAuthUsernamePassword();
diff --git a/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java b/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java
new file mode 100644
index 0000000..c4845d2
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/view/IconCacheTask.java
@@ -0,0 +1,44 @@
+package acr.browser.lightning.view;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.constant.Constants;
+import acr.browser.lightning.utils.Utils;
+
+/**
+ * @author Anthony C. Restaino
+ * @date 2015/09/29
+ */
+class IconCacheTask implements Runnable{
+ private final Uri uri;
+ private final Bitmap icon;
+
+ public IconCacheTask(Uri uri, Bitmap icon) {
+ this.uri = uri;
+ this.icon = icon;
+ }
+
+ @Override
+ public void run() {
+ String hash = String.valueOf(uri.getHost().hashCode());
+ Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
+ FileOutputStream fos = null;
+ try {
+ File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
+ fos = new FileOutputStream(image);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ Utils.close(fos);
+ }
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java
new file mode 100644
index 0000000..7167582
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java
@@ -0,0 +1,250 @@
+package acr.browser.lightning.view;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Message;
+import android.support.v7.app.AlertDialog;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.webkit.GeolocationPermissions;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+
+import com.squareup.otto.Bus;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import acr.browser.lightning.R;
+import acr.browser.lightning.activity.BrowserActivity;
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
+import acr.browser.lightning.constant.Constants;
+import acr.browser.lightning.utils.PermissionsManager;
+import acr.browser.lightning.utils.Utils;
+
+/**
+ * @author Stefano Pacifici based on Anthony C. Restaino code
+ * @date 2015/09/21
+ */
+class LightningChromeClient extends WebChromeClient {
+
+ private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
+
+ private final BrowserActivity mActivity;
+ private final LightningView mLightningView;
+ private final Bus eventBus;
+
+ LightningChromeClient(BrowserActivity activity, LightningView lightningView) {
+ mActivity = activity;
+ mLightningView = lightningView;
+ eventBus = BrowserApp.getAppComponent().getBus();
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (mLightningView.isShown()) {
+ mActivity.updateProgress(newProgress);
+ }
+ }
+
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ if (icon == null)
+ return;
+ mLightningView.mTitle.setFavicon(icon);
+ eventBus.post(new BrowserEvents.TabsChanged()); ;
+ cacheFavicon(view.getUrl(), icon);
+ }
+
+ /**
+ * Naive caching of the favicon according to the domain name of the URL
+ * @param icon the icon to cache
+ */
+ private void cacheFavicon(final String url, final Bitmap icon) {
+ if (icon == null) return;
+ final Uri uri = Uri.parse(url);
+ if (uri.getHost() == null) {
+ return;
+ }
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ String hash = String.valueOf(uri.getHost().hashCode());
+ Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
+ FileOutputStream fos = null;
+ try {
+ File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
+ fos = new FileOutputStream(image);
+ icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
+ fos.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ Utils.close(fos);
+ }
+ }
+ }).start();
+ }
+
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ if (title != null && !title.isEmpty()) {
+ mLightningView.mTitle.setTitle(title);
+ } else {
+ mLightningView.mTitle.setTitle(mActivity.getString(R.string.untitled));
+ }
+ eventBus.post(new BrowserEvents.TabsChanged());
+ if (view != null) {
+ mActivity.updateHistory(title, view.getUrl());
+ }
+ }
+
+ @Override
+ public void onGeolocationPermissionsShowPrompt(final String origin,
+ final GeolocationPermissions.Callback callback) {
+ PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS);
+ final boolean remember = true;
+ AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
+ builder.setTitle(mActivity.getString(R.string.location));
+ String org;
+ if (origin.length() > 50) {
+ org = origin.subSequence(0, 50) + "...";
+ } else {
+ org = origin;
+ }
+ builder.setMessage(org + mActivity.getString(R.string.message_location))
+ .setCancelable(true)
+ .setPositiveButton(mActivity.getString(R.string.action_allow),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ callback.invoke(origin, true, remember);
+ }
+ })
+ .setNegativeButton(mActivity.getString(R.string.action_dont_allow),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ callback.invoke(origin, false, remember);
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+
+ }
+
+ @Override
+ public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
+ Message resultMsg) {
+ mActivity.onCreateWindow(resultMsg);
+ return true;
+ }
+
+ @Override
+ public void onCloseWindow(WebView window) {
+ mActivity.onCloseWindow(mLightningView);
+ }
+
+ public void openFileChooser(ValueCallback uploadMsg) {
+ mActivity.openFileChooser(uploadMsg);
+ }
+
+ public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
+ mActivity.openFileChooser(uploadMsg);
+ }
+
+ public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
+ mActivity.openFileChooser(uploadMsg);
+ }
+
+ public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback,
+ WebChromeClient.FileChooserParams fileChooserParams) {
+ mActivity.showFileChooser(filePathCallback);
+ return true;
+ }
+
+ /**
+ * Obtain an image that is displayed as a placeholder on a video until the video has initialized
+ * and can begin loading.
+ *
+ * @return a Bitmap that can be used as a place holder for videos.
+ */
+ @Override
+ public Bitmap getDefaultVideoPoster() {
+ final Resources resources = mActivity.getResources();
+ return BitmapFactory.decodeResource(resources, android.R.drawable.spinner_background);
+ }
+
+ /**
+ * Inflate a view to send to a LightningView when it needs to display a video and has to
+ * show a loading dialog. Inflates a progress view and returns it.
+ *
+ * @return A view that should be used to display the state
+ * of a video's loading progress.
+ */
+ @Override
+ public View getVideoLoadingProgressView() {
+ LayoutInflater inflater = LayoutInflater.from(mActivity);
+ return inflater.inflate(R.layout.video_loading_progress, null);
+ }
+
+ @Override
+ public void onHideCustomView() {
+ mActivity.onHideCustomView();
+ super.onHideCustomView();
+ }
+
+ @Override
+ public void onShowCustomView(View view, CustomViewCallback callback) {
+ // While these lines might look like they work, in practice,
+ // Full-screen videos won't work correctly. I may test this out some
+ // more
+ // if (view instanceof FrameLayout) {
+ // FrameLayout frame = (FrameLayout) view;
+ // if (frame.getFocusedChild() instanceof VideoView) {
+ // VideoView video = (VideoView) frame.getFocusedChild();
+ // video.stopPlayback();
+ // frame.removeView(video);
+ // video.setVisibility(View.GONE);
+ // }
+ // } else {
+ mActivity.onShowCustomView(view, callback);
+
+ // }
+
+ super.onShowCustomView(view, callback);
+ }
+
+ @Override
+ @Deprecated
+ public void onShowCustomView(View view, int requestedOrientation,
+ CustomViewCallback callback) {
+ // While these lines might look like they work, in practice,
+ // Full-screen videos won't work correctly. I may test this out some
+ // more
+ // if (view instanceof FrameLayout) {
+ // FrameLayout frame = (FrameLayout) view;
+ // if (frame.getFocusedChild() instanceof VideoView) {
+ // VideoView video = (VideoView) frame.getFocusedChild();
+ // video.stopPlayback();
+ // frame.removeView(video);
+ // video.setVisibility(View.GONE);
+ // }
+ // } else {
+ mActivity.onShowCustomView(view, callback);
+
+ // }
+
+ super.onShowCustomView(view, requestedOrientation, callback);
+ }
+}
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 a14f65d..964e897 100644
--- a/app/src/main/java/acr/browser/lightning/view/LightningView.java
+++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java
@@ -6,26 +6,18 @@ package acr.browser.lightning.view;
import android.Manifest;
import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
-import android.net.MailTo;
import android.net.Uri;
-import android.net.http.SslError;
import android.os.Build;
+import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.text.InputType;
-import android.text.method.PasswordTransformationMethod;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
@@ -34,60 +26,48 @@ import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.webkit.CookieManager;
-import android.webkit.GeolocationPermissions;
-import android.webkit.HttpAuthHandler;
-import android.webkit.SslErrorHandler;
-import android.webkit.ValueCallback;
-import android.webkit.WebChromeClient;
-import android.webkit.WebResourceRequest;
-import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import java.io.ByteArrayInputStream;
+import com.squareup.otto.Bus;
+
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.net.URISyntaxException;
+
+import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import acr.browser.lightning.R;
+import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
+import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.constant.StartPage;
-import acr.browser.lightning.controller.BrowserController;
+import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.download.LightningDownloadListener;
import acr.browser.lightning.preference.PreferenceManager;
-import acr.browser.lightning.utils.AdBlock;
-import acr.browser.lightning.utils.IntentUtils;
import acr.browser.lightning.utils.PermissionsManager;
+import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
public class LightningView {
- private final Title mTitle;
+ final LightningViewTitle mTitle;
private WebView mWebView;
- private final boolean mIsIncognitoTab;
- private final BrowserController mBrowserController;
+ final boolean mIsIncognitoTab;
private final GestureDetector mGestureDetector;
- private final Activity mActivity;
+ private final BrowserActivity mActivity;
private static String mHomepage;
private static String mDefaultUserAgent;
- // TODO fix so that mWebpageBitmap can be static - static changes the icon when switching from light to dark and then back to light
- private final Bitmap mWebpageBitmap;
- private static PreferenceManager mPreferences;
- private final AdBlock mAdBlock;
- private final IntentUtils mIntentUtils;
private final Paint mPaint = new Paint();
private boolean isForegroundTab;
- private boolean mTextReflow = false;
private boolean mInvertPage = false;
private boolean mToggleDesktop = false;
private static float mMaxFling;
@@ -101,24 +81,28 @@ public class LightningView {
};
private final PermissionsManager mPermissionsManager;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
+ private final WebViewHandler webViewHandler = new WebViewHandler();
+
+ @Inject
+ Bus eventBus;
+
+ @Inject
+ PreferenceManager mPreferences;
+
+ @Inject
+ LightningDialogBuilder bookmarksDialogBuilder;
@SuppressLint("NewApi")
- public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito, BrowserController controller) {
-
+ public LightningView(BrowserActivity activity, String url, boolean darkTheme, boolean isIncognito) {
+ BrowserApp.getAppComponent().inject(this);
mActivity = activity;
mWebView = new WebView(activity);
mIsIncognitoTab = isIncognito;
- mTitle = new Title(activity, darkTheme);
- mAdBlock = AdBlock.getInstance(activity.getApplicationContext());
+ mTitle = new LightningViewTitle(activity, darkTheme);
mPermissionsManager = PermissionsManager.getInstance();
- mWebpageBitmap = mTitle.mDefaultIcon;
-
mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity();
- mBrowserController = controller;
-
- mIntentUtils = new IntentUtils(mActivity);
mWebView.setDrawingCacheBackgroundColor(Color.WHITE);
mWebView.setFocusableInTouchMode(true);
mWebView.setFocusable(true);
@@ -135,8 +119,8 @@ public class LightningView {
mWebView.setScrollbarFadingEnabled(true);
mWebView.setSaveEnabled(true);
mWebView.setNetworkAvailable(true);
- mWebView.setWebChromeClient(new LightningChromeClient(activity));
- mWebView.setWebViewClient(new LightningWebClient(activity));
+ mWebView.setWebChromeClient(new LightningChromeClient(activity, this));
+ mWebView.setWebViewClient(new LightningWebClient(activity, this));
mWebView.setDownloadListener(new LightningDownloadListener(activity));
mGestureDetector = new GestureDetector(activity, new CustomGestureListener());
mWebView.setOnTouchListener(new TouchListener());
@@ -162,12 +146,37 @@ public class LightningView {
if (mHomepage.startsWith("about:home")) {
mWebView.loadUrl(StartPage.getHomepage(mActivity));
} else if (mHomepage.startsWith("about:bookmarks")) {
- mBrowserController.openBookmarkPage(mWebView);
+ loadBookmarkpage();
} else {
mWebView.loadUrl(mHomepage);
}
}
+ /**
+ * Load the HTML bookmarks page in this view
+ */
+ public void loadBookmarkpage() {
+ if (mWebView == null)
+ return;
+ Bitmap folderIcon = ThemeUtils.getThemedBitmap(mActivity, R.drawable.ic_folder, false);
+ FileOutputStream outputStream = null;
+ File image = new File(mActivity.getCacheDir(), "folder.png");
+ try {
+ outputStream = new FileOutputStream(image);
+ folderIcon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
+ folderIcon.recycle();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } finally {
+ Utils.close(outputStream);
+ }
+ File bookmarkWebPage = new File(mActivity.getFilesDir(), Constants.BOOKMARKS_FILENAME);
+
+ BrowserApp.getAppComponent().getBookmarkPage().buildBookmarkPage(null);
+ mWebView.loadUrl(Constants.FILE + bookmarkWebPage);
+
+ }
+
/**
* Initialize the preference driven settings of the WebView
*
@@ -182,12 +191,9 @@ public class LightningView {
} else if (settings == null) {
settings = mWebView.getSettings();
}
- mPreferences = PreferenceManager.getInstance();
settings.setDefaultTextEncodingName(mPreferences.getTextEncoding());
mHomepage = mPreferences.getHomepage();
- mAdBlock.updatePreference();
-
setColorMode(mPreferences.getRenderingMode());
if (!mIsIncognitoTab) {
@@ -242,7 +248,6 @@ public class LightningView {
}
if (mPreferences.getTextReflowEnabled()) {
- mTextReflow = true;
settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
if (API >= android.os.Build.VERSION_CODES.KITKAT) {
try {
@@ -254,7 +259,6 @@ public class LightningView {
}
}
} else {
- mTextReflow = false;
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
}
@@ -408,7 +412,7 @@ public class LightningView {
public void setForegroundTab(boolean isForeground) {
isForegroundTab = isForeground;
- mBrowserController.updateTabs();
+ eventBus.post(new BrowserEvents.TabsChanged());
}
public boolean isForegroundTab() {
@@ -511,7 +515,7 @@ public class LightningView {
public synchronized void reload() {
// Check if configured proxy is available
- if (mBrowserController.proxyIsNotReady()) {
+ if (!ProxyUtils.getInstance().isProxyReady()) {
// User has been notified
return;
}
@@ -579,6 +583,60 @@ public class LightningView {
}
}
+ /**
+ * Used by {@link LightningWebClient}
+ *
+ * @return true if the page is in inverted mode, false otherwise
+ */
+ public boolean getInvertePage() {
+ return mInvertPage;
+ }
+ /**
+ * handles a long click on the page, parameter String url
+ * is the url that should have been obtained from the WebView touch node
+ * thingy, if it is null, this method tries to deal with it and find a workaround
+ */
+ private void longClickPage(final String url) {
+ final WebView.HitTestResult result = mWebView.getHitTestResult();
+ String currentUrl = mWebView.getUrl();
+ if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) {
+ if (currentUrl.endsWith(HistoryPage.FILENAME)) {
+ if (url != null) {
+ bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url);
+ } else if (result != null && result.getExtra() != null) {
+ final String newUrl = result.getExtra();
+ bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl);
+ }
+ } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) {
+ if (url != null) {
+ bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
+ } else if (result != null && result.getExtra() != null) {
+ final String newUrl = result.getExtra();
+ bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
+ }
+ }
+ } else {
+ if (url != null) {
+ if (result != null) {
+ if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
+ bookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent());
+ } else {
+ bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
+ }
+ } else {
+ bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
+ }
+ } else if (result != null && result.getExtra() != null) {
+ final String newUrl = result.getExtra();
+ if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
+ bookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent());
+ } else {
+ bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
+ }
+ }
+ }
+ }
+
public boolean canGoBack() {
return mWebView != null && mWebView.canGoBack();
}
@@ -598,8 +656,7 @@ public class LightningView {
public synchronized void loadUrl(String url) {
// Check if configured proxy is available
- if (mBrowserController.proxyIsNotReady()) {
- // User has been notified
+ if (!ProxyUtils.getInstance().isProxyReady()) {
return;
}
@@ -621,500 +678,6 @@ public class LightningView {
}
}
- private static class IconCacheTask implements Runnable {
- private final Uri uri;
- private final Bitmap icon;
-
- public IconCacheTask(Uri uri, Bitmap icon) {
- this.uri = uri;
- this.icon = icon;
- }
-
- @Override
- public void run() {
- String hash = String.valueOf(uri.getHost().hashCode());
- Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
- FileOutputStream fos = null;
- try {
- File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
- fos = new FileOutputStream(image);
- icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
- fos.flush();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- Utils.close(fos);
- }
- }
- }
-
- public class LightningWebClient extends WebViewClient {
-
- final Activity mActivity;
-
- LightningWebClient(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- if (mAdBlock.isAd(request.getUrl().toString())) {
- ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
- return new WebResourceResponse("text/plain", "utf-8", EMPTY);
- }
- }
- return super.shouldInterceptRequest(view, request);
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
- if (mAdBlock.isAd(url)) {
- ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
- return new WebResourceResponse("text/plain", "utf-8", EMPTY);
- }
- return null;
- }
-
- @SuppressLint("NewApi")
- @Override
- public void onPageFinished(WebView view, String url) {
- if (view.isShown()) {
- mBrowserController.updateUrl(url, true);
- view.postInvalidate();
- }
- if (view.getTitle() == null || view.getTitle().isEmpty()) {
- mTitle.setTitle(mActivity.getString(R.string.untitled));
- } else {
- mTitle.setTitle(view.getTitle());
- }
- if (API >= android.os.Build.VERSION_CODES.KITKAT && mInvertPage) {
- view.evaluateJavascript(Constants.JAVASCRIPT_INVERT_PAGE, null);
- }
- mBrowserController.updateTabs();
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- if (isShown()) {
- mBrowserController.updateUrl(url, false);
- mBrowserController.showActionBar();
- }
- mTitle.setFavicon(mWebpageBitmap);
- mBrowserController.updateTabs();
- }
-
- @Override
- public void onReceivedHttpAuthRequest(final WebView view, @NonNull final HttpAuthHandler handler,
- final String host, final String realm) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
- final EditText name = new EditText(mActivity);
- final EditText password = new EditText(mActivity);
- LinearLayout passLayout = new LinearLayout(mActivity);
- passLayout.setOrientation(LinearLayout.VERTICAL);
-
- passLayout.addView(name);
- passLayout.addView(password);
-
- name.setHint(mActivity.getString(R.string.hint_username));
- name.setSingleLine();
- password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
- password.setSingleLine();
- password.setTransformationMethod(new PasswordTransformationMethod());
- password.setHint(mActivity.getString(R.string.hint_password));
- builder.setTitle(mActivity.getString(R.string.title_sign_in));
- builder.setView(passLayout);
- builder.setCancelable(true)
- .setPositiveButton(mActivity.getString(R.string.title_sign_in),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- String user = name.getText().toString();
- String pass = password.getText().toString();
- handler.proceed(user.trim(), pass.trim());
- Log.d(Constants.TAG, "Request Login");
-
- }
- })
- .setNegativeButton(mActivity.getString(R.string.action_cancel),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- handler.cancel();
-
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
-
- }
-
- 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) {
- if (mIsRunning)
- return;
- if (Math.abs(mZoomScale - newScale) > 0.01f) {
- mIsRunning = view.postDelayed(new Runnable() {
-
- @Override
- public void run() {
- mZoomScale = newScale;
- view.evaluateJavascript(Constants.JAVASCRIPT_TEXT_REFLOW, null);
- mIsRunning = false;
- }
-
- }, 100);
- }
-
- }
- }
-
- private List getAllSslErrorMessageCodes(SslError error) {
-
- List errorCodeMessageCodes = new ArrayList<>();
-
- if (error.hasError(SslError.SSL_DATE_INVALID)) {
- errorCodeMessageCodes.add(R.string.message_certificate_date_invalid);
- }
- if (error.hasError(SslError.SSL_EXPIRED)) {
- errorCodeMessageCodes.add(R.string.message_certificate_expired);
- }
- if (error.hasError(SslError.SSL_IDMISMATCH)) {
- errorCodeMessageCodes.add(R.string.message_certificate_domain_mismatch);
- }
- if (error.hasError(SslError.SSL_NOTYETVALID)) {
- errorCodeMessageCodes.add(R.string.message_certificate_not_yet_valid);
- }
- if (error.hasError(SslError.SSL_UNTRUSTED)) {
- errorCodeMessageCodes.add(R.string.message_certificate_untrusted);
- }
- if (error.hasError(SslError.SSL_INVALID)) {
- errorCodeMessageCodes.add(R.string.message_certificate_invalid);
- }
-
- return errorCodeMessageCodes;
- }
-
- @Override
- public void onReceivedSslError(WebView view, @NonNull final SslErrorHandler handler, SslError error) {
-
- List errorCodeMessageCodes = getAllSslErrorMessageCodes(error);
-
- StringBuilder stringBuilder = new StringBuilder();
- for (Integer messageCode : errorCodeMessageCodes) {
- stringBuilder.append(" - ").append(mActivity.getString(messageCode)).append('\n');
- }
- String alertMessage =
- mActivity.getString(R.string.message_insecure_connection, stringBuilder.toString());
-
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
- builder.setTitle(mActivity.getString(R.string.title_warning));
- builder.setMessage(alertMessage)
- .setCancelable(true)
- .setPositiveButton(mActivity.getString(R.string.action_yes),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- handler.proceed();
- }
- })
- .setNegativeButton(mActivity.getString(R.string.action_no),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- handler.cancel();
- }
- });
- builder.create().show();
- }
-
- @Override
- public void onFormResubmission(WebView view, @NonNull final Message dontResend, final Message resend) {
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
- builder.setTitle(mActivity.getString(R.string.title_form_resubmission));
- builder.setMessage(mActivity.getString(R.string.message_form_resubmission))
- .setCancelable(true)
- .setPositiveButton(mActivity.getString(R.string.action_yes),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
-
- resend.sendToTarget();
- }
- })
- .setNegativeButton(mActivity.getString(R.string.action_no),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
-
- dontResend.sendToTarget();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
- }
-
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- // Check if configured proxy is available
- if (mBrowserController.proxyIsNotReady()) {
- // User has been notified
- return true;
- }
-
- if (mIsIncognitoTab) {
- return super.shouldOverrideUrlLoading(view, url);
- }
- if (url.startsWith("about:")) {
- return super.shouldOverrideUrlLoading(view, url);
- }
- if (url.contains("mailto:")) {
- MailTo mailTo = MailTo.parse(url);
- Intent i = Utils.newEmailIntent(mailTo.getTo(), mailTo.getSubject(),
- mailTo.getBody(), mailTo.getCc());
- mActivity.startActivity(i);
- view.reload();
- return true;
- } else if (url.startsWith("intent://")) {
- Intent intent;
- try {
- intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
- } catch (URISyntaxException ex) {
- return false;
- }
- if (intent != null) {
- try {
- mActivity.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- Log.e(Constants.TAG, "ActivityNotFoundException");
- }
- return true;
- }
- }
- return mIntentUtils.startActivityForUrl(mWebView, url);
- }
- }
-
- public class LightningChromeClient extends WebChromeClient {
-
- final Activity mActivity;
-
- LightningChromeClient(Activity activity) {
- mActivity = activity;
- }
-
- @Override
- public void onProgressChanged(WebView view, int newProgress) {
- if (isShown()) {
- mBrowserController.updateProgress(newProgress);
- }
- }
-
- @Override
- public void onReceivedIcon(WebView view, Bitmap icon) {
- if (icon == null)
- return;
- mTitle.setFavicon(icon);
- mBrowserController.updateTabs();
- cacheFavicon(icon);
- }
-
- @Override
- public void onReceivedTitle(WebView view, String title) {
- if (title != null && !title.isEmpty()) {
- mTitle.setTitle(title);
- } else {
- mTitle.setTitle(mActivity.getString(R.string.untitled));
- }
- mBrowserController.updateTabs();
- if (view != null)
- mBrowserController.updateHistory(title, view.getUrl());
- }
-
- @Override
- public void onGeolocationPermissionsShowPrompt(final String origin,
- final GeolocationPermissions.Callback callback) {
- mPermissionsManager.requestPermissionsIfNecessary(mActivity, PERMISSIONS);
- final boolean remember = true;
- AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
- builder.setTitle(mActivity.getString(R.string.location));
- String org;
- if (origin.length() > 50) {
- org = origin.subSequence(0, 50) + "...";
- } else {
- org = origin;
- }
- builder.setMessage(org + mActivity.getString(R.string.message_location))
- .setCancelable(true)
- .setPositiveButton(mActivity.getString(R.string.action_allow),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- callback.invoke(origin, true, remember);
- }
- })
- .setNegativeButton(mActivity.getString(R.string.action_dont_allow),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- callback.invoke(origin, false, remember);
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
-
- }
-
- @Override
- public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
- Message resultMsg) {
- mBrowserController.onCreateWindow(resultMsg);
- return true;
- }
-
- @Override
- public void onCloseWindow(WebView window) {
- mBrowserController.onCloseWindow(LightningView.this);
- }
-
- @SuppressWarnings("unused")
- public void openFileChooser(ValueCallback uploadMsg) {
- mBrowserController.openFileChooser(uploadMsg);
- }
-
- @SuppressWarnings("unused")
- public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
- mBrowserController.openFileChooser(uploadMsg);
- }
-
- @SuppressWarnings("unused")
- public void openFileChooser(ValueCallback uploadMsg, String acceptType, String capture) {
- mBrowserController.openFileChooser(uploadMsg);
- }
-
- public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback,
- WebChromeClient.FileChooserParams fileChooserParams) {
- mBrowserController.showFileChooser(filePathCallback);
- return true;
- }
-
- @Override
- public Bitmap getDefaultVideoPoster() {
- return mBrowserController.getDefaultVideoPoster();
- }
-
- @Override
- public View getVideoLoadingProgressView() {
- return mBrowserController.getVideoLoadingProgressView();
- }
-
- @Override
- public void onHideCustomView() {
- mBrowserController.onHideCustomView();
- super.onHideCustomView();
- }
-
- @Override
- public void onShowCustomView(View view, CustomViewCallback callback) {
- // While these lines might look like they work, in practice,
- // Full-screen videos won't work correctly. I may test this out some
- // more
- // if (view instanceof FrameLayout) {
- // FrameLayout frame = (FrameLayout) view;
- // if (frame.getFocusedChild() instanceof VideoView) {
- // VideoView video = (VideoView) frame.getFocusedChild();
- // video.stopPlayback();
- // frame.removeView(video);
- // video.setVisibility(View.GONE);
- // }
- // } else {
- mBrowserController.onShowCustomView(view, callback);
-
- // }
-
- super.onShowCustomView(view, callback);
- }
-
- @SuppressWarnings("deprecation")
- @Override
- @Deprecated
- public void onShowCustomView(View view, int requestedOrientation,
- CustomViewCallback callback) {
- // While these lines might look like they work, in practice,
- // Full-screen videos won't work correctly. I may test this out some
- // more
- // if (view instanceof FrameLayout) {
- // FrameLayout frame = (FrameLayout) view;
- // if (frame.getFocusedChild() instanceof VideoView) {
- // VideoView video = (VideoView) frame.getFocusedChild();
- // video.stopPlayback();
- // frame.removeView(video);
- // video.setVisibility(View.GONE);
- // }
- // } else {
- mBrowserController.onShowCustomView(view, callback);
-
- // }
-
- super.onShowCustomView(view, requestedOrientation, callback);
- }
- }
-
- public class Title {
-
- private Bitmap mFavicon;
- private String mTitle;
- private final Bitmap mDefaultIcon;
-
- public Title(Context context, boolean darkTheme) {
- mDefaultIcon = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
- mFavicon = mDefaultIcon;
- mTitle = mActivity.getString(R.string.action_new_tab);
- }
-
- public void setFavicon(Bitmap favicon) {
- if (favicon == null) {
- mFavicon = mDefaultIcon;
- } else {
- mFavicon = Utils.padFavicon(favicon);
- }
- }
-
- public void setTitle(String title) {
- if (title == null) {
- mTitle = "";
- } else {
- mTitle = title;
- }
- }
-
- public void setTitleAndFavicon(String title, Bitmap favicon) {
- mTitle = title;
-
- if (favicon == null) {
- mFavicon = mDefaultIcon;
- } else {
- mFavicon = Utils.padFavicon(favicon);
- }
- }
-
- public String getTitle() {
- return mTitle;
- }
-
- public Bitmap getFavicon() {
- return mFavicon;
- }
-
- }
-
private class TouchListener implements OnTouchListener {
float mLocation;
@@ -1137,9 +700,9 @@ public class LightningView {
} else if (mAction == MotionEvent.ACTION_UP) {
final float distance = (mY - mLocation);
if (distance > SCROLL_UP_THRESHOLD && view.getScrollY() < SCROLL_UP_THRESHOLD) {
- mBrowserController.showActionBar();
+ mActivity.showActionBar();
} else if (distance < -SCROLL_UP_THRESHOLD) {
- mBrowserController.hideActionBar();
+ mActivity.hideActionBar();
}
mLocation = 0;
}
@@ -1154,9 +717,9 @@ public class LightningView {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int power = (int) (velocityY * 100 / mMaxFling);
if (power < -10) {
- mBrowserController.hideActionBar();
+ mActivity.hideActionBar();
} else if (power > 15) {
- mBrowserController.showActionBar();
+ mActivity.showActionBar();
}
return super.onFling(e1, e2, velocityX, velocityY);
}
@@ -1172,8 +735,13 @@ public class LightningView {
@Override
public void onLongPress(MotionEvent e) {
- if (mCanTriggerLongPress)
- mBrowserController.onLongPress();
+ if (mCanTriggerLongPress) {
+ Message msg = webViewHandler.obtainMessage();
+ if (msg != null) {
+ msg.setTarget(webViewHandler);
+ mWebView.requestFocusNodeHref(msg);
+ }
+ }
}
/**
@@ -1195,4 +763,13 @@ public class LightningView {
mCanTriggerLongPress = true;
}
}
+
+ private class WebViewHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ final String url = msg.getData().getString("url");
+ longClickPage(url);
+ }
+ }
}
diff --git a/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java b/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java
new file mode 100644
index 0000000..2452d85
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java
@@ -0,0 +1,66 @@
+package acr.browser.lightning.view;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+
+import acr.browser.lightning.R;
+import acr.browser.lightning.utils.ThemeUtils;
+import acr.browser.lightning.utils.Utils;
+
+/**
+ * @author Stefano Pacifici base on Anthony C. Restaino's code
+ * @date 2015/09/21
+ */
+class LightningViewTitle {
+
+ private static Bitmap DEFAULT_ICON = null;
+
+ private Bitmap mFavicon;
+ private String mTitle;
+
+ public LightningViewTitle(Context context, boolean darkTheme) {
+ if (DEFAULT_ICON == null) {
+ DEFAULT_ICON = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
+ }
+ mFavicon = DEFAULT_ICON;
+ mTitle = context.getString(R.string.action_new_tab);
+ }
+
+ public void setFavicon(Bitmap favicon) {
+ if (favicon == null) {
+ mFavicon = DEFAULT_ICON;
+ } else {
+ mFavicon = Utils.padFavicon(favicon);
+ }
+ }
+
+ public void setTitle(String title) {
+ if (title == null) {
+ mTitle = "";
+ } else {
+ mTitle = title;
+ }
+ }
+
+ public void setTitleAndFavicon(String title, Bitmap favicon) {
+ mTitle = title;
+
+ if (favicon == null) {
+ mFavicon = DEFAULT_ICON;
+ } else {
+ mFavicon = Utils.padFavicon(favicon);
+ }
+ }
+
+ public String getTitle() {
+ return mTitle;
+ }
+
+ public Bitmap getFavicon() {
+ return mFavicon;
+ }
+
+ public Bitmap getDefaultIcon() {
+ return DEFAULT_ICON;
+ }
+}
diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java
new file mode 100644
index 0000000..b57556e
--- /dev/null
+++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java
@@ -0,0 +1,276 @@
+package acr.browser.lightning.view;
+
+import android.annotation.SuppressLint;
+import android.content.ActivityNotFoundException;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.MailTo;
+import android.net.http.SslError;
+import android.os.Build;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AlertDialog;
+import android.text.InputType;
+import android.text.method.PasswordTransformationMethod;
+import android.util.Log;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+import com.squareup.otto.Bus;
+
+import java.io.ByteArrayInputStream;
+import java.net.URISyntaxException;
+
+import acr.browser.lightning.R;
+import acr.browser.lightning.activity.BrowserActivity;
+import acr.browser.lightning.app.BrowserApp;
+import acr.browser.lightning.bus.BrowserEvents;
+import acr.browser.lightning.constant.Constants;
+import acr.browser.lightning.utils.AdBlock;
+import acr.browser.lightning.utils.IntentUtils;
+import acr.browser.lightning.utils.ProxyUtils;
+import acr.browser.lightning.utils.Utils;
+
+/**
+ * @author Stefano Pacifici based on Anthony C. Restaino's code
+ * @date 2015/09/22
+ */
+public class LightningWebClient extends WebViewClient {
+
+ private final BrowserActivity mActivity;
+ private final LightningView mLightningView;
+ private final AdBlock mAdBlock;
+ private final Bus mEventBus;
+ private final IntentUtils mIntentUtils;
+
+ LightningWebClient(BrowserActivity activity, LightningView lightningView) {
+ mActivity = activity;
+ mLightningView = lightningView;
+ mAdBlock = AdBlock.getInstance(activity);
+ mAdBlock.updatePreference();
+ mEventBus = BrowserApp.getAppComponent().getBus();
+ mIntentUtils = new IntentUtils(activity);
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (mAdBlock.isAd(request.getUrl().toString())) {
+ ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
+ return new WebResourceResponse("text/plain", "utf-8", EMPTY);
+ }
+ }
+ return super.shouldInterceptRequest(view, request);
+ }
+
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+ if (mAdBlock.isAd(url)) {
+ ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
+ return new WebResourceResponse("text/plain", "utf-8", EMPTY);
+ }
+ return null;
+ }
+
+ @SuppressLint("NewApi")
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ if (view.isShown()) {
+ mActivity.updateUrl(url, true);
+ view.postInvalidate();
+ }
+ if (view.getTitle() == null || view.getTitle().isEmpty()) {
+ mLightningView.mTitle.setTitle(mActivity.getString(R.string.untitled));
+ } else {
+ mLightningView.mTitle.setTitle(view.getTitle());
+ }
+ if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT &&
+ mLightningView.getInvertePage()) {
+ view.evaluateJavascript(Constants.JAVASCRIPT_INVERT_PAGE, null);
+ }
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ if (mLightningView.isShown()) {
+ mActivity.updateUrl(url, false);
+ mActivity.showActionBar();
+ }
+ mEventBus.post(new BrowserEvents.TabsChanged());
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest(final WebView view, @NonNull final HttpAuthHandler handler,
+ final String host, final String realm) {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
+ final EditText name = new EditText(mActivity);
+ final EditText password = new EditText(mActivity);
+ LinearLayout passLayout = new LinearLayout(mActivity);
+ passLayout.setOrientation(LinearLayout.VERTICAL);
+
+ passLayout.addView(name);
+ passLayout.addView(password);
+
+ name.setHint(mActivity.getString(R.string.hint_username));
+ name.setSingleLine();
+ password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ password.setSingleLine();
+ password.setTransformationMethod(new PasswordTransformationMethod());
+ password.setHint(mActivity.getString(R.string.hint_password));
+ builder.setTitle(mActivity.getString(R.string.title_sign_in));
+ builder.setView(passLayout);
+ builder.setCancelable(true)
+ .setPositiveButton(mActivity.getString(R.string.title_sign_in),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ String user = name.getText().toString();
+ String pass = password.getText().toString();
+ handler.proceed(user.trim(), pass.trim());
+ Log.d(Constants.TAG, "Request Login");
+
+ }
+ })
+ .setNegativeButton(mActivity.getString(R.string.action_cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ handler.cancel();
+
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+
+ }
+
+ 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() && mLightningView.mPreferences.getTextReflowEnabled() &&
+ Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
+ if (mIsRunning)
+ return;
+ if (Math.abs(mZoomScale - newScale) > 0.01f) {
+ mIsRunning = view.postDelayed(new Runnable() {
+
+ @Override
+ public void run() {
+ mZoomScale = newScale;
+ view.evaluateJavascript(Constants.JAVASCRIPT_TEXT_REFLOW, null);
+ mIsRunning = false;
+ }
+
+ }, 100);
+ }
+
+ }
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, @NonNull final SslErrorHandler handler, SslError error) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
+ builder.setTitle(mActivity.getString(R.string.title_warning));
+ builder.setMessage(mActivity.getString(R.string.message_untrusted_certificate))
+ .setCancelable(true)
+ .setPositiveButton(mActivity.getString(R.string.action_yes),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ handler.proceed();
+ }
+ })
+ .setNegativeButton(mActivity.getString(R.string.action_no),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ handler.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) {
+ alert.show();
+ } else {
+ handler.proceed();
+ }
+
+ }
+
+ @Override
+ public void onFormResubmission(WebView view, @NonNull final Message dontResend, final Message resend) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
+ builder.setTitle(mActivity.getString(R.string.title_form_resubmission));
+ builder.setMessage(mActivity.getString(R.string.message_form_resubmission))
+ .setCancelable(true)
+ .setPositiveButton(mActivity.getString(R.string.action_yes),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+
+ resend.sendToTarget();
+ }
+ })
+ .setNegativeButton(mActivity.getString(R.string.action_no),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+
+ dontResend.sendToTarget();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
+ }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ // Check if configured proxy is available
+ if (!ProxyUtils.getInstance().isProxyReady()) {
+ // User has been notified
+ return true;
+ }
+
+ if (mLightningView.mIsIncognitoTab) {
+ return super.shouldOverrideUrlLoading(view, url);
+ }
+ if (url.startsWith("about:")) {
+ return super.shouldOverrideUrlLoading(view, url);
+ }
+ if (url.contains("mailto:")) {
+ MailTo mailTo = MailTo.parse(url);
+ Intent i = Utils.newEmailIntent(mailTo.getTo(), mailTo.getSubject(),
+ mailTo.getBody(), mailTo.getCc());
+ mActivity.startActivity(i);
+ view.reload();
+ return true;
+ } else if (url.startsWith("intent://")) {
+ Intent intent;
+ try {
+ intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
+ } catch (URISyntaxException ex) {
+ return false;
+ }
+ if (intent != null) {
+ try {
+ mActivity.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(Constants.TAG, "ActivityNotFoundException");
+ }
+ return true;
+ }
+ }
+ return mIntentUtils.startActivityForUrl(view, url);
+ }
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 31777df..eae84d4 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -25,7 +25,14 @@
-
+
-
-
-
+ android:layout_height="match_parent" />
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/tab_drawer.xml b/app/src/main/res/layout/tab_drawer.xml
index dbed4bd..bbf334e 100644
--- a/app/src/main/res/layout/tab_drawer.xml
+++ b/app/src/main/res/layout/tab_drawer.xml
@@ -1,12 +1,9 @@
+ android:dividerHeight="0dp"
+ android:overScrollMode="ifContentScrolls" />
+
+
diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml
index 9b144f3..cc0fbcb 100644
--- a/app/src/main/res/layout/toolbar.xml
+++ b/app/src/main/res/layout/toolbar.xml
@@ -8,13 +8,10 @@
android:elevation="2dp"
android:orientation="vertical">
-
+ android:id="@+id/tabs_toolbar_container"/>