Simplified LightningView with externalized XXXClients
This commit is contained in:
parent
3615018816
commit
6749ca39b8
@ -18,14 +18,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 +32,13 @@ import android.provider.MediaStore;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
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 +66,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,11 +84,7 @@ 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;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -115,7 +100,7 @@ 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.dialog.LightningDialogBuilder;
|
||||
import acr.browser.lightning.fragment.TabsFragment;
|
||||
import acr.browser.lightning.object.SearchAdapter;
|
||||
import acr.browser.lightning.preference.PreferenceManager;
|
||||
@ -166,10 +151,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
mCurrentUiColor = Color.BLACK;
|
||||
private String mSearchText, mUntitledTitle, mHomepage, mCameraPhotoPath;
|
||||
|
||||
// Storage
|
||||
private HistoryDatabase mHistoryDatabase;
|
||||
|
||||
|
||||
// The singleton BookmarkManager
|
||||
@Inject
|
||||
BookmarkManager bookmarkManager;
|
||||
@ -182,7 +163,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
BookmarkPage bookmarkPage;
|
||||
|
||||
@Inject
|
||||
BookmarksDialogBuilder bookmarksDialogBuilder;
|
||||
LightningDialogBuilder bookmarksDialogBuilder;
|
||||
|
||||
@Inject
|
||||
TabsManager tabsManager;
|
||||
@ -190,6 +171,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
@Inject
|
||||
PreferenceManager mPreferences;
|
||||
|
||||
@Inject
|
||||
HistoryDatabase mHistoryDatabase;
|
||||
|
||||
// Image
|
||||
private Bitmap mWebpageBitmap;
|
||||
private final ColorDrawable mBackground = new ColorDrawable();
|
||||
@ -280,8 +264,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container));
|
||||
}
|
||||
|
||||
mHistoryDatabase = HistoryDatabase.getInstance();
|
||||
|
||||
if (actionBar == null)
|
||||
return;
|
||||
|
||||
@ -356,7 +338,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);
|
||||
}
|
||||
@ -565,45 +549,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO !!!! THIS MUST BY RESTORED ASAP !!!!
|
||||
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();
|
||||
@ -1001,7 +946,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
return false;
|
||||
}
|
||||
mIsNewIntent = false;
|
||||
LightningView startingTab = tabsManager.newTab(mActivity, url, mDarkTheme, isIncognito(), this);
|
||||
LightningView startingTab = tabsManager.newTab(this, url, mDarkTheme, isIncognito());
|
||||
if (mIdGenerator == 0) {
|
||||
startingTab.resumeTimers();
|
||||
}
|
||||
@ -1227,7 +1172,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
currentTab.resumeTimers();
|
||||
currentTab.onResume();
|
||||
}
|
||||
mHistoryDatabase = HistoryDatabase.getInstance();
|
||||
initializePreferences();
|
||||
tabsManager.resume(this);
|
||||
|
||||
@ -1366,9 +1310,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);
|
||||
@ -1848,107 +1789,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
private void longPressHistoryLink(final String url) {
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final LightningView currentTab = tabsManager.getCurrentTab();
|
||||
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 (currentTab != null) {
|
||||
loadUrlInCurrentView(url);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
|
||||
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();
|
||||
}
|
||||
|
||||
private void longPressImage(final String url) {
|
||||
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final LightningView currentTab = tabsManager.getCurrentTab();
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON_POSITIVE:
|
||||
newTab(url, false);
|
||||
break;
|
||||
|
||||
case DialogInterface.BUTTON_NEGATIVE:
|
||||
loadUrlInCurrentView(url);
|
||||
break;
|
||||
|
||||
case DialogInterface.BUTTON_NEUTRAL:
|
||||
if (API > 8) {
|
||||
Utils.downloadFile(mActivity, url,
|
||||
currentTab.getUserAgent(), "attachment");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
|
||||
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();
|
||||
}
|
||||
|
||||
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(mActivity); // 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -2058,13 +1898,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements
|
||||
|
||||
private final Object busEventListener = 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 The event as it comes from the bus
|
||||
*/
|
||||
@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();
|
||||
@ -2077,13 +1918,14 @@ 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 The event as it comes from the bus
|
||||
*/
|
||||
@Subscribe
|
||||
public void loadBookmarkInNewTab(final BookmarkEvents.AsNewTab event) {
|
||||
BrowserActivity.this.newTab(event.bookmark.getUrl(), true);
|
||||
public void loadUrlInNewTab(final BrowserEvents.OpenUrlInNewTab event) {
|
||||
BrowserActivity.this.newTab(event.url, true);
|
||||
mDrawerLayout.closeDrawers();
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ 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;
|
||||
|
||||
/**
|
||||
@ -26,7 +27,30 @@ public class TabsManager {
|
||||
private LightningView mCurrentTab;
|
||||
|
||||
@Inject
|
||||
public TabsManager(final Context context, final PreferenceManager preferenceManager) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,13 +136,11 @@ public class TabsManager {
|
||||
* @param url
|
||||
* @param darkTheme
|
||||
* @param isIncognito
|
||||
* @param controller
|
||||
* @return
|
||||
*/
|
||||
public synchronized LightningView newTab(final Activity activity,
|
||||
public synchronized LightningView newTab(final BrowserActivity activity,
|
||||
final String url, final boolean darkTheme,
|
||||
final boolean isIncognito,
|
||||
final BrowserController controller) {
|
||||
final boolean isIncognito) {
|
||||
final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito);
|
||||
mWebViewList.add(tab);
|
||||
return tab;
|
||||
|
@ -8,7 +8,8 @@ import javax.inject.Singleton;
|
||||
|
||||
import acr.browser.lightning.activity.BrowserActivity;
|
||||
import acr.browser.lightning.constant.BookmarkPage;
|
||||
import acr.browser.lightning.dialog.BookmarksDialogBuilder;
|
||||
import acr.browser.lightning.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;
|
||||
@ -33,7 +34,7 @@ public interface AppComponent {
|
||||
|
||||
void inject(SearchAdapter adapter);
|
||||
|
||||
void inject(BookmarksDialogBuilder builder);
|
||||
void inject(LightningDialogBuilder builder);
|
||||
|
||||
void inject(BookmarkPage bookmarkPage);
|
||||
|
||||
@ -47,6 +48,8 @@ public interface AppComponent {
|
||||
|
||||
Bus getBus();
|
||||
|
||||
HistoryDatabase getHistoryDatabase();
|
||||
|
||||
Context getApplicationContext();
|
||||
|
||||
void inject(LightningView lightningView);
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -1,11 +1,7 @@
|
||||
package acr.browser.lightning.bus;
|
||||
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
|
||||
import acr.browser.lightning.R;
|
||||
|
||||
/**
|
||||
* Created by Stefano Pacifici on 26/08/15.
|
||||
*/
|
||||
@ -21,9 +17,9 @@ public final class BrowserEvents {
|
||||
* result is a new bookmark added.
|
||||
*/
|
||||
public static class AddBookmark {
|
||||
public final String title, url;
|
||||
public final java.lang.String title, url;
|
||||
|
||||
public AddBookmark(final String title, final String url) {
|
||||
public AddBookmark(final java.lang.String title, final java.lang.String url) {
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
}
|
||||
@ -34,9 +30,9 @@ public final class BrowserEvents {
|
||||
* {@link acr.browser.lightning.fragment.BookmarksFragment} interface.
|
||||
*/
|
||||
public static class CurrentPageUrl {
|
||||
public final String url;
|
||||
public final java.lang.String url;
|
||||
|
||||
public CurrentPageUrl(final String url) {
|
||||
public CurrentPageUrl(final java.lang.String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
@ -53,15 +49,19 @@ public final class BrowserEvents {
|
||||
public static class TabsChanged {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Notify the Browser to display a SnackBar in the main activity
|
||||
*/
|
||||
public static class ShowSnackBarMessage {
|
||||
public final String message;
|
||||
public final java.lang.String message;
|
||||
@StringRes
|
||||
public final int stringRes;
|
||||
|
||||
public ShowSnackBarMessage(final String message) {
|
||||
public ShowSnackBarMessage(final java.lang.String message) {
|
||||
this.message = message;
|
||||
this.stringRes = -1;
|
||||
}
|
||||
@ -71,4 +71,26 @@ public final class BrowserEvents {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public class HistoryPage {
|
||||
}
|
||||
|
||||
private static List<HistoryItem> getWebHistory(Context context) {
|
||||
HistoryDatabase databaseHandler = HistoryDatabase.getInstance();
|
||||
HistoryDatabase databaseHandler = BrowserApp.getAppComponent().getHistoryDatabase();
|
||||
return databaseHandler.getLastHundredItems();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -42,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.utils.DownloadImageTask;
|
||||
import acr.browser.lightning.utils.ThemeUtils;
|
||||
@ -62,7 +62,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
|
||||
// Dialog builder
|
||||
@Inject
|
||||
BookmarksDialogBuilder bookmarksDialogBuilder;
|
||||
LightningDialogBuilder bookmarksDialogBuilder;
|
||||
|
||||
@Inject
|
||||
PreferenceManager preferenceManager;
|
||||
@ -109,7 +109,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true),
|
||||
true);
|
||||
} else {
|
||||
eventBus.post(new BookmarkEvents.Clicked(item));
|
||||
eventBus.post(new BrowserEvents.OpenUrlInCurrentTab(item.getUrl()));
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -293,7 +293,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
|
||||
if (item.isFolder()) {
|
||||
bookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item);
|
||||
} else {
|
||||
bookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item);
|
||||
bookmarksDialogBuilder.showLongPressLinkDialog(getContext(), item.getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,14 +54,11 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
|
||||
private final List<HistoryItem> mFilteredList = new ArrayList<>();
|
||||
private final List<HistoryItem> mAllBookmarks = new ArrayList<>();
|
||||
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;
|
||||
@Inject PreferenceManager mPreferenceManager;
|
||||
private static final String CACHE_FILE_TYPE = ".sgg";
|
||||
private static final String ENCODING = "ISO-8859-1";
|
||||
private static final long INTERVAL_DAY = 86400000;
|
||||
@ -73,9 +70,17 @@ 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 = mPreferenceManager.getGoogleSearchSuggestionsEnabled();
|
||||
mContext = context;
|
||||
@ -125,7 +130,6 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
|
||||
mSuggestions.clear();
|
||||
}
|
||||
}
|
||||
mDatabaseHandler = HistoryDatabase.getInstance();
|
||||
}
|
||||
|
||||
public void refreshBookmarks() {
|
||||
@ -240,13 +244,10 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
|
||||
mBookmarks.add(mAllBookmarks.get(n));
|
||||
counter++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mDatabaseHandler == null || mDatabaseHandler.isClosed()) {
|
||||
mDatabaseHandler = HistoryDatabase.getInstance();
|
||||
}
|
||||
|
||||
List<HistoryItem> historyList = mDatabaseHandler.findItemsContaining(constraint.toString());
|
||||
synchronized (mHistory) {
|
||||
mHistory.clear();
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
@ -32,7 +33,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();
|
||||
|
@ -0,0 +1,234 @@
|
||||
package acr.browser.lightning.view;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Message;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
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<Uri> uploadMsg) {
|
||||
mActivity.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
|
||||
mActivity.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
|
||||
mActivity.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
WebChromeClient.FileChooserParams fileChooserParams) {
|
||||
mActivity.showFileChooser(filePathCallback);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap getDefaultVideoPoster() {
|
||||
// TODO Simplify the method can be moved here
|
||||
return mActivity.getDefaultVideoPoster();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getVideoLoadingProgressView() {
|
||||
// TODO Simplify the method can be moved here
|
||||
return mActivity.getVideoLoadingProgressView();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
@ -6,27 +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;
|
||||
@ -35,45 +26,30 @@ 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 com.squareup.otto.Bus;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
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 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.bus.TabEvents;
|
||||
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.BookmarksDialogBuilder;
|
||||
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;
|
||||
@ -81,21 +57,15 @@ 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 = null; // TODO REMOVE
|
||||
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 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;
|
||||
@ -118,23 +88,20 @@ public class LightningView {
|
||||
PreferenceManager mPreferences;
|
||||
|
||||
@Inject
|
||||
BookmarksDialogBuilder bookmarksDialogBuilder;
|
||||
LightningDialogBuilder bookmarksDialogBuilder;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) {
|
||||
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);
|
||||
// mAdBlock = AdBlock.getInstance(activity.getApplicationContext());
|
||||
mPermissionsManager = PermissionsManager.getInstance();
|
||||
|
||||
mWebpageBitmap = mTitle.mDefaultIcon;
|
||||
|
||||
mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity();
|
||||
|
||||
mIntentUtils = new IntentUtils(activity);
|
||||
mWebView.setDrawingCacheBackgroundColor(Color.WHITE);
|
||||
mWebView.setFocusableInTouchMode(true);
|
||||
mWebView.setFocusable(true);
|
||||
@ -149,8 +116,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());
|
||||
@ -224,7 +191,7 @@ public class LightningView {
|
||||
|
||||
settings.setDefaultTextEncodingName(mPreferences.getTextEncoding());
|
||||
mHomepage = mPreferences.getHomepage();
|
||||
mAdBlock.updatePreference();
|
||||
// mAdBlock.updatePreference();
|
||||
|
||||
setColorMode(mPreferences.getRenderingMode());
|
||||
|
||||
@ -275,7 +242,6 @@ public class LightningView {
|
||||
}
|
||||
|
||||
if (mPreferences.getTextReflowEnabled()) {
|
||||
mTextReflow = true;
|
||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
|
||||
if (API >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
@ -287,7 +253,6 @@ public class LightningView {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mTextReflow = false;
|
||||
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
|
||||
}
|
||||
|
||||
@ -549,36 +514,6 @@ public class LightningView {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Naive caching of the favicon according to the domain name of the URL
|
||||
* @param icon the icon to cache
|
||||
*/
|
||||
private void cacheFavicon(final Bitmap icon) {
|
||||
if (icon == null) return;
|
||||
final Uri uri = Uri.parse(getUrl());
|
||||
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();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public synchronized void find(String text) {
|
||||
if (mWebView != null) {
|
||||
@ -623,6 +558,14 @@ 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
|
||||
@ -634,36 +577,36 @@ public class LightningView {
|
||||
if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) {
|
||||
if (currentUrl.endsWith(HistoryPage.FILENAME)) {
|
||||
if (url != null) {
|
||||
// TODO longPressHistoryLink(url);
|
||||
bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url);
|
||||
} else if (result != null && result.getExtra() != null) {
|
||||
final String newUrl = result.getExtra();
|
||||
// TODO longPressHistoryLink(newUrl);
|
||||
bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl);
|
||||
}
|
||||
} else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) {
|
||||
if (url != null) {
|
||||
bookmarksDialogBuilder.showLongPressedDialogForUrl(mActivity, url);
|
||||
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
|
||||
} else if (result != null && result.getExtra() != null) {
|
||||
final String newUrl = result.getExtra();
|
||||
bookmarksDialogBuilder.showLongPressedDialogForUrl(mActivity, newUrl);
|
||||
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) {
|
||||
// TODO longPressImage(url);
|
||||
bookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent());
|
||||
} else {
|
||||
// TODO longPressLink(url);
|
||||
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
|
||||
}
|
||||
} else {
|
||||
// TODO longPressLink(url);
|
||||
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) {
|
||||
// TODO longPressImage(newUrl);
|
||||
bookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent());
|
||||
} else {
|
||||
// TODO longPressLink(newUrl);
|
||||
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -716,438 +659,6 @@ public class LightningView {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
eventBus.post(new BrowserEvents.TabsChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
if (isShown()) {
|
||||
mBrowserController.updateUrl(url, false);
|
||||
mBrowserController.showActionBar();
|
||||
}
|
||||
mTitle.setFavicon(mWebpageBitmap);
|
||||
eventBus.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() && 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@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 (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);
|
||||
eventBus.post(new BrowserEvents.TabsChanged()); ;
|
||||
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));
|
||||
}
|
||||
eventBus.post(new BrowserEvents.TabsChanged()); ;
|
||||
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);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
|
||||
mBrowserController.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
|
||||
mBrowserController.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
|
||||
mBrowserController.openFileChooser(uploadMsg);
|
||||
}
|
||||
|
||||
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> 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);
|
||||
}
|
||||
|
||||
@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;
|
||||
@ -1170,9 +681,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;
|
||||
}
|
||||
@ -1187,9 +698,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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user