From 56284337184f90d530fc9412370747e95ffe179d Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Wed, 9 Sep 2015 09:52:11 +0200 Subject: [PATCH 01/58] iml files removed. They are generated during gradle sync by Android Studio. --- .gitignore | 2 + app/app.iml | 138 ---------------------------------------------------- 2 files changed, 2 insertions(+), 138 deletions(-) delete mode 100644 app/app.iml 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 8903f3d..0000000 --- a/app/app.iml +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 74a75d4adb09c0bf870229a8f5a09302fa5bd21f Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 14 Sep 2015 13:44:36 +0200 Subject: [PATCH 02/58] TabsManager created --- .../lightning/activity/BrowserActivity.java | 103 +++++------ .../lightning/activity/TabsManager.java | 172 ++++++++++++++++++ 2 files changed, 213 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/activity/TabsManager.java 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 acf0003..969afc0 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -137,7 +137,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private RelativeLayout mSearchBar; // List - private final List mWebViewList = new ArrayList<>(); private LightningView mCurrentView; private WebView mWebView; @@ -189,6 +188,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Inject BookmarksDialogBuilder bookmarksDialogBuilder; + @Inject + TabsManager tabsManager; + // Image private Bitmap mWebpageBitmap; private final ColorDrawable mBackground = new ColorDrawable(); @@ -237,7 +239,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet()); mActivity = this; - mWebViewList.clear(); + // TODO Stefano, check this + // mWebViewList.clear(); mClickHandler = new ClickHandler(this); mBrowserFrame = (FrameLayout) findViewById(R.id.content_frame); @@ -272,7 +275,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (mShowTabsInDrawer) { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, mWebViewList); + mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, tabsManager.getTabsList()); mDrawerListLeft = (RecyclerView) findViewById(R.id.left_drawer_list); mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); @@ -280,7 +283,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mDrawerListLeft.setHasFixedSize(true); mToolbarLayout.removeView(horizontalListView); } else { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item_horizontal, mWebViewList); + mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item_horizontal, tabsManager.getTabsList()); mDrawerListLeft = horizontalListView; mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_NEVER); mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft); @@ -873,10 +876,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onClick(View v) { - int position = mDrawerListLeft.getChildAdapterPosition(v); - if (mCurrentView != mWebViewList.get(position)) { + final int position = mDrawerListLeft.getChildAdapterPosition(v); + final LightningView tab = tabsManager.getTabAtPosition(position); + if (tab != null && mCurrentView != tab) { mIsNewIntent = false; - showTab(mWebViewList.get(position)); + showTab(tab); } } } @@ -1018,25 +1022,22 @@ 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(mActivity, url, mDarkTheme, isIncognito(), this); + LightningView startingTab = tabsManager.newTab(mActivity, url, mDarkTheme, isIncognito(), this); if (mIdGenerator == 0) { startingTab.resumeTimers(); } mIdGenerator++; - mWebViewList.add(startingTab); if (show) { showTab(startingTab); @@ -1045,7 +1046,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements new Handler().postDelayed(new Runnable() { @Override public void run() { - mDrawerListLeft.smoothScrollToPosition(mWebViewList.size() - 1); + mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); } }, 300); @@ -1053,49 +1054,47 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } private synchronized void deleteTab(int position) { - if (position >= mWebViewList.size()) { + final LightningView reference = tabsManager.getTabAtPosition(position); + if (reference == null) { return; } - int current = mWebViewList.indexOf(mCurrentView); +// What? + int current = tabsManager.getPositionForTab(mCurrentView); if (current < 0) { return; } - LightningView reference = mWebViewList.get(position); - if (reference == null) { - return; - } if (!reference.getUrl().startsWith(Constants.FILE) && !isIncognito()) { mPreferences.setSavedUrl(reference.getUrl()); } - boolean isShown = reference.isShown(); + final boolean isShown = reference.isShown(); if (isShown) { mBrowserFrame.setBackgroundColor(mBackgroundColor); } if (current > position) { - mWebViewList.remove(position); - showTab(mWebViewList.get(current - 1)); + tabsManager.deleteTab(position); + showTab(tabsManager.getTabAtPosition(current - 1)); updateTabs(); reference.onDestroy(); - } else if (mWebViewList.size() > position + 1) { + } else if (tabsManager.size() > position + 1) { if (current == position) { - showTab(mWebViewList.get(position + 1)); - mWebViewList.remove(position); - showTab(mWebViewList.get(position)); + showTab(tabsManager.getTabAtPosition(position + 1)); + tabsManager.deleteTab(position); + showTab(tabsManager.getTabAtPosition(position)); updateTabs(); } 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); - showTab(mWebViewList.get(position - 1)); + showTab(tabsManager.getTabAtPosition(position - 1)); + tabsManager.deleteTab(position); + showTab(tabsManager.getTabAtPosition(position - 1)); updateTabs(); } else { - mWebViewList.remove(position); + tabsManager.deleteTab(position); } reference.onDestroy(); @@ -1103,7 +1102,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (mCurrentView.getUrl().startsWith(Constants.FILE) || mCurrentView.getUrl().equals(mHomepage)) { closeActivity(); } else { - mWebViewList.remove(position); + tabsManager.deleteTab(position); performExitCleanUp(); reference.pauseTimers(); reference.onDestroy(); @@ -1150,7 +1149,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - showCloseDialog(mWebViewList.indexOf(mCurrentView)); + showCloseDialog(tabsManager.positionOf(mCurrentView)); } return true; } @@ -1160,12 +1159,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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(); + tabsManager.shutdown(); mTabAdapter.notifyDataSetChanged(); finish(); } @@ -1189,7 +1183,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mCurrentView.goBack(); } } else { - deleteTab(mWebViewList.indexOf(mCurrentView)); + deleteTab(tabsManager.positionOf(mCurrentView)); } } else { Log.e(Constants.TAG, "This shouldn't happen ever"); @@ -1220,12 +1214,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements void saveOpenTabs() { if (mPreferences.getRestoreLostTabsEnabled()) { - String s = ""; - for (int n = 0, size = mWebViewList.size(); n < size; n++) { - if (!mWebViewList.get(n).getUrl().isEmpty()) { - s = s + mWebViewList.get(n).getUrl() + "|$|SEPARATOR|$|"; - } - } + final String s = tabsManager.tabsString(); mPreferences.setMemoryUrl(s); } } @@ -1266,13 +1255,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } 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(); @@ -1984,7 +1967,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Override public void onCloseWindow(LightningView view) { - deleteTab(mWebViewList.indexOf(view)); + deleteTab(tabsManager.positionOf(view)); } /** @@ -2278,7 +2261,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (mCurrentView.canGoBack()) { mCurrentView.goBack(); } else { - deleteTab(mWebViewList.indexOf(mCurrentView)); + deleteTab(tabsManager.positionOf(mCurrentView)); } } break; @@ -2353,11 +2336,7 @@ 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); } }; 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..aaf4e26 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -0,0 +1,172 @@ +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 acr.browser.lightning.controller.BrowserController; +import acr.browser.lightning.view.LightningView; + +/** + * @author Stefano Pacifici + * @date 2015/09/14 + */ +public class TabsManager { + + private final List mWebViewList = new ArrayList<>(); + + @Inject + public TabsManager() { + } + + /** + * 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 + * @param controller + * @return + */ + public synchronized LightningView newTab(final Activity activity, + final String url, final boolean darkTheme, + final boolean isIncognito, + final BrowserController controller) { + final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito, controller); + 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); + // TODO This should not be done outside this call + // tab.onDestroy(); + return tab; + } + + /** + * TODO I think it should be removed + * 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(); + } + + /** + * TODO Remove this, temporary workaround + * @param tab + * @return + */ + public int getPositionForTab(final LightningView tab) { + return mWebViewList.indexOf(tab); + } +} From f0c3b743d48d3e75b15bcbe057eb15d0131f52ac Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 14 Sep 2015 14:19:07 +0200 Subject: [PATCH 03/58] CurrentTab reference removed from BrowserActivity --- .../lightning/activity/BrowserActivity.java | 255 ++++++++++-------- .../lightning/activity/TabsManager.java | 16 ++ 2 files changed, 157 insertions(+), 114 deletions(-) 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 969afc0..9f40851 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -137,7 +137,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private RelativeLayout mSearchBar; // List - private LightningView mCurrentView; + // private LightningView mCurrentView; private WebView mWebView; // Views @@ -387,8 +387,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: @@ -409,8 +410,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; } @@ -419,15 +421,16 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onFocusChange(View v, final boolean hasFocus) { - if (!hasFocus && mCurrentView != null) { - if (mCurrentView.getProgress() < 100) { + final LightningView currentView = tabsManager.getCurrentTab(); + if (!hasFocus && currentView != null) { + if (currentView.getProgress() < 100) { setIsLoading(); } else { setIsFinishedLoading(); } - updateUrl(mCurrentView.getUrl(), true); + updateUrl(currentView.getUrl(), true); } else if (hasFocus) { - String url = mCurrentView.getUrl(); + String url = currentView.getUrl(); if (url.startsWith(Constants.FILE)) { mSearch.setText(""); } else { @@ -616,6 +619,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } private void initializePreferences() { + final LightningView currentView = tabsManager.getCurrentTab(); if (mPreferences == null) { mPreferences = PreferenceManager.getInstance(); } @@ -624,9 +628,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mColorMode &= !mDarkTheme; if (!isIncognito() && !mColorMode && !mDarkTheme && mWebpageBitmap != null) { changeToolbarBackground(mWebpageBitmap, null); - } else if (!isIncognito() && mCurrentView != null && !mDarkTheme - && mCurrentView.getFavicon() != null) { - changeToolbarBackground(mCurrentView.getFavicon(), null); + } else if (!isIncognito() && currentView != null && !mDarkTheme + && currentView.getFavicon() != null) { + changeToolbarBackground(currentView.getFavicon(), null); } if (mFullScreen) { @@ -729,6 +733,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: @@ -737,13 +742,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: @@ -754,11 +759,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; @@ -766,9 +771,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(mActivity, R.string.message_link_copied); } @@ -780,9 +785,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)) { - eventBus.post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(), - mCurrentView.getUrl())); + if (currentView != null && !currentView.getUrl().startsWith(Constants.FILE)) { + eventBus.post(new BrowserEvents.AddBookmark(currentView.getTitle(), + currentView.getUrl())); } return true; case R.id.action_find: @@ -790,7 +795,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: @@ -822,8 +827,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 = (RelativeLayout) findViewById(R.id.search_bar); mSearchBar.setVisibility(View.VISIBLE); @@ -876,9 +882,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onClick(View v) { + final LightningView currentTab = tabsManager.getCurrentTab(); final int position = mDrawerListLeft.getChildAdapterPosition(v); final LightningView tab = tabsManager.getTabAtPosition(position); - if (tab != null && mCurrentView != tab) { + if (tab != null && currentTab != tab) { mIsNewIntent = false; showTab(tab); } @@ -902,34 +909,35 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * displays the WebView contained in the LightningView Also handles the * removal of previous views * - * @param view the LightningView to show + * @param newView the LightningView to show */ - private synchronized void showTab(LightningView view) { + private synchronized void showTab(LightningView newView) { + final LightningView currentView = tabsManager.getCurrentTab(); // Set the background color so the color mode color doesn't show through mBrowserFrame.setBackgroundColor(mBackgroundColor); - if (view == null) { + if (newView == null) { return; } 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); + tabsManager.setCurrentTab(newView); + mWebView = newView.getWebView(); + newView.setForegroundTab(true); if (mWebView != null) { - updateUrl(mCurrentView.getUrl(), true); - updateProgress(mCurrentView.getProgress()); + updateUrl(newView.getUrl(), true); + updateProgress(newView.getProgress()); } else { updateUrl("", true); updateProgress(0); } mBrowserFrame.addView(mWebView, MATCH_PARENT); - mCurrentView.requestFocus(); - mCurrentView.onResume(); + newView.requestFocus(); + newView.onResume(); if (mFullScreen) { // mToolbarLayout has already been removed @@ -960,7 +968,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements }, 200); // Should update the bookmark status in BookmarksFragment - eventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); + eventBus.post(new BrowserEvents.CurrentPageUrl(newView.getUrl())); // new Handler().postDelayed(new Runnable() { // @Override @@ -998,12 +1006,13 @@ 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); eventBus.post(new BrowserEvents.CurrentPageUrl(url)); } @@ -1054,20 +1063,22 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } private synchronized void deleteTab(int position) { - final LightningView reference = tabsManager.getTabAtPosition(position); - if (reference == null) { + final LightningView tabToDelete = tabsManager.getTabAtPosition(position); + final LightningView currentTab = tabsManager.getCurrentTab(); + + if (tabToDelete == null) { return; } // What? - int current = tabsManager.getPositionForTab(mCurrentView); + int current = tabsManager.getPositionForTab(currentTab); if (current < 0) { return; } - if (!reference.getUrl().startsWith(Constants.FILE) && !isIncognito()) { - mPreferences.setSavedUrl(reference.getUrl()); + if (!tabToDelete.getUrl().startsWith(Constants.FILE) && !isIncognito()) { + mPreferences.setSavedUrl(tabToDelete.getUrl()); } - final boolean isShown = reference.isShown(); + final boolean isShown = tabToDelete.isShown(); if (isShown) { mBrowserFrame.setBackgroundColor(mBackgroundColor); } @@ -1075,7 +1086,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements tabsManager.deleteTab(position); showTab(tabsManager.getTabAtPosition(current - 1)); updateTabs(); - reference.onDestroy(); + tabToDelete.onDestroy(); } else if (tabsManager.size() > position + 1) { if (current == position) { showTab(tabsManager.getTabAtPosition(position + 1)); @@ -1086,7 +1097,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements tabsManager.deleteTab(position); } - reference.onDestroy(); + tabToDelete.onDestroy(); } else if (tabsManager.size() > 1) { if (current == position) { showTab(tabsManager.getTabAtPosition(position - 1)); @@ -1097,16 +1108,15 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements tabsManager.deleteTab(position); } - reference.onDestroy(); + tabToDelete.onDestroy(); } else { - if (mCurrentView.getUrl().startsWith(Constants.FILE) || mCurrentView.getUrl().equals(mHomepage)) { + if (currentTab.getUrl().startsWith(Constants.FILE) || currentTab.getUrl().equals(mHomepage)) { closeActivity(); } else { tabsManager.deleteTab(position); performExitCleanUp(); - reference.pauseTimers(); - reference.onDestroy(); - mCurrentView = null; + tabToDelete.pauseTimers(); + tabToDelete.onDestroy(); mWebView = null; mTabAdapter.notifyDataSetChanged(); finish(); @@ -1123,8 +1133,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"); } @@ -1148,8 +1159,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(tabsManager.positionOf(mCurrentView)); + showCloseDialog(tabsManager.positionOf(currentTab)); } return true; } @@ -1157,7 +1169,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private void closeBrowser() { mBrowserFrame.setBackgroundColor(mBackgroundColor); performExitCleanUp(); - mCurrentView = null; mWebView = null; tabsManager.shutdown(); mTabAdapter.notifyDataSetChanged(); @@ -1166,24 +1177,25 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onBackPressed() { + final LightningView currentTab = tabsManager.getCurrentTab(); if (mDrawerLayout.isDrawerOpen(mDrawerLeft)) { mDrawerLayout.closeDrawer(mDrawerLeft); } else if (mDrawerLayout.isDrawerOpen(mDrawerRight)) { eventBus .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(tabsManager.positionOf(mCurrentView)); + deleteTab(tabsManager.positionOf(currentTab)); } } else { Log.e(Constants.TAG, "This shouldn't happen ever"); @@ -1195,10 +1207,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); @@ -1244,14 +1257,15 @@ 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(); @@ -1271,13 +1285,14 @@ 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)); } } @@ -1496,6 +1511,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; } @@ -1511,8 +1527,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); } @@ -1564,7 +1580,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); @@ -1583,8 +1599,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"); @@ -1798,6 +1814,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onShowCustomView(View view, CustomViewCallback callback) { + final LightningView currentTab = tabsManager.getCurrentTab(); if (view == null) { return; } @@ -1817,7 +1834,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(); @@ -1830,11 +1847,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) { @@ -1984,6 +2002,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Override public void hideActionBar() { + final LightningView currentTab = tabsManager.getCurrentTab(); if (mFullScreen) { if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) { mUiLayout.removeView(mToolbarLayout); @@ -1993,7 +2012,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.setTranslationY(0); mWebView.setTranslationY(mToolbarLayout.getHeight()); } - if (mToolbarLayout == null || mCurrentView == null) + if (mToolbarLayout == null || currentTab == null) return; final int height = mToolbarLayout.getHeight(); @@ -2040,7 +2059,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.setTranslationY(0); mWebView.setTranslationY(height); } - if (mCurrentView == null) + final LightningView currentTab = tabsManager.getCurrentTab(); + if (currentTab == null) return; final WebView view = mWebView; @@ -2119,6 +2139,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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); @@ -2131,7 +2152,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements break; case DialogInterface.BUTTON_NEUTRAL: - if (mCurrentView != null) { + if (currentTab != null) { loadUrlInCurrentView(url); } break; @@ -2153,6 +2174,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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); @@ -2165,7 +2187,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements case DialogInterface.BUTTON_NEUTRAL: if (API > 8) { Utils.downloadFile(mActivity, url, - mCurrentView.getUserAgent(), "attachment"); + currentTab.getUserAgent(), "attachment"); } break; } @@ -2244,41 +2266,43 @@ 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(); } } } @Override public void onClick(View v) { + final LightningView currentTab = tabsManager.getCurrentTab(); switch (v.getId()) { case R.id.action_back: - if (mCurrentView != null) { - if (mCurrentView.canGoBack()) { - mCurrentView.goBack(); + if (currentTab != null) { + if (currentTab.canGoBack()) { + currentTab.goBack(); } else { - deleteTab(tabsManager.positionOf(mCurrentView)); + deleteTab(tabsManager.positionOf(currentTab)); } } break; case R.id.action_forward: - if (mCurrentView != null) { - if (mCurrentView.canGoForward()) { - mCurrentView.goForward(); + if (currentTab != null) { + if (currentTab.canGoForward()) { + currentTab.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: @@ -2296,12 +2320,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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; } @@ -2386,8 +2410,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Subscribe public void bookmarkCurrentPage(final BookmarkEvents.WantToBookmarkCurrentPage event) { - if (mCurrentView != null) { - eventBus.post(new BrowserEvents.AddBookmark(mCurrentView.getTitle(), mCurrentView.getUrl())); + final LightningView currentTab = tabsManager.getCurrentTab(); + if (currentTab != null) { + eventBus.post(new BrowserEvents.AddBookmark(currentTab.getTitle(), currentTab.getUrl())); } } @@ -2409,12 +2434,13 @@ 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)) { + final LightningView currentTab = tabsManager.getCurrentTab(); + if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) + && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { openBookmarkPage(mWebView); } - if (mCurrentView != null) { - eventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); + if (currentTab != null) { + eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); } } @@ -2425,12 +2451,13 @@ 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)) { + final LightningView currentTab = tabsManager.getCurrentTab(); + if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) + && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { openBookmarkPage(mWebView); } - if (mCurrentView != null) { - eventBus.post(new BrowserEvents.CurrentPageUrl(mCurrentView.getUrl())); + if (currentTab != null) { + eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); } } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index aaf4e26..0e46366 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -20,6 +20,7 @@ import acr.browser.lightning.view.LightningView; public class TabsManager { private final List mWebViewList = new ArrayList<>(); + private LightningView mCurrentTab; @Inject public TabsManager() { @@ -169,4 +170,19 @@ public class TabsManager { public int getPositionForTab(final LightningView tab) { return mWebViewList.indexOf(tab); } + + /** + * TODO We should remove also this + * @return + */ + public LightningView getCurrentTab() { + return mCurrentTab; + } + + /** + * TODO We should remove also this + */ + public void setCurrentTab(final LightningView tab) { + mCurrentTab = tab; + } } From 74073178bfa7513939297752520a53c32315ddd4 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 14 Sep 2015 14:41:11 +0200 Subject: [PATCH 04/58] mWebView reference removed from BrowserActivity --- .../lightning/activity/BrowserActivity.java | 74 +++++++++++-------- .../lightning/activity/TabsManager.java | 9 +++ 2 files changed, 51 insertions(+), 32 deletions(-) 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 9f40851..dfee365 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -136,10 +136,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private RelativeLayout mSearchBar; - // List - // private LightningView mCurrentView; - private WebView mWebView; - // Views private AnimatedProgressBar mProgressBar; private AutoCompleteTextView mSearch; @@ -620,6 +616,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private void initializePreferences() { final LightningView currentView = tabsManager.getCurrentTab(); + final WebView currentWebView = currentView.getWebView(); if (mPreferences == null) { mPreferences = PreferenceManager.getInstance(); } @@ -640,8 +637,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); @@ -655,8 +652,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); @@ -925,9 +922,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements currentView.onPause(); } tabsManager.setCurrentTab(newView); - mWebView = newView.getWebView(); + final WebView currentWebView = currentView.getWebView(); newView.setForegroundTab(true); - if (mWebView != null) { + if (currentWebView != null) { updateUrl(newView.getUrl(), true); updateProgress(newView.getProgress()); } else { @@ -935,7 +932,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements updateProgress(0); } - mBrowserFrame.addView(mWebView, MATCH_PARENT); + mBrowserFrame.addView(currentWebView, MATCH_PARENT); newView.requestFocus(); newView.onResume(); @@ -949,10 +946,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); height = mToolbarLayout.getMeasuredHeight(); } - mWebView.setTranslationY(translation + height); + currentWebView.setTranslationY(translation + height); mToolbarLayout.setTranslationY(translation); } else { - mWebView.setTranslationY(0); + currentWebView.setTranslationY(0); } showActionBar(); @@ -1018,7 +1015,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void closeEmptyTab() { - if (mWebView != null && mWebView.copyBackForwardList().getSize() == 0) { + final WebView currentWebView = tabsManager.getCurrentWebView(); + if (currentWebView != null && currentWebView.copyBackForwardList().getSize() == 0) { closeCurrentTab(); } } @@ -1117,7 +1115,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements performExitCleanUp(); tabToDelete.pauseTimers(); tabToDelete.onDestroy(); - mWebView = null; mTabAdapter.notifyDataSetChanged(); finish(); } @@ -1169,7 +1166,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private void closeBrowser() { mBrowserFrame.setBackgroundColor(mBackgroundColor); performExitCleanUp(); - mWebView = null; tabsManager.shutdown(); mTabAdapter.notifyDataSetChanged(); finish(); @@ -1808,7 +1804,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements Message click = mClickHandler.obtainMessage(); if (click != null) { click.setTarget(mClickHandler); - mWebView.requestFocusNodeHref(click); + final WebView currentWebView = tabsManager.getCurrentWebView(); + if (currentWebView != null) { + currentWebView.requestFocusNodeHref(click); + } } } @@ -1972,8 +1971,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(); } } @@ -2003,6 +2004,7 @@ 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); @@ -2010,13 +2012,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 || 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 @@ -2030,7 +2032,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements show.setDuration(250); show.setInterpolator(new DecelerateInterpolator()); // show.setFillAfter(true); - mWebView.startAnimation(show); + currentWebView.startAnimation(show); } } } @@ -2041,6 +2043,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void showActionBar() { if (mFullScreen) { + final WebView view = tabsManager.getCurrentWebView(); if (mToolbarLayout == null) return; @@ -2057,13 +2060,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); + } } 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() { @@ -2079,7 +2083,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements show.setDuration(250); show.setInterpolator(new DecelerateInterpolator()); // show.setFillAfter(true); - mWebView.startAnimation(show); + if (view != null) { + view.startAnimation(show); + } } } } @@ -2093,9 +2099,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements public void longClickPage(final String url) { HitTestResult result = null; String currentUrl = null; - if (mWebView != null) { - result = mWebView.getHitTestResult(); - currentUrl = mWebView.getUrl(); + final WebView currentWebView = tabsManager.getCurrentWebView(); + if (currentWebView != null) { + result = currentWebView.getHitTestResult(); + currentUrl = currentWebView.getUrl(); } if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) { if (currentUrl.endsWith(HistoryPage.FILENAME)) { @@ -2279,6 +2286,7 @@ 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 (currentTab != null) { @@ -2309,13 +2317,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements newTab(null, true); 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: @@ -2435,9 +2443,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @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)) { - openBookmarkPage(mWebView); + openBookmarkPage(currentWebView); } if (currentTab != null) { eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); @@ -2452,9 +2461,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @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)) { - openBookmarkPage(mWebView); + openBookmarkPage(currentWebView); } if (currentTab != null) { eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 0e46366..1c7d0fd 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -171,6 +171,15 @@ public class TabsManager { return mWebViewList.indexOf(tab); } + /** + * 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 * @return From 51f783cea435f01dd5c3f597d857854a31a726b1 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 14 Sep 2015 17:58:21 +0200 Subject: [PATCH 05/58] TabsFragment extracted --- .../lightning/activity/BrowserActivity.java | 290 ++++-------------- .../lightning/activity/TabsManager.java | 26 +- .../browser/lightning/app/AppComponent.java | 3 + .../browser/lightning/bus/BrowserEvents.java | 6 + .../acr/browser/lightning/bus/TabEvents.java | 49 +++ .../lightning/fragment/TabsFragment.java | 281 +++++++++++++++++ app/src/main/res/layout/activity_main.xml | 7 +- app/src/main/res/layout/tab_drawer.xml | 6 +- app/src/main/res/layout/tab_strip.xml | 9 + app/src/main/res/layout/toolbar.xml | 7 +- 10 files changed, 447 insertions(+), 237 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/bus/TabEvents.java create mode 100644 app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java create mode 100644 app/src/main/res/layout/tab_strip.xml 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 dfee365..d235410 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -106,6 +106,7 @@ 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.TabEvents; import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.HistoryPage; @@ -113,6 +114,7 @@ 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.fragment.TabsFragment; import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.preference.PreferenceManager; @@ -132,7 +134,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private DrawerLayout mDrawerLayout; private FrameLayout mBrowserFrame; private FullscreenHolder mFullscreenContainer; - private RecyclerView mDrawerListLeft; private ViewGroup mDrawerLeft, mDrawerRight, mUiLayout, mToolbarLayout; private RelativeLayout mSearchBar; @@ -144,7 +145,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private View mCustomView; // Adapter - private LightningViewAdapter mTabAdapter; private SearchAdapter mSearchAdapter; // Callback @@ -247,7 +247,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mUiLayout = (LinearLayout) findViewById(R.id.ui_layout); mProgressBar = (AnimatedProgressBar) findViewById(R.id.progress_view); setupFrameLayoutButton(R.id.new_tab_button, R.id.icon_plus); - mDrawerLeft = (LinearLayout) findViewById(R.id.left_drawer); + mDrawerLeft = (FrameLayout) findViewById(R.id.left_drawer); // Drawer stutters otherwise mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); @@ -267,29 +267,19 @@ 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 arguments = new Bundle(); + arguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer); + tabsFragment.setArguments(arguments); + getSupportFragmentManager() + .beginTransaction() + .add(containerId, tabsFragment) + .commit(); if (mShowTabsInDrawer) { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item, tabsManager.getTabsList()); - mDrawerListLeft = (RecyclerView) findViewById(R.id.left_drawer_list); - mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_IF_CONTENT_SCROLLS); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); - mDrawerListLeft.setLayoutManager(layoutManager); - mDrawerListLeft.setHasFixedSize(true); - mToolbarLayout.removeView(horizontalListView); - } else { - mTabAdapter = new LightningViewAdapter(this, R.layout.tab_list_item_horizontal, tabsManager.getTabsList()); - mDrawerListLeft = horizontalListView; - mDrawerListLeft.setOverScrollMode(View.OVER_SCROLL_NEVER); - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, mDrawerLeft); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); - mDrawerListLeft.setLayoutManager(layoutManager); - mDrawerListLeft.setHasFixedSize(true); + mToolbarLayout.removeView(findViewById(R.id.tabs_toolbar_container)); } - mDrawerListLeft.setAdapter(mTabAdapter); - mHistoryDatabase = HistoryDatabase.getInstance(); if (actionBar == null) @@ -872,56 +862,29 @@ 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) { - final LightningView currentTab = tabsManager.getCurrentTab(); - final int position = mDrawerListLeft.getChildAdapterPosition(v); - final LightningView tab = tabsManager.getTabAtPosition(position); - if (tab != null && currentTab != tab) { - mIsNewIntent = false; - showTab(tab); - } - } - } - - /** - * long click listener for Navigation Drawer - */ - private class DrawerItemLongClickListener implements OnLongClickListener { - - @Override - public boolean onLongClick(View v) { - int position = mDrawerListLeft.getChildAdapterPosition(v); - showCloseDialog(position); - return true; - } - } - /** * displays the WebView contained in the LightningView Also handles the * removal of previous views * - * @param newView the LightningView to show + * @param position the poition of the tab to display */ - private synchronized void showTab(LightningView newView) { + private synchronized void showTab(final int position) { final LightningView currentView = tabsManager.getCurrentTab(); + final LightningView newView = tabsManager.switchToTab(position); + // Set the background color so the color mode color doesn't show through mBrowserFrame.setBackgroundColor(mBackgroundColor); - if (newView == null) { + if (newView == null || currentView == newView) { return; } + mIsNewIntent = false; + final float translation = mToolbarLayout.getTranslationY(); mBrowserFrame.removeAllViews(); if (currentView != null) { currentView.setForegroundTab(false); currentView.onPause(); } - tabsManager.setCurrentTab(newView); final WebView currentWebView = currentView.getWebView(); newView.setForegroundTab(true); if (currentWebView != null) { @@ -1047,15 +1010,17 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mIdGenerator++; if (show) { - showTab(startingTab); + showTab(tabsManager.size() - 1); } updateTabs(); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); - } - }, 300); + +// TODO Restore this +// new Handler().postDelayed(new Runnable() { +// @Override +// public void run() { +// mDrawerListLeft.smoothScrollToPosition(tabsManager.size() - 1); +// } +// }, 300); return true; } @@ -1082,14 +1047,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } if (current > position) { tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(current - 1)); + showTab(current - 1); updateTabs(); tabToDelete.onDestroy(); } else if (tabsManager.size() > position + 1) { if (current == position) { - showTab(tabsManager.getTabAtPosition(position + 1)); + showTab(position + 1); tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(position)); + showTab(position); updateTabs(); } else { tabsManager.deleteTab(position); @@ -1098,9 +1063,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements tabToDelete.onDestroy(); } else if (tabsManager.size() > 1) { if (current == position) { - showTab(tabsManager.getTabAtPosition(position - 1)); + showTab(position - 1); tabsManager.deleteTab(position); - showTab(tabsManager.getTabAtPosition(position - 1)); + showTab(position - 1); updateTabs(); } else { tabsManager.deleteTab(position); @@ -1115,11 +1080,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements performExitCleanUp(); tabToDelete.pauseTimers(); tabToDelete.onDestroy(); - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); finish(); } } - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); if (mIsNewIntent && isShown) { mIsNewIntent = false; @@ -1167,7 +1132,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mBrowserFrame.setBackgroundColor(mBackgroundColor); performExitCleanUp(); tabsManager.shutdown(); - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); finish(); } @@ -1293,157 +1258,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - public 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(mActivity), 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 { - 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 { - 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 { - holder.txtTitle.setTextAppearance(context, 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 (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 @@ -1684,7 +1498,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void updateTabs() { - mTabAdapter.notifyDataSetChanged(); + eventBus.post(new BrowserEvents.TabsChanged()); } /** @@ -2482,5 +2296,33 @@ 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 + */ + 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 + */ + public void showCloseDialog(final TabEvents.ShowCloseDialog event) { + BrowserActivity.this.showCloseDialog(event.position); + } }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 1c7d0fd..3f3a994 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -181,7 +181,7 @@ public class TabsManager { } /** - * TODO We should remove also this + * TODO We should remove also this, but probably not * @return */ public LightningView getCurrentTab() { @@ -189,9 +189,27 @@ public class TabsManager { } /** - * TODO We should remove also this + * 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 */ - public void setCurrentTab(final LightningView tab) { - mCurrentTab = tab; + @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; + } } + +// /** +// * TODO We should remove also this +// */ +// public void setCurrentTab(final LightningView tab) { +// mCurrentTab = tab; +// } } 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..a3927bf 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,6 +7,7 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.fragment.BookmarkSettingsFragment; import acr.browser.lightning.fragment.BookmarksFragment; +import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.object.SearchAdapter; import dagger.Component; @@ -28,4 +29,6 @@ public interface AppComponent { void inject(BookmarksDialogBuilder builder); void inject(BookmarkPage bookmarkPage); + + void inject(TabsFragment fragment); } 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..696f103 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -41,4 +41,10 @@ public final class BrowserEvents { */ public static class UserPressedBack { } + + /** + * Notify that the user closed or opened a tab + */ + public static class TabsChanged { + } } 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..5fd4118 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java @@ -0,0 +1,49 @@ +package acr.browser.lightning.bus; + +/** + * @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; + } + } +} 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..d42aeb3 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -0,0 +1,281 @@ +package acr.browser.lightning.fragment; + +import android.content.Context; +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.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.view.ViewCompat; +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.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.TabEvents; +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 { + + 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"; + + private boolean mDarkTheme = false; // TODO Only temporary + private int mIconColor = 0; // TODO Only temporary + private boolean mColorMode = true; // TODO Only temporary + private boolean isIncognito = false; // TODO Only temporary + private int mCurrentUiColor = 0; // TODO Only temporary + + private RecyclerView mRecyclerView; + private LightningViewAdapter mTabsAdapter; + + @Inject + TabsManager tabsManager; + + @Inject + Bus bus; + + public TabsFragment() { + BrowserApp.getAppComponent().inject(this); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final Bundle arguments = getArguments(); + final boolean vertical = arguments.getBoolean(VERTICAL_MODE, true); + final View view; + final LayoutManager layoutManager; + if (vertical) { + view = inflater.inflate(R.layout.tab_drawer, container, false); + layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + } 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(vertical); + mRecyclerView.setAdapter(mTabsAdapter); + mRecyclerView.setHasFixedSize(true); + return view; + } + + @Override + public void onDestroyView() { + mRecyclerView = null; + mTabsAdapter = null; + } + + @Override + public void onStart() { + super.onStart(); + bus.register(this); + } + + @Override + public void onStop() { + super.onStop(); + bus.unregister(this); + } + + @Subscribe + public void tabsChanged(final BrowserEvents.TabsChanged event) { + if (mTabsAdapter != null) { + mTabsAdapter.notifyDataSetChanged(); + } + } + + 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 (!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 { + holder.layout.setBackgroundDrawable(foregroundDrawable); + } + if (!isIncognito && mColorMode) { + // TODO Restore this + // 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; + } + + 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/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 31777df..655df01 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -25,7 +25,12 @@ - + + 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"/> Date: Tue, 15 Sep 2015 14:24:31 +0200 Subject: [PATCH 06/58] In the middle of events rewiring (back/forward) --- .../lightning/activity/BrowserActivity.java | 76 ++++++++++--------- .../lightning/activity/TabsManager.java | 9 +-- .../lightning/bus/NavigationEvents.java | 25 ++++++ .../acr/browser/lightning/bus/TabEvents.java | 7 ++ .../lightning/fragment/TabsFragment.java | 49 +++++++++++- app/src/main/res/layout/activity_main.xml | 4 +- app/src/main/res/layout/tab_drawer.xml | 4 +- 7 files changed, 127 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java 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 d235410..93a5221 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -235,8 +235,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet()); mActivity = this; - // TODO Stefano, check this - // mWebViewList.clear(); mClickHandler = new ClickHandler(this); mBrowserFrame = (FrameLayout) findViewById(R.id.content_frame); @@ -246,15 +244,15 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mUiLayout = (LinearLayout) findViewById(R.id.ui_layout); mProgressBar = (AnimatedProgressBar) findViewById(R.id.progress_view); - setupFrameLayoutButton(R.id.new_tab_button, R.id.icon_plus); mDrawerLeft = (FrameLayout) findViewById(R.id.left_drawer); // Drawer stutters otherwise mDrawerLeft.setLayerType(View.LAYER_TYPE_HARDWARE, null); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerRight = (ViewGroup) findViewById(R.id.right_drawer); mDrawerRight.setLayerType(View.LAYER_TYPE_HARDWARE, null); - ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon); - tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); +// TODO Probably should be moved to the TabsFragement +// 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); @@ -313,10 +311,8 @@ 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_toggle_desktop, R.id.icon_desktop); // create the search EditText in the ToolBar mSearch = (AutoCompleteTextView) actionBar.getCustomView().findViewById(R.id.search); @@ -870,7 +866,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ 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); @@ -885,7 +883,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements currentView.setForegroundTab(false); currentView.onPause(); } - final WebView currentWebView = currentView.getWebView(); newView.setForegroundTab(true); if (currentWebView != null) { updateUrl(newView.getUrl(), true); @@ -895,7 +892,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements updateProgress(0); } - mBrowserFrame.addView(currentWebView, MATCH_PARENT); + mBrowserFrame.addView(newWebView, MATCH_PARENT); newView.requestFocus(); newView.onResume(); @@ -909,10 +906,10 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); height = mToolbarLayout.getMeasuredHeight(); } - currentWebView.setTranslationY(translation + height); + newWebView.setTranslationY(translation + height); mToolbarLayout.setTranslationY(translation); } else { - currentWebView.setTranslationY(0); + newWebView.setTranslationY(0); } showActionBar(); @@ -2102,22 +2099,23 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final LightningView currentTab = tabsManager.getCurrentTab(); final WebView currentWebView = currentTab.getWebView(); switch (v.getId()) { - case R.id.action_back: - if (currentTab != null) { - if (currentTab.canGoBack()) { - currentTab.goBack(); - } else { - deleteTab(tabsManager.positionOf(currentTab)); - } - } - break; - case R.id.action_forward: - if (currentTab != null) { - if (currentTab.canGoForward()) { - currentTab.goForward(); - } - } - break; +// TODO Remove this +// case R.id.action_back: +// if (currentTab != null) { +// if (currentTab.canGoBack()) { +// currentTab.goBack(); +// } else { +// deleteTab(tabsManager.positionOf(currentTab)); +// } +// } +// break; +// case R.id.action_forward: +// if (currentTab != null) { +// if (currentTab.canGoForward()) { +// currentTab.goForward(); +// } +// } +// break; case R.id.arrow_button: if (mSearch != null && mSearch.hasFocus()) { currentTab.requestFocus(); @@ -2127,9 +2125,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements currentTab.loadHomepage(); } break; - case R.id.new_tab_button: - newTab(null, true); - break; case R.id.button_next: currentWebView.findNext(false); break; @@ -2168,11 +2163,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements return true; } + // TODO Check if all the calls are relative to TabsFragement 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); } @@ -2219,7 +2215,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Subscribe public void loadBookmarkInNewTab(final BookmarkEvents.AsNewTab event) { - newTab(event.bookmark.getUrl(), true); + BrowserActivity.this.newTab(event.bookmark.getUrl(), true); mDrawerLayout.closeDrawers(); } @@ -2312,6 +2308,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * * @param event contains the tab position in the tabs adapter */ + @Subscribe public void showTab(final TabEvents.ShowTab event) { BrowserActivity.this.showTab(event.position); } @@ -2321,8 +2318,19 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * * @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); + } }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 3f3a994..d4cf26b 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -9,6 +9,7 @@ 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.view.LightningView; @@ -17,6 +18,7 @@ import acr.browser.lightning.view.LightningView; * @author Stefano Pacifici * @date 2015/09/14 */ +@Singleton public class TabsManager { private final List mWebViewList = new ArrayList<>(); @@ -205,11 +207,4 @@ public class TabsManager { return tab; } } - -// /** -// * TODO We should remove also this -// */ -// public void setCurrentTab(final LightningView tab) { -// mCurrentTab = tab; -// } } 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..2bdaded --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java @@ -0,0 +1,25 @@ +package acr.browser.lightning.bus; + +/** + * @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 teh user presses forward + * button. + */ + public static class GoForward { + } +} diff --git a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java index 5fd4118..f219da6 100644 --- a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java @@ -46,4 +46,11 @@ public final class TabEvents { this.position = position; } } + + /** + * Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user want to create a + * new tab. + */ + public static class NewTab { + } } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index d42aeb3..7a2a30c 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -13,6 +13,8 @@ import android.graphics.drawable.BitmapDrawable; 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; @@ -38,6 +40,7 @@ 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.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; @@ -47,7 +50,7 @@ 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 { +public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { private static final String TAG = TabsFragment.class.getSimpleName(); @@ -86,6 +89,11 @@ public class TabsFragment extends Fragment { if (vertical) { view = inflater.inflate(R.layout.tab_drawer, container, false); layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + // TODO Handle also long press + 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); + } else { view = inflater.inflate(R.layout.tab_strip, container, false); layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); @@ -98,6 +106,15 @@ public class TabsFragment extends Fragment { 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() { mRecyclerView = null; @@ -110,6 +127,13 @@ public class TabsFragment extends Fragment { bus.register(this); } + @Override + public void onResume() { + super.onResume(); + // Force adapter refresh + mTabsAdapter.notifyDataSetChanged(); + } + @Override public void onStop() { super.onStop(); @@ -123,6 +147,28 @@ public class TabsFragment extends Fragment { } } + @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; + default: + break; + } + } + + @Override + public boolean onLongClick(View v) { + return false; + } + public class LightningViewAdapter extends RecyclerView.Adapter { private final int layoutResourceId; @@ -277,5 +323,4 @@ public class TabsFragment extends Fragment { } } } - } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 655df01..5f87668 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -30,7 +30,9 @@ android:layout_height="match_parent" android:background="?attr/drawerBackground" android:id="@+id/left_drawer" - android:fitsSystemWindows="true" /> + android:fitsSystemWindows="true" + android:layout_gravity="start" + android:weightSum="1" /> Date: Tue, 15 Sep 2015 16:10:34 +0200 Subject: [PATCH 07/58] Back, Forward and Plus rewired --- .../lightning/activity/BrowserActivity.java | 76 ++++++++++++------- .../browser/lightning/bus/BookmarkEvents.java | 7 -- .../browser/lightning/bus/BrowserEvents.java | 5 +- .../lightning/bus/NavigationEvents.java | 2 + .../acr/browser/lightning/bus/TabEvents.java | 9 +++ .../lightning/fragment/TabsFragment.java | 25 +++++- 6 files changed, 84 insertions(+), 40 deletions(-) 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 93a5221..1309e9e 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -106,6 +106,7 @@ 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; @@ -269,6 +270,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container; final Bundle arguments = new Bundle(); arguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer); + arguments.putBoolean(TabsFragment.USE_DARK_THEME, mDarkTheme); tabsFragment.setArguments(arguments); getSupportFragmentManager() .beginTransaction() @@ -2099,23 +2101,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final LightningView currentTab = tabsManager.getCurrentTab(); final WebView currentWebView = currentTab.getWebView(); switch (v.getId()) { -// TODO Remove this -// case R.id.action_back: -// if (currentTab != null) { -// if (currentTab.canGoBack()) { -// currentTab.goBack(); -// } else { -// deleteTab(tabsManager.positionOf(currentTab)); -// } -// } -// break; -// case R.id.action_forward: -// if (currentTab != null) { -// if (currentTab.canGoForward()) { -// currentTab.goForward(); -// } -// } -// break; case R.id.arrow_button: if (mSearch != null && mSearch.hasFocus()) { currentTab.requestFocus(); @@ -2150,16 +2135,6 @@ 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(mActivity, R.string.deleted_tab); - } - mPreferences.setSavedUrl(null); - break; - } return true; } @@ -2332,5 +2307,52 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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(mActivity, R.string.deleted_tab); + } + mPreferences.setSavedUrl(null); + } }; } 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..7b8846d 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java @@ -61,13 +61,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 696f103..d461205 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -24,9 +24,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; diff --git a/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java b/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java index 2bdaded..732ca23 100644 --- a/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java @@ -1,6 +1,8 @@ package acr.browser.lightning.bus; /** + * Collections of navigation events, like go back or go forward + * * @author Stefano Pacifici * @date 2015/09/15 */ diff --git a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java index f219da6..a2bac5c 100644 --- a/app/src/main/java/acr/browser/lightning/bus/TabEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/TabEvents.java @@ -1,6 +1,8 @@ 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 */ @@ -53,4 +55,11 @@ public final class TabEvents { */ 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/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 7a2a30c..43738f1 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -59,9 +59,10 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View * 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 USE_DARK_THEME = TAG + ".USE_DARK_THEME"; - private boolean mDarkTheme = false; // TODO Only temporary - private int mIconColor = 0; // TODO Only temporary + private boolean mDarkTheme; + private int mIconColor; private boolean mColorMode = true; // TODO Only temporary private boolean isIncognito = false; // TODO Only temporary private int mCurrentUiColor = 0; // TODO Only temporary @@ -79,6 +80,17 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View BrowserApp.getAppComponent().inject(this); } + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Bundle arguments = getArguments(); + final Context context = getContext(); + mDarkTheme = arguments.getBoolean(USE_DARK_THEME, false); + mIconColor = mDarkTheme ? + ThemeUtils.getIconDarkThemeColor(context) : + ThemeUtils.getIconLightThemeColor(context); + } + @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -166,7 +178,14 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public boolean onLongClick(View v) { - return false; + 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 { From 5c2cf07e20211a25e6a3418acaa6fef8a1ea6857 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Wed, 16 Sep 2015 16:49:59 +0200 Subject: [PATCH 08/58] PreferenceManager injected --- .../browser/lightning/utils/ProxyUtils.java | 2 +- .../lightning/activity/BrowserActivity.java | 15 +-- .../lightning/activity/IncognitoActivity.java | 10 +- .../lightning/activity/MainActivity.java | 12 +- .../lightning/activity/ReadingActivity.java | 3 +- .../lightning/activity/TabsManager.java | 3 +- .../activity/ThemableBrowserActivity.java | 8 +- .../activity/ThemableSettingsActivity.java | 5 +- .../browser/lightning/app/AppComponent.java | 6 + .../browser/lightning/constant/StartPage.java | 5 +- .../lightning/download/DownloadHandler.java | 3 +- .../fragment/AdvancedSettingsFragment.java | 39 +++---- .../lightning/fragment/BookmarksFragment.java | 4 +- .../fragment/DisplaySettingsFragment.java | 40 ++++--- .../fragment/GeneralSettingsFragment.java | 104 +++++++++--------- .../fragment/LightningPreferenceFragment.java | 27 +++++ .../fragment/PrivacySettingsFragment.java | 34 +++--- .../lightning/fragment/TabsFragment.java | 1 + .../lightning/object/SearchAdapter.java | 5 +- .../preference/PreferenceManager.java | 18 ++- .../acr/browser/lightning/utils/AdBlock.java | 5 +- .../browser/lightning/view/LightningView.java | 8 +- 22 files changed, 194 insertions(+), 163 deletions(-) create mode 100644 app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java 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 269c185..3942f7d 100644 --- a/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java @@ -28,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()); } 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 1309e9e..2831051 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -169,7 +169,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements // Storage private HistoryDatabase mHistoryDatabase; - private PreferenceManager mPreferences; + // The singleton BookmarkManager @Inject @@ -188,6 +188,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Inject TabsManager tabsManager; + @Inject + PreferenceManager mPreferences; + // Image private Bitmap mWebpageBitmap; private final ColorDrawable mBackground = new ColorDrawable(); @@ -207,7 +210,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements public abstract boolean isIncognito(); - abstract void initializeTabs(); +// abstract void initializeTabs(); abstract void closeActivity(); @@ -229,7 +232,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements setSupportActionBar(toolbar); ActionBar actionBar = getSupportActionBar(); - mPreferences = PreferenceManager.getInstance(); //TODO make sure dark theme flag gets set correctly mDarkTheme = mPreferences.getUseTheme() != 0 || isIncognito(); mIconColor = mDarkTheme ? ThemeUtils.getIconDarkThemeColor(this) : ThemeUtils.getIconLightThemeColor(this); @@ -356,7 +358,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath()); } - initializeTabs(); +// initializeTabs(); mProxyUtils.checkForProxy(this); } @@ -565,6 +567,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } + /* TODO !!!! THIS MUST BY RESTORED ASAP !!!! void restoreOrNewTab() { mIdGenerator = 0; @@ -601,13 +604,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements newTab(url, true); } } + */ private void initializePreferences() { final LightningView currentView = tabsManager.getCurrentTab(); final WebView currentWebView = currentView.getWebView(); - if (mPreferences == null) { - mPreferences = PreferenceManager.getInstance(); - } mFullScreen = mPreferences.getFullScreenEnabled(); mColorMode = mPreferences.getColorModeEnabled(); mColorMode &= !mDarkTheme; 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 index d4cf26b..c3dd109 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -12,6 +12,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import acr.browser.lightning.controller.BrowserController; +import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.view.LightningView; /** @@ -25,7 +26,7 @@ public class TabsManager { private LightningView mCurrentTab; @Inject - public TabsManager() { + public TabsManager(final Context context, final PreferenceManager preferenceManager) { } /** 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 a09c20b..1ab4a62 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java @@ -15,8 +15,8 @@ public abstract class ThemableBrowserActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { - mTheme = PreferenceManager.getInstance().getUseTheme(); - mShowTabsInDrawer = PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet()); + mTheme = 0; //PreferenceManager.getInstance().getUseTheme(); + mShowTabsInDrawer = false; // PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet()); // set the theme if (mTheme == 1) { @@ -30,8 +30,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 = 0; // PreferenceManager.getInstance().getUseTheme(); + boolean drawerTabs = false; // PreferenceManager.getInstance().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 a3927bf..94e9682 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,8 +7,10 @@ import acr.browser.lightning.constant.BookmarkPage; import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.fragment.BookmarkSettingsFragment; import acr.browser.lightning.fragment.BookmarksFragment; +import acr.browser.lightning.fragment.LightningPreferenceFragment; import acr.browser.lightning.fragment.TabsFragment; import acr.browser.lightning.object.SearchAdapter; +import acr.browser.lightning.preference.PreferenceManager; import dagger.Component; /** @@ -31,4 +33,8 @@ public interface AppComponent { void inject(BookmarkPage bookmarkPage); void inject(TabsFragment fragment); + + PreferenceManager getPreferenceManager(); + + void inject(LightningPreferenceFragment fragment); } 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 118696f..144b146 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/download/DownloadHandler.java b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java index 191560c..4a715a7 100644 --- a/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java +++ b/app/src/main/java/acr/browser/lightning/download/DownloadHandler.java @@ -20,6 +20,7 @@ import android.webkit.CookieManager; import android.webkit.URLUtil; import acr.browser.lightning.R; +import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; @@ -170,7 +171,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(); request.setDestinationInExternalPublicDir(location, filename); // let this downloaded file be scanned by MediaScanner - so that it can // show up in Gallery app, for example. 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 597d600..b8bbd51 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java @@ -18,7 +18,7 @@ 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 +29,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 +45,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 +62,7 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref cbcookiesInkognito.setOnPreferenceChangeListener(this); cbrestoreTabs.setOnPreferenceChangeListener(this); - switch (mPreferences.getRenderingMode()) { + switch (preferenceManager.getRenderingMode()) { case 0: renderingmode.setSummary(getString(R.string.name_normal)); break; @@ -80,16 +77,16 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref break; } - textEncoding.setSummary(mPreferences.getTextEncoding()); + textEncoding.setSummary(preferenceManager.getTextEncoding()); mUrlOptions = getResources().getStringArray(R.array.url_content_array); - int option = mPreferences.getUrlBoxContentChoice(); + int option = preferenceManager.getUrlBoxContentChoice(); urlcontent.setSummary(mUrlOptions[option]); - cbAllowPopups.setChecked(mPreferences.getPopupsEnabled()); - cbenablecookies.setChecked(mPreferences.getCookiesEnabled()); - cbcookiesInkognito.setChecked(mPreferences.getIncognitoCookiesEnabled()); - cbrestoreTabs.setChecked(mPreferences.getRestoreLostTabsEnabled()); + cbAllowPopups.setChecked(preferenceManager.getPopupsEnabled()); + cbenablecookies.setChecked(preferenceManager.getCookiesEnabled()); + cbcookiesInkognito.setChecked(preferenceManager.getIncognitoCookiesEnabled()); + cbrestoreTabs.setChecked(preferenceManager.getRestoreLostTabsEnabled()); } @Override @@ -114,19 +111,19 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref // switch preferences switch (preference.getKey()) { case SETTINGS_NEWWINDOW: - mPreferences.setPopupsEnabled((Boolean) newValue); + preferenceManager.setPopupsEnabled((Boolean) newValue); cbAllowPopups.setChecked((Boolean) newValue); return true; case SETTINGS_ENABLECOOKIES: - mPreferences.setCookiesEnabled((Boolean) newValue); + preferenceManager.setCookiesEnabled((Boolean) newValue); cbenablecookies.setChecked((Boolean) newValue); return true; case SETTINGS_COOKIESINKOGNITO: - mPreferences.setIncognitoCookiesEnabled((Boolean) newValue); + preferenceManager.setIncognitoCookiesEnabled((Boolean) newValue); cbcookiesInkognito.setChecked((Boolean) newValue); return true; case SETTINGS_RESTORETABS: - mPreferences.setRestoreLostTabsEnabled((Boolean) newValue); + preferenceManager.setRestoreLostTabsEnabled((Boolean) newValue); cbrestoreTabs.setChecked((Boolean) newValue); return true; default: @@ -142,12 +139,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 = preferenceManager.getRenderingMode(); picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setRenderingMode(which); + preferenceManager.setRenderingMode(which); switch (which) { case 0: renderingmode.setSummary(getString(R.string.name_normal)); @@ -178,12 +175,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(preferenceManager.getTextEncoding()); picker.setSingleChoiceItems(Constants.TEXT_ENCODINGS, n, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setTextEncoding(Constants.TEXT_ENCODINGS[which]); + preferenceManager.setTextEncoding(Constants.TEXT_ENCODINGS[which]); textEncoding.setSummary(Constants.TEXT_ENCODINGS[which]); } }); @@ -201,12 +198,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 = preferenceManager.getUrlBoxContentChoice(); picker.setSingleChoiceItems(mUrlOptions, n, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setUrlBoxContentChoice(which); + preferenceManager.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 fdf15f2..2c01ac5 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -64,6 +64,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Inject BookmarksDialogBuilder bookmarksDialogBuilder; + @Inject + PreferenceManager preferenceManager; + // Adapter private BookmarkViewAdapter mBookmarkAdapter; @@ -151,7 +154,6 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, // TODO this code depend way too much on BrowserActivity super.onActivityCreated(savedInstanceState); final BrowserActivity activity = (BrowserActivity) getActivity(); - final PreferenceManager preferenceManager =PreferenceManager.getInstance(); boolean darkTheme = preferenceManager.getUseTheme() != 0 || activity.isIncognito(); mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme); 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 d33c40e..304bba8 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java @@ -21,7 +21,7 @@ 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 +38,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 +56,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 = preferenceManager.getUseTheme(); theme = findPreference(SETTINGS_THEME); Preference textsize = findPreference(SETTINGS_TEXTSIZE); @@ -77,13 +75,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(preferenceManager.getHideStatusBarEnabled()); + cbfullscreen.setChecked(preferenceManager.getFullScreenEnabled()); + cbviewport.setChecked(preferenceManager.getUseWideViewportEnabled()); + cboverview.setChecked(preferenceManager.getOverviewModeEnabled()); + cbreflow.setChecked(preferenceManager.getTextReflowEnabled()); - theme.setSummary(mThemeOptions[mPreferences.getUseTheme()]); + theme.setSummary(mThemeOptions[preferenceManager.getUseTheme()]); } @Override @@ -105,23 +103,23 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe // switch preferences switch (preference.getKey()) { case SETTINGS_HIDESTATUSBAR: - mPreferences.setHideStatusBarEnabled((Boolean) newValue); + preferenceManager.setHideStatusBarEnabled((Boolean) newValue); cbstatus.setChecked((Boolean) newValue); return true; case SETTINGS_FULLSCREEN: - mPreferences.setFullScreenEnabled((Boolean) newValue); + preferenceManager.setFullScreenEnabled((Boolean) newValue); cbfullscreen.setChecked((Boolean) newValue); return true; case SETTINGS_VIEWPORT: - mPreferences.setUseWideViewportEnabled((Boolean) newValue); + preferenceManager.setUseWideViewportEnabled((Boolean) newValue); cbviewport.setChecked((Boolean) newValue); return true; case SETTINGS_OVERVIEWMODE: - mPreferences.setOverviewModeEnabled((Boolean) newValue); + preferenceManager.setOverviewModeEnabled((Boolean) newValue); cboverview.setChecked((Boolean) newValue); return true; case SETTINGS_REFLOW: - mPreferences.setTextReflowEnabled((Boolean) newValue); + preferenceManager.setTextReflowEnabled((Boolean) newValue); cbreflow.setChecked((Boolean) newValue); return true; default: @@ -157,14 +155,14 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe }); final int MAX = 5; bar.setMax(MAX); - bar.setProgress(MAX - mPreferences.getTextSize()); + bar.setProgress(MAX - preferenceManager.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()); + preferenceManager.setTextSize(MAX - bar.getProgress()); } }); @@ -194,12 +192,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 = preferenceManager.getUseTheme(); picker.setSingleChoiceItems(mThemeOptions, n, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setUseTheme(which); + preferenceManager.setUseTheme(which); if (which < mThemeOptions.length) { theme.setSummary(mThemeOptions[which]); } @@ -210,7 +208,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { - if (mCurrentTheme != mPreferences.getUseTheme()) { + if (mCurrentTheme != preferenceManager.getUseTheme()) { getActivity().onBackPressed(); } } @@ -218,7 +216,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 != preferenceManager.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 6698e29..68714cd 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -28,7 +28,7 @@ import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ProxyUtils; 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 +45,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 +64,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 +91,23 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe cbgooglesuggest.setOnPreferenceChangeListener(this); cbDrawerTabs.setOnPreferenceChangeListener(this); - mAgentChoice = mPreferences.getUserAgentChoice(); - mHomepage = mPreferences.getHomepage(); - mDownloadLocation = mPreferences.getDownloadDirectory(); + mAgentChoice = preferenceManager.getUserAgentChoice(); + mHomepage = preferenceManager.getHomepage(); + mDownloadLocation = preferenceManager.getDownloadDirectory(); mProxyChoices = getResources().getStringArray(R.array.proxy_choices_array); - int choice = mPreferences.getProxyChoice(); + int choice = preferenceManager.getProxyChoice(); if (choice == Constants.PROXY_MANUAL) { - proxy.setSummary(mPreferences.getProxyHost() + ':' + mPreferences.getProxyPort()); + proxy.setSummary(preferenceManager.getProxyHost() + ':' + preferenceManager.getProxyPort()); } else { proxy.setSummary(mProxyChoices[choice]); } if (API >= 19) { - mPreferences.setFlashSupport(0); + preferenceManager.setFlashSupport(0); } - setSearchEngineSummary(mPreferences.getSearchChoice()); + setSearchEngineSummary(preferenceManager.getSearchChoice()); downloadloc.setSummary(Constants.EXTERNAL_STORAGE + '/' + mDownloadLocation); @@ -139,9 +135,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 = preferenceManager.getFlashSupport(); + boolean imagesBool = preferenceManager.getBlockImagesEnabled(); + boolean enableJSBool = preferenceManager.getJavaScriptEnabled(); proxy.setEnabled(Constants.FULL_VERSION); cbAds.setEnabled(Constants.FULL_VERSION); @@ -150,17 +146,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 && preferenceManager.getAdBlockEnabled()); + cbColorMode.setChecked(preferenceManager.getColorModeEnabled()); + cbgooglesuggest.setChecked(preferenceManager.getGoogleSearchSuggestionsEnabled()); + cbDrawerTabs.setChecked(preferenceManager.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 = preferenceManager.getSearchUrl(); getSearchUrl.setText(mSearchUrl); urlPicker.setView(getSearchUrl); urlPicker.setPositiveButton(getResources().getString(R.string.action_ok), @@ -168,7 +164,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { String text = getSearchUrl.getText().toString(); - mPreferences.setSearchUrl(text); + preferenceManager.setSearchUrl(text); searchengine.setSummary(getResources().getString(R.string.custom_url) + ": " + text); } @@ -185,7 +181,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { - mPreferences.setFlashSupport(1); + preferenceManager.setFlashSupport(1); } }) .setNegativeButton(getResources().getString(R.string.action_auto), @@ -193,13 +189,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setFlashSupport(2); + preferenceManager.setFlashSupport(2); } }).setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { - mPreferences.setFlashSupport(0); + preferenceManager.setFlashSupport(0); } }); @@ -210,7 +206,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, preferenceManager.getProxyChoice(), new DialogInterface.OnClickListener() { @Override @@ -240,7 +236,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe break; } - mPreferences.setProxyChoice(choice); + preferenceManager.setProxyChoice(choice); if (choice < mProxyChoices.length) proxy.setSummary(mProxyChoices[choice]); } @@ -258,8 +254,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(preferenceManager.getProxyHost()); + eProxyPort.setText(Integer.toString(preferenceManager.getProxyPort())); new AlertDialog.Builder(mActivity) .setTitle(R.string.manual_proxy) @@ -274,10 +270,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 = preferenceManager.getProxyPort(); } - mPreferences.setProxyHost(proxyHost); - mPreferences.setProxyPort(proxyPort); + preferenceManager.setProxyHost(proxyHost); + preferenceManager.setProxyPort(proxyPort); proxy.setSummary(proxyHost + ':' + proxyPort); } }).show(); @@ -291,13 +287,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe "DuckDuckGo (Privacy)", "DuckDuckGo Lite (Privacy)", "Baidu (Chinese)", "Yandex (Russian)"}; - int n = mPreferences.getSearchChoice(); + int n = preferenceManager.getSearchChoice(); picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setSearchChoice(which); + preferenceManager.setSearchChoice(which); setSearchEngineSummary(which); } }); @@ -313,7 +309,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 = preferenceManager.getHomepage(); int n; if (mHomepage.contains("about:home")) { n = 1; @@ -331,15 +327,15 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe public void onClick(DialogInterface dialog, int which) { switch (which + 1) { case 1: - mPreferences.setHomepage("about:home"); + preferenceManager.setHomepage("about:home"); home.setSummary(getResources().getString(R.string.action_homepage)); break; case 2: - mPreferences.setHomepage("about:blank"); + preferenceManager.setHomepage("about:blank"); home.setSummary(getResources().getString(R.string.action_blank)); break; case 3: - mPreferences.setHomepage("about:bookmarks"); + preferenceManager.setHomepage("about:bookmarks"); home.setSummary(getResources().getString(R.string.action_bookmarks)); break; case 4: @@ -361,7 +357,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 = preferenceManager.getHomepage(); if (!mHomepage.startsWith("about:")) { getHome.setText(mHomepage); } else { @@ -373,7 +369,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { String text = getHome.getText().toString(); - mPreferences.setHomepage(text); + preferenceManager.setHomepage(text); home.setSummary(text); } }); @@ -383,7 +379,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 = preferenceManager.getDownloadDirectory(); int n; if (mDownloadLocation.contains(Environment.DIRECTORY_DOWNLOADS)) { n = 1; @@ -397,7 +393,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe public void onClick(DialogInterface dialog, int which) { switch (which + 1) { case 1: - mPreferences.setDownloadDirectory(Environment.DIRECTORY_DOWNLOADS); + preferenceManager.setDownloadDirectory(Environment.DIRECTORY_DOWNLOADS); downloadloc.setSummary(Constants.EXTERNAL_STORAGE + '/' + Environment.DIRECTORY_DOWNLOADS); break; @@ -419,12 +415,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 = preferenceManager.getUserAgentChoice(); agentPicker.setSingleChoiceItems(R.array.user_agent, mAgentChoice - 1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mPreferences.setUserAgentChoice(which + 1); + preferenceManager.setUserAgentChoice(which + 1); switch (which + 1) { case 1: useragent.setSummary(getResources().getString(R.string.agent_default)); @@ -467,7 +463,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { String text = getAgent.getText().toString(); - mPreferences.setUserAgentString(text); + preferenceManager.setUserAgentString(text); useragent.setSummary(getResources().getString(R.string.agent_custom)); } }); @@ -479,7 +475,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe LinearLayout layout = new LinearLayout(mActivity); downLocationPicker.setTitle(getResources().getString(R.string.title_download_location)); final EditText getDownload = new EditText(mActivity); - getDownload.setText(mPreferences.getDownloadDirectory()); + getDownload.setText(preferenceManager.getDownloadDirectory()); int padding = Utils.dpToPx(10); @@ -507,7 +503,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @Override public void onClick(DialogInterface dialog, int which) { String text = getDownload.getText().toString(); - mPreferences.setDownloadDirectory(text); + preferenceManager.setDownloadDirectory(text); downloadloc.setSummary(Constants.EXTERNAL_STORAGE + '/' + text); } }); @@ -582,37 +578,37 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe if (cbFlash.isChecked()) { getFlashChoice(); } else { - mPreferences.setFlashSupport(0); + preferenceManager.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); + preferenceManager.setFlashSupport(0); } cbFlash.setChecked((Boolean) newValue); return true; case SETTINGS_ADS: - mPreferences.setAdBlockEnabled((Boolean) newValue); + preferenceManager.setAdBlockEnabled((Boolean) newValue); cbAds.setChecked((Boolean) newValue); return true; case SETTINGS_IMAGES: - mPreferences.setBlockImagesEnabled((Boolean) newValue); + preferenceManager.setBlockImagesEnabled((Boolean) newValue); cbImages.setChecked((Boolean) newValue); return true; case SETTINGS_JAVASCRIPT: - mPreferences.setJavaScriptEnabled((Boolean) newValue); + preferenceManager.setJavaScriptEnabled((Boolean) newValue); cbJsScript.setChecked((Boolean) newValue); return true; case SETTINGS_COLORMODE: - mPreferences.setColorModeEnabled((Boolean) newValue); + preferenceManager.setColorModeEnabled((Boolean) newValue); cbColorMode.setChecked((Boolean) newValue); return true; case SETTINGS_GOOGLESUGGESTIONS: - mPreferences.setGoogleSearchSuggestionsEnabled((Boolean) newValue); + preferenceManager.setGoogleSearchSuggestionsEnabled((Boolean) newValue); cbgooglesuggest.setChecked((Boolean) newValue); return true; case SETTINGS_DRAWERTABS: - mPreferences.setShowTabsInDrawer((Boolean) newValue); + preferenceManager.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..194b3cb --- /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 preferenceManager; + + @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 66b9c11..8bd540c 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java @@ -20,7 +20,7 @@ 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 +35,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 +51,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 +77,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(preferenceManager.getLocationEnabled()); + cbsavepasswords.setChecked(preferenceManager.getSavePasswordsEnabled()); + cbcacheexit.setChecked(preferenceManager.getClearCacheExit()); + cbhistoryexit.setChecked(preferenceManager.getClearHistoryExitEnabled()); + cbcookiesexit.setChecked(preferenceManager.getClearCookiesExitEnabled()); + cb3cookies.setChecked(preferenceManager.getBlockThirdPartyCookiesEnabled()); + cbwebstorageexit.setChecked(preferenceManager.getClearWebStorageExitEnabled()); cb3cookies.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP); @@ -213,31 +209,31 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe // switch preferences switch (preference.getKey()) { case SETTINGS_LOCATION: - mPreferences.setLocationEnabled((Boolean) newValue); + preferenceManager.setLocationEnabled((Boolean) newValue); cblocation.setChecked((Boolean) newValue); return true; case SETTINGS_THIRDPCOOKIES: - mPreferences.setBlockThirdPartyCookiesEnabled((Boolean) newValue); + preferenceManager.setBlockThirdPartyCookiesEnabled((Boolean) newValue); cb3cookies.setChecked((Boolean) newValue); return true; case SETTINGS_SAVEPASSWORD: - mPreferences.setSavePasswordsEnabled((Boolean) newValue); + preferenceManager.setSavePasswordsEnabled((Boolean) newValue); cbsavepasswords.setChecked((Boolean) newValue); return true; case SETTINGS_CACHEEXIT: - mPreferences.setClearCacheExit((Boolean) newValue); + preferenceManager.setClearCacheExit((Boolean) newValue); cbcacheexit.setChecked((Boolean) newValue); return true; case SETTINGS_HISTORYEXIT: - mPreferences.setClearHistoryExitEnabled((Boolean) newValue); + preferenceManager.setClearHistoryExitEnabled((Boolean) newValue); cbhistoryexit.setChecked((Boolean) newValue); return true; case SETTINGS_COOKIEEXIT: - mPreferences.setClearCookiesExitEnabled((Boolean) newValue); + preferenceManager.setClearCookiesExitEnabled((Boolean) newValue); cbcookiesexit.setChecked((Boolean) newValue); return true; case SETTINGS_WEBSTORAGEEXIT: - mPreferences.setClearWebStorageExitEnabled((Boolean) newValue); + preferenceManager.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 index 43738f1..678c332 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -129,6 +129,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public void onDestroyView() { + super.onDestroyView(); mRecyclerView = null; mTabsAdapter = null; } 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 c79bb54..f61aabc 100644 --- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java +++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java @@ -61,6 +61,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { 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; @@ -76,7 +77,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { 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; @@ -118,7 +119,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { } public void refreshPreferences() { - mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled(); + mUseGoogle = mPreferenceManager.getGoogleSearchSuggestionsEnabled(); if (!mUseGoogle) { synchronized (mSuggestions) { mSuggestions.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 9e186b4..438fad0 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 android.os.Environment; +import javax.inject.Inject; +import javax.inject.Singleton; + import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; +@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 0f06386..5ac6baf 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/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index b4b377c..011d97e 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -55,6 +55,8 @@ 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.app.BrowserApp; import acr.browser.lightning.constant.Constants; @@ -80,7 +82,8 @@ public class LightningView { 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; + @Inject + PreferenceManager mPreferences; private final AdBlock mAdBlock; private final IntentUtils mIntentUtils; private final Paint mPaint = new Paint(); @@ -102,7 +105,7 @@ public class LightningView { @SuppressLint("NewApi") public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito, BrowserController controller) { - + mPreferences = BrowserApp.getAppComponent().getPreferenceManager(); mActivity = activity; mWebView = new WebView(activity); mIsIncognitoTab = isIncognito; @@ -178,7 +181,6 @@ public class LightningView { } else if (settings == null) { settings = mWebView.getSettings(); } - mPreferences = PreferenceManager.getInstance(); settings.setDefaultTextEncodingName(mPreferences.getTextEncoding()); mHomepage = mPreferences.getHomepage(); From 2563e81f7a76bd9455c2de5755b4dd8cc1006685 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Wed, 16 Sep 2015 17:42:20 +0200 Subject: [PATCH 09/58] Bookmark page generation moved to LightningView to avoid call loop between BrowserActivity and LightningView through BrowserController --- .../lightning/activity/BrowserActivity.java | 29 +-------------- .../browser/lightning/app/AppComponent.java | 2 + .../lightning/constant/BookmarkPage.java | 5 ++- .../controller/BrowserController.java | 2 - .../browser/lightning/utils/IntentUtils.java | 15 +++++--- .../browser/lightning/view/LightningView.java | 37 +++++++++++++++---- 6 files changed, 46 insertions(+), 44 deletions(-) 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 2831051..eb3821d 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -1471,31 +1471,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(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); - - bookmarkPage.buildBookmarkPage(null, bookmarkManager.getBookmarksFromFolder(null, true)); - view.loadUrl(Constants.FILE + bookmarkWebPage); - } - @Override public void updateTabs() { eventBus.post(new BrowserEvents.TabsChanged()); @@ -2232,7 +2207,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final WebView currentWebView = currentTab.getWebView(); if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { - openBookmarkPage(currentWebView); + currentTab.loadBookmarkpage(); } if (currentTab != null) { eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); @@ -2250,7 +2225,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final WebView currentWebView = currentTab.getWebView(); if (currentTab != null && currentTab.getUrl().startsWith(Constants.FILE) && currentTab.getUrl().endsWith(Constants.BOOKMARKS_FILENAME)) { - openBookmarkPage(currentWebView); + currentTab.loadBookmarkpage(); } if (currentTab != null) { eventBus.post(new BrowserEvents.CurrentPageUrl(currentTab.getUrl())); 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 94e9682..14e0b56 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -37,4 +37,6 @@ public interface AppComponent { PreferenceManager getPreferenceManager(); void inject(LightningPreferenceFragment fragment); + + BookmarkPage getBookmarkPage(); } 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 6137cc1..2c3a8dc 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/controller/BrowserController.java b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java index 21750a8..7f4944a 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -48,8 +48,6 @@ public interface BrowserController { void longClickPage(String url); - void openBookmarkPage(WebView view); - void showFileChooser(ValueCallback filePathCallback); void closeEmptyTab(); 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 fb4e177..820d274 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; @@ -19,7 +20,7 @@ import acr.browser.lightning.controller.BrowserController; public class IntentUtils { - private final Activity mActivity; + private final Context mActivity; private static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile("(?i)" + // switch on case insensitive matching @@ -28,8 +29,8 @@ public class IntentUtils { "(?:http|https|file):\\/\\/" + "|(?:inline|data|about|javascript):" + "|(?:.*:.*@)" + ')' + "(.*)"); - public IntentUtils(BrowserController controller) { - mActivity = controller.getActivity(); + public IntentUtils(Context context) { + mActivity = context.getApplicationContext(); } public boolean startActivityForUrl(WebView tab, String url) { @@ -64,9 +65,11 @@ public class IntentUtils { return false; } try { - if (mActivity.startActivityIfNeeded(intent, -1)) { - return true; - } + // TODO Restore this +// if (mActivity.startActivityIfNeeded(intent, -1)) { +// return true; +// } + mActivity.startActivity(intent); } catch (ActivityNotFoundException ex) { ex.printStackTrace(); } 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 011d97e..c3bcb82 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -51,6 +51,7 @@ import android.widget.LinearLayout; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; @@ -75,14 +76,13 @@ public class LightningView { private final Title mTitle; private WebView mWebView; private final boolean mIsIncognitoTab; - private final BrowserController mBrowserController; + private final BrowserController mBrowserController = null; // TODO REMOVE private final GestureDetector mGestureDetector; private final Activity 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; - @Inject PreferenceManager mPreferences; private final AdBlock mAdBlock; private final IntentUtils mIntentUtils; @@ -104,7 +104,7 @@ public class LightningView { private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; @SuppressLint("NewApi") - public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito, BrowserController controller) { + public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) { mPreferences = BrowserApp.getAppComponent().getPreferenceManager(); mActivity = activity; mWebView = new WebView(activity); @@ -117,9 +117,7 @@ public class LightningView { mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity(); - mBrowserController = controller; - - mIntentUtils = new IntentUtils(mBrowserController); + mIntentUtils = new IntentUtils(activity); mWebView.setDrawingCacheBackgroundColor(Color.WHITE); mWebView.setFocusableInTouchMode(true); mWebView.setFocusable(true); @@ -161,12 +159,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 * From 030b839aa63c029e2811cae26e892595e121a968 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 17 Sep 2015 09:46:00 +0200 Subject: [PATCH 10/58] Trying to remove BrowserController interface --- .../browser/lightning/utils/ProxyUtils.java | 11 ++++--- .../lightning/activity/BrowserActivity.java | 29 ++++++++++--------- .../lightning/activity/TabsManager.java | 2 +- .../browser/lightning/app/AppComponent.java | 8 +++++ .../browser/lightning/bus/BrowserEvents.java | 24 +++++++++++++++ .../controller/BrowserController.java | 4 --- .../browser/lightning/view/LightningView.java | 24 +++++++++------ 7 files changed, 70 insertions(+), 32 deletions(-) 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 3942f7d..3847e58 100644 --- a/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java +++ b/app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java @@ -11,6 +11,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; @@ -144,13 +145,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; } } @@ -201,7 +204,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 eb3821d..09f27dd 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -38,6 +38,7 @@ 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; @@ -1012,7 +1013,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (show) { showTab(tabsManager.size() - 1); } - updateTabs(); + // TODO Check is this is callable directly from LightningView + eventBus.post(new BrowserEvents.TabsChanged()); // TODO Restore this // new Handler().postDelayed(new Runnable() { @@ -1048,14 +1050,14 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (current > position) { tabsManager.deleteTab(position); showTab(current - 1); - updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); tabToDelete.onDestroy(); } else if (tabsManager.size() > position + 1) { if (current == position) { showTab(position + 1); tabsManager.deleteTab(position); showTab(position); - updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); } else { tabsManager.deleteTab(position); } @@ -1066,7 +1068,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements showTab(position - 1); tabsManager.deleteTab(position); showTab(position - 1); - updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); } else { tabsManager.deleteTab(position); } @@ -1424,11 +1426,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 */ @@ -1471,11 +1468,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements return super.onCreateOptionsMenu(menu); } - @Override - public void updateTabs() { - eventBus.post(new BrowserEvents.TabsChanged()); - } - /** * opens a file chooser * param ValueCallback is the message from the WebView indicating a file chooser @@ -2326,9 +2318,18 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements String url = mPreferences.getSavedUrl(); if (url != null) { BrowserActivity.this.newTab(url, true); + Utils.showSnackbar(mActivity, 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(mActivity, event.stringRes); } + } }; } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index c3dd109..1510cb7 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -119,7 +119,7 @@ public class TabsManager { final String url, final boolean darkTheme, final boolean isIncognito, final BrowserController controller) { - final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito, controller); + final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito); mWebViewList.add(tab); return tab; } 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 14e0b56..76e1e46 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -1,5 +1,9 @@ package acr.browser.lightning.app; +import android.content.Context; + +import com.squareup.otto.Bus; + import javax.inject.Singleton; import acr.browser.lightning.activity.BrowserActivity; @@ -39,4 +43,8 @@ public interface AppComponent { void inject(LightningPreferenceFragment fragment); BookmarkPage getBookmarkPage(); + + Bus getBus(); + + Context getApplicationContext(); } 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 d461205..250d8d2 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,10 @@ package acr.browser.lightning.bus; +import android.support.annotation.IdRes; +import android.support.annotation.StringRes; + +import acr.browser.lightning.R; + /** * Created by Stefano Pacifici on 26/08/15. */ @@ -46,4 +51,23 @@ 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; + @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; + } + } } 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 7f4944a..51e4528 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -24,8 +24,6 @@ public interface BrowserController { void openFileChooser(ValueCallback uploadMsg); - void updateTabs(); - void onLongPress(); void onShowCustomView(View view, CustomViewCallback callback); @@ -52,8 +50,6 @@ public interface BrowserController { void closeEmptyTab(); - boolean proxyIsNotReady(); - // void updateBookmarkIndicator(String url); } 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 c3bcb82..cdce9a3 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -49,6 +49,8 @@ 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; @@ -60,6 +62,7 @@ import javax.inject.Inject; 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.constant.StartPage; import acr.browser.lightning.controller.BrowserController; @@ -68,6 +71,7 @@ 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; @@ -103,8 +107,11 @@ public class LightningView { private final PermissionsManager mPermissionsManager; private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; + private final Bus eventBus; + @SuppressLint("NewApi") public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) { + eventBus = BrowserApp.getAppComponent().getBus(); mPreferences = BrowserApp.getAppComponent().getPreferenceManager(); mActivity = activity; mWebView = new WebView(activity); @@ -419,7 +426,7 @@ public class LightningView { public void setForegroundTab(boolean isForeground) { isForegroundTab = isForeground; - mBrowserController.updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); } public boolean isForegroundTab() { @@ -522,7 +529,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; } @@ -625,8 +632,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; } @@ -697,7 +703,7 @@ public class LightningView { if (API >= android.os.Build.VERSION_CODES.KITKAT && mInvertPage) { view.evaluateJavascript(Constants.JAVASCRIPT_INVERT_PAGE, null); } - mBrowserController.updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); } @Override @@ -707,7 +713,7 @@ public class LightningView { mBrowserController.showActionBar(); } mTitle.setFavicon(mWebpageBitmap); - mBrowserController.updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); } @Override @@ -839,7 +845,7 @@ public class LightningView { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // Check if configured proxy is available - if (mBrowserController.proxyIsNotReady()) { + if (!ProxyUtils.getInstance().isProxyReady()) { // User has been notified return true; } @@ -897,7 +903,7 @@ public class LightningView { if (icon == null) return; mTitle.setFavicon(icon); - mBrowserController.updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); ; cacheFavicon(icon); } @@ -908,7 +914,7 @@ public class LightningView { } else { mTitle.setTitle(mActivity.getString(R.string.untitled)); } - mBrowserController.updateTabs(); + eventBus.post(new BrowserEvents.TabsChanged()); ; if (view != null) mBrowserController.updateHistory(title, view.getUrl()); } From 36150188164966779fdb662e0af854272e83fbf9 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Thu, 17 Sep 2015 11:23:35 +0200 Subject: [PATCH 11/58] ClickHandler removed, avoid call loop duirng long press on a webview between BrowserActivity and LightningView --- .../lightning/activity/BrowserActivity.java | 75 ----------------- .../browser/lightning/app/AppComponent.java | 3 + .../browser/lightning/bus/BrowserEvents.java | 1 + .../controller/BrowserController.java | 4 +- .../lightning/object/ClickHandler.java | 30 ------- .../browser/lightning/view/LightningView.java | 82 +++++++++++++++++-- 6 files changed, 82 insertions(+), 113 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/object/ClickHandler.java 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 09f27dd..d42a574 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -117,7 +117,6 @@ import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.dialog.BookmarksDialogBuilder; import acr.browser.lightning.fragment.TabsFragment; -import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.object.SearchAdapter; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.receiver.NetworkReceiver; @@ -150,7 +149,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private SearchAdapter mSearchAdapter; // Callback - private ClickHandler mClickHandler; private CustomViewCallback mCustomViewCallback; private ValueCallback mUploadMessage; private ValueCallback mFilePathCallback; @@ -240,7 +238,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mActivity = this; - mClickHandler = new ClickHandler(this); mBrowserFrame = (FrameLayout) findViewById(R.id.content_frame); mToolbarLayout = (LinearLayout) findViewById(R.id.toolbar_layout); // initialize background ColorDrawable @@ -1572,26 +1569,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mActivity.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(mActivity); - } - Message click = mClickHandler.obtainMessage(); - if (click != null) { - click.setTarget(mClickHandler); - final WebView currentWebView = tabsManager.getCurrentWebView(); - if (currentWebView != null) { - currentWebView.requestFocusNodeHref(click); - } - } - } - @Override public void onShowCustomView(View view, CustomViewCallback callback) { final LightningView currentTab = tabsManager.getCurrentTab(); @@ -1871,58 +1848,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - /** - * 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 - */ - @Override - public void longClickPage(final String url) { - HitTestResult result = null; - String currentUrl = null; - final WebView currentWebView = tabsManager.getCurrentWebView(); - if (currentWebView != null) { - result = currentWebView.getHitTestResult(); - currentUrl = currentWebView.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) { - bookmarksDialogBuilder.showLongPressedDialogForUrl(this, url); - } else if (result != null && result.getExtra() != null) { - final String newUrl = result.getExtra(); - bookmarksDialogBuilder.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); - } - } - } - } - private void longPressHistoryLink(final String url) { DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { @Override 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 76e1e46..6b54710 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -15,6 +15,7 @@ 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; /** @@ -47,4 +48,6 @@ public interface AppComponent { Bus getBus(); Context getApplicationContext(); + + void inject(LightningView lightningView); } 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 250d8d2..06e4d2d 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -1,6 +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; 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 51e4528..34ae451 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -24,7 +24,7 @@ public interface BrowserController { void openFileChooser(ValueCallback uploadMsg); - void onLongPress(); +// void onLongPress(); void onShowCustomView(View view, CustomViewCallback callback); @@ -44,7 +44,7 @@ public interface BrowserController { void showActionBar(); - void longClickPage(String url); + // void longClickPage(String url); void showFileChooser(ValueCallback filePathCallback); 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/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index cdce9a3..5b43ffe 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -20,6 +20,7 @@ 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; @@ -63,9 +64,12 @@ import javax.inject.Inject; import acr.browser.lightning.R; 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.download.LightningDownloadListener; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.AdBlock; @@ -87,7 +91,6 @@ public class LightningView { 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; - PreferenceManager mPreferences; private final AdBlock mAdBlock; private final IntentUtils mIntentUtils; private final Paint mPaint = new Paint(); @@ -106,13 +109,20 @@ 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; - private final Bus eventBus; + @Inject + BookmarksDialogBuilder bookmarksDialogBuilder; @SuppressLint("NewApi") public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito) { - eventBus = BrowserApp.getAppComponent().getBus(); - mPreferences = BrowserApp.getAppComponent().getPreferenceManager(); + BrowserApp.getAppComponent().inject(this); mActivity = activity; mWebView = new WebView(activity); mIsIncognitoTab = isIncognito; @@ -613,6 +623,52 @@ public class LightningView { } } + /** + * 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) { + // TODO longPressHistoryLink(url); + } else if (result != null && result.getExtra() != null) { + final String newUrl = result.getExtra(); + // TODO longPressHistoryLink(newUrl); + } + } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) { + if (url != null) { + bookmarksDialogBuilder.showLongPressedDialogForUrl(mActivity, url); + } else if (result != null && result.getExtra() != null) { + final String newUrl = result.getExtra(); + bookmarksDialogBuilder.showLongPressedDialogForUrl(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); + } else { + // TODO longPressLink(url); + } + } else { + // TODO longPressLink(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); + } else { + // TODO longPressLink(newUrl); + } + } + } + } + public boolean canGoBack() { return mWebView != null && mWebView.canGoBack(); } @@ -1149,8 +1205,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); + } + } } /** @@ -1172,4 +1233,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); + } + } } From 6749ca39b8c005a6e1e54d23e4d532763e9e1971 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Tue, 22 Sep 2015 16:15:17 +0200 Subject: [PATCH 12/58] Simplified LightningView with externalized XXXClients --- .../lightning/activity/BrowserActivity.java | 196 +------ .../lightning/activity/TabsManager.java | 32 +- .../browser/lightning/app/AppComponent.java | 7 +- .../browser/lightning/bus/BookmarkEvents.java | 22 - .../browser/lightning/bus/BrowserEvents.java | 42 +- .../lightning/constant/HistoryPage.java | 2 +- .../lightning/database/HistoryDatabase.java | 14 +- ...ilder.java => LightningDialogBuilder.java} | 124 +++- .../lightning/fragment/BookmarksFragment.java | 8 +- .../lightning/object/SearchAdapter.java | 19 +- .../acr/browser/lightning/utils/WebUtils.java | 3 +- .../lightning/view/LightningChromeClient.java | 234 ++++++++ .../browser/lightning/view/LightningView.java | 555 ++---------------- .../lightning/view/LightningViewTitle.java | 66 +++ .../lightning/view/LightningWebClient.java | 276 +++++++++ 15 files changed, 833 insertions(+), 767 deletions(-) rename app/src/main/java/acr/browser/lightning/dialog/{BookmarksDialogBuilder.java => LightningDialogBuilder.java} (60%) create mode 100644 app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java create mode 100644 app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java create mode 100644 app/src/main/java/acr/browser/lightning/view/LightningWebClient.java 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 d42a574..0188bdc 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -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(); } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 1510cb7..75d1a1d 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -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; 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 6b54710..4eea3c7 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -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); 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 7b8846d..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 */ 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 06e4d2d..f115149 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -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; + } + } } 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/database/HistoryDatabase.java b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java index 8d42983..a10a0bb 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(); } 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 79235cc..c7ac9e9 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/fragment/BookmarksFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java index 2c01ac5..18dc308 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -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()); } } 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 f61aabc..87185d6 100644 --- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java +++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java @@ -54,14 +54,11 @@ public class SearchAdapter extends BaseAdapter implements Filterable { private final List mFilteredList = new ArrayList<>(); private final List 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 historyList = mDatabaseHandler.findItemsContaining(constraint.toString()); synchronized (mHistory) { mHistory.clear(); 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 96ce095..e0434fe 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; /** @@ -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(); 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..747dac2 --- /dev/null +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -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 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; + } + + @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); + } +} 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 5b43ffe..1920b8a 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -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 uploadMsg) { - mBrowserController.openFileChooser(uploadMsg); - } - - public void openFileChooser(ValueCallback uploadMsg, String acceptType) { - mBrowserController.openFileChooser(uploadMsg); - } - - 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); - } - - @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); } 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); + } +} From 1f025debd7cbbad7f171870d80ee3683a2c6e285 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Mon, 28 Sep 2015 15:44:23 +0200 Subject: [PATCH 13/58] Solve problems with colors when tabs are switched --- .../lightning/activity/BrowserActivity.java | 4 +- .../lightning/fragment/TabsFragment.java | 96 ++++++++++++++++--- 2 files changed, 85 insertions(+), 15 deletions(-) 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 0188bdc..fa79e74 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -235,7 +235,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerRight = (ViewGroup) findViewById(R.id.right_drawer); mDrawerRight.setLayerType(View.LAYER_TYPE_HARDWARE, null); -// TODO Probably should be moved to the TabsFragement +// TODO Please review this // ImageView tabTitleImage = (ImageView) findViewById(R.id.plusIcon); // tabTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN); @@ -253,8 +253,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final TabsFragment tabsFragment = new TabsFragment(); final int containerId = mShowTabsInDrawer ? R.id.left_drawer : R.id.tabs_toolbar_container; final Bundle arguments = new Bundle(); + arguments.putBoolean(TabsFragment.IS_INCOGNITO, isIncognito()); arguments.putBoolean(TabsFragment.VERTICAL_MODE, mShowTabsInDrawer); - arguments.putBoolean(TabsFragment.USE_DARK_THEME, mDarkTheme); tabsFragment.setArguments(arguments); getSupportFragmentManager() .beginTransaction() diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 678c332..2047453 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -1,6 +1,9 @@ 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; @@ -10,6 +13,7 @@ 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; @@ -18,12 +22,14 @@ 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; @@ -42,6 +48,7 @@ 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; @@ -59,13 +66,13 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View * 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 USE_DARK_THEME = TAG + ".USE_DARK_THEME"; + public static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO"; - private boolean mDarkTheme; + private boolean mIsIncognito, mDarkTheme; private int mIconColor; - private boolean mColorMode = true; // TODO Only temporary - private boolean isIncognito = false; // TODO Only temporary - private int mCurrentUiColor = 0; // TODO Only temporary + private boolean mColorMode = true; + private boolean mShowInNavigationDrawer; + private int mCurrentUiColor = Color.BLACK; // TODO Only temporary private RecyclerView mRecyclerView; private LightningViewAdapter mTabsAdapter; @@ -76,6 +83,9 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Inject Bus bus; + @Inject + PreferenceManager mPreferences; + public TabsFragment() { BrowserApp.getAppComponent().inject(this); } @@ -85,7 +95,11 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View super.onCreate(savedInstanceState); final Bundle arguments = getArguments(); final Context context = getContext(); - mDarkTheme = arguments.getBoolean(USE_DARK_THEME, false); + 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); @@ -95,10 +109,9 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Bundle arguments = getArguments(); - final boolean vertical = arguments.getBoolean(VERTICAL_MODE, true); final View view; final LayoutManager layoutManager; - if (vertical) { + if (mShowInNavigationDrawer) { view = inflater.inflate(R.layout.tab_drawer, container, false); layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); // TODO Handle also long press @@ -112,7 +125,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View } mRecyclerView = (RecyclerView) view.findViewById(R.id.tabs_list); mRecyclerView.setLayoutManager(layoutManager); - mTabsAdapter = new LightningViewAdapter(vertical); + mTabsAdapter = new LightningViewAdapter(mShowInNavigationDrawer); mRecyclerView.setAdapter(mTabsAdapter); mRecyclerView.setHasFixedSize(true); return view; @@ -249,7 +262,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View Drawable foregroundDrawable; if (!vertical) { foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap); - if (!isIncognito && mColorMode) { + if (!mIsIncognito && mColorMode) { foregroundDrawable.setColorFilter(mCurrentUiColor, PorterDuff.Mode.SRC_IN); } } else { @@ -260,9 +273,8 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View } else { holder.layout.setBackgroundDrawable(foregroundDrawable); } - if (!isIncognito && mColorMode) { - // TODO Restore this - // changeToolbarBackground(favicon, foregroundDrawable); + if (!mIsIncognito && mColorMode) { + changeToolbarBackground(favicon, foregroundDrawable); } holder.favicon.setImageBitmap(favicon); } else { @@ -302,6 +314,64 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View 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) { From f761383fc4e5880360cd873c800d234a842d2c17 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Mon, 28 Sep 2015 20:36:04 -0400 Subject: [PATCH 14/58] Up version number, fix build error. --- .travis.yml | 2 +- app/build.gradle | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8f769e4..b226663 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false android: components: - build-tools-22.0.1 - - build-tools-23.0.0 + - build-tools-23.0.1 - android-23 - android-22 - extra-android-support diff --git a/app/build.gradle b/app/build.gradle index 8453c1a..aaf4c35 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,7 +7,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionName "4.2.0a" + versionName "4.2.1a" } sourceSets { lightningPlus.setRoot('src/LightningPlus') @@ -30,12 +30,12 @@ android { lightningPlus { buildConfigField "boolean", "FULL_VERSION", "true" applicationId "acr.browser.lightning" - versionCode 81 + versionCode 82 } lightningLite { buildConfigField "boolean", "FULL_VERSION", "false" applicationId "acr.browser.barebones" - versionCode 82 + versionCode 83 } } lintOptions { From a015d810ea527f72fb2aca3a398b26b42b05643c Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Tue, 29 Sep 2015 07:42:56 -0400 Subject: [PATCH 15/58] Fix UI bug caused by obfuscation --- app/build.gradle | 6 +++--- app/proguard-project.txt | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index aaf4c35..070918d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,7 +7,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionName "4.2.1a" + versionName "4.2.2a" } sourceSets { lightningPlus.setRoot('src/LightningPlus') @@ -30,12 +30,12 @@ android { lightningPlus { buildConfigField "boolean", "FULL_VERSION", "true" applicationId "acr.browser.lightning" - versionCode 82 + versionCode 83 } lightningLite { buildConfigField "boolean", "FULL_VERSION", "false" applicationId "acr.browser.barebones" - versionCode 83 + versionCode 84 } } lintOptions { diff --git a/app/proguard-project.txt b/app/proguard-project.txt index edc15dc..40cddda 100644 --- a/app/proguard-project.txt +++ b/app/proguard-project.txt @@ -50,6 +50,18 @@ public static *** i(...); } +-keep class butterknife.** { *; } +-dontwarn butterknife.internal.** +-keep class **$$ViewBinder { *; } + +-keepclasseswithmembernames class * { + @butterknife.* ; +} + +-keepclasseswithmembernames class * { + @butterknife.* ; +} + # this will fix a force close in ReadingActivity -keep public class org.jsoup.** { public *; From 61b57cd992decfa502492cc127cf3066f1feff72 Mon Sep 17 00:00:00 2001 From: Stefano Pacifici Date: Tue, 29 Sep 2015 14:39:05 +0200 Subject: [PATCH 16/58] Restore activity restart when tab mode changes --- .../lightning/activity/BrowserActivity.java | 3 +-- .../activity/ThemableBrowserActivity.java | 15 +++++++++++---- .../acr/browser/lightning/app/AppComponent.java | 3 +++ .../acr/browser/lightning/bus/BrowserEvents.java | 12 ++++++------ 4 files changed, 21 insertions(+), 12 deletions(-) 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 609476a..2638622 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -191,8 +191,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Inject TabsManager tabsManager; - @Inject - PreferenceManager mPreferences; + // Preference manager was moved on ThemeableBrowserActivity @Inject HistoryDatabase mHistoryDatabase; 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 b84d798..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 = 0; //PreferenceManager.getInstance().getUseTheme(); - mShowTabsInDrawer = false; // 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 = 0; // PreferenceManager.getInstance().getUseTheme(); - boolean drawerTabs = false; // 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/app/AppComponent.java b/app/src/main/java/acr/browser/lightning/app/AppComponent.java index 4eea3c7..6be83ca 100644 --- a/app/src/main/java/acr/browser/lightning/app/AppComponent.java +++ b/app/src/main/java/acr/browser/lightning/app/AppComponent.java @@ -7,6 +7,7 @@ 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.database.HistoryDatabase; import acr.browser.lightning.dialog.LightningDialogBuilder; @@ -53,4 +54,6 @@ public interface AppComponent { Context getApplicationContext(); void inject(LightningView lightningView); + + void inject(ThemableBrowserActivity activity); } 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 f115149..478dbce 100644 --- a/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java +++ b/app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java @@ -17,9 +17,9 @@ public final class BrowserEvents { * result is a new bookmark added. */ public static class AddBookmark { - public final java.lang.String title, url; + public final String title, url; - public AddBookmark(final java.lang.String title, final java.lang.String url) { + public AddBookmark(final String title, final String url) { this.title = title; this.url = url; } @@ -30,9 +30,9 @@ public final class BrowserEvents { * {@link acr.browser.lightning.fragment.BookmarksFragment} interface. */ public static class CurrentPageUrl { - public final java.lang.String url; + public final String url; - public CurrentPageUrl(final java.lang.String url) { + public CurrentPageUrl(final String url) { this.url = url; } } @@ -57,11 +57,11 @@ public final class BrowserEvents { * Notify the Browser to display a SnackBar in the main activity */ public static class ShowSnackBarMessage { - public final java.lang.String message; + public final String message; @StringRes public final int stringRes; - public ShowSnackBarMessage(final java.lang.String message) { + public ShowSnackBarMessage(final String message) { this.message = message; this.stringRes = -1; } From 06e80ad5418a04871aea024b09714ae33d74bd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=82osz=20Sieradzki?= Date: Wed, 30 Sep 2015 21:56:14 +0200 Subject: [PATCH 17/58] Fixes #297: properly implement onReceivedSslError() method Validation of SSL certificates is still not ideal, as https://badssl.com/ shows, but further improvements require more investigation. --- .../browser/lightning/view/LightningView.java | 48 +++++++++++++++---- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-gr/strings.xml | 1 - app/src/main/res/values-hu/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 5 +- app/src/main/res/values-ja/strings.xml | 1 - app/src/main/res/values-ko/strings.xml | 3 +- app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-pt/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-sr/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values/strings.xml | 8 +++- 15 files changed, 50 insertions(+), 25 deletions(-) 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 2c9a9e1..a14f65d 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -54,6 +54,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; @@ -774,11 +776,47 @@ public class LightningView { } } + 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(mActivity.getString(R.string.message_untrusted_certificate)) + builder.setMessage(alertMessage) .setCancelable(true) .setPositiveButton(mActivity.getString(R.string.action_yes), new DialogInterface.OnClickListener() { @@ -794,13 +832,7 @@ public class LightningView { handler.cancel(); } }); - AlertDialog alert = builder.create(); - if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) { - alert.show(); - } else { - handler.proceed(); - } - + builder.create().show(); } @Override diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f30e7d9..c332fc1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -123,7 +123,6 @@ Open Source-Lizenzen Suche nach Werbung blockieren - Das Zertifikat dieser Webseite ist nicht vertrauenswürdig. Trotzdem fortsetzen? Formularneuzustellung Daten erneut senden? \nMeine Position verwenden? diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b6c61a0..1503551 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -106,7 +106,6 @@ Licencias de código abierto (open source) Buscar Bloquear anuncios - El certificado del sitio no es de fiar. ¿Continuar de todas maneras? Resubir el formulario ¿Quieres mandar los datos de nuevo? \n¿Quieres usar tu geolocalización? diff --git a/app/src/main/res/values-gr/strings.xml b/app/src/main/res/values-gr/strings.xml index 55ab54d..fc5a410 100644 --- a/app/src/main/res/values-gr/strings.xml +++ b/app/src/main/res/values-gr/strings.xml @@ -107,7 +107,6 @@ Άδειες ανοιχτού κώδικα Αναζήτηση για Μπλοκάρισμα διαφημίσεων - Το πιστοποιητικό δεν είναι αξιόπιστο. Συνέχεια παρ\'όλα αυτά; Επαναυποβολή φόρμας Θα θέλατε να ξαναστείλετε τα στοιχεία; \nΘα θέλατε να χρησιμοποιήσετε την τοποθεσία σας; diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 5c03fb8..39d13db 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -123,7 +123,6 @@ Nyílt forráskódú licencek Keresés Reklámok blokkolása - Az oldal tanusítványa nem megfelelő.Folytatja mindenképpen? Űrlap újraküldése Szeretnél újból elküldi az adatokat? \nSzeretné használni a saját helyét? diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a547cea..f8d4205 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,10 +1,10 @@ + android:layout_height="match_parent" /> + \ No newline at end of file From 159053841a09a521569496cf555fa2dbd0c07629 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Wed, 14 Oct 2015 21:21:51 -0400 Subject: [PATCH 28/58] Add dex counter, fixed new bugs in bookmarks, fixed bug in bookmark sync, todo fix downloading bug --- app/build.gradle | 11 +- .../activity/BrowserActivity.java.orig | 2129 ----------------- .../lightning/database/BookmarkLocalSync.java | 2 +- .../dialog/LightningDialogBuilder.java | 3 - .../download/LightningDownloadListener.java | 2 + .../lightning/fragment/BookmarksFragment.java | 2 +- .../browser/lightning/view/LightningView.java | 4 +- build.gradle | 2 +- 8 files changed, 17 insertions(+), 2138 deletions(-) delete mode 100644 app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig diff --git a/app/build.gradle b/app/build.gradle index 04f1417..0fae57c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,5 +1,6 @@ apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' +apply plugin: 'com.getkeepsafe.dexcount' android { compileSdkVersion 23 @@ -43,6 +44,14 @@ android { } } +dexcount { + includeClasses = false + includeFieldCount = false + printAsTree = true + orderByMethodCount = true + verbose = false +} + dependencies { compile 'com.android.support:palette-v7:23.0.1' compile 'com.android.support:appcompat-v7:23.0.1' @@ -54,7 +63,6 @@ dependencies { apt 'com.google.dagger:dagger-compiler:2.0.1' compile 'com.jakewharton:butterknife:7.0.1' - // Only Lightning Plus needs the proxy libraries compile 'net.i2p.android:client:0.7' // Use the following code to update the libnetcipher submodule @@ -66,4 +74,5 @@ dependencies { releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' provided 'javax.annotation:jsr250-api:1.0' + } \ No newline at end of file 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 deleted file mode 100644 index 7e0fa1d..0000000 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig +++ /dev/null @@ -1,2129 +0,0 @@ -/* - * 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/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index 1c1b8c1..c651f43 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -72,7 +72,7 @@ public class BookmarkLocalSync { if (!isChromeSupported()) { return list; } - Cursor cursor = getStockCursor(); + Cursor cursor = getChromeCursor(); try { if (cursor != null) { for (int n = 0; n < cursor.getColumnCount(); n++) { diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index 923472a..b70d44d 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -257,11 +257,8 @@ public class LightningDialogBuilder { 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; } } 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 6d6b7a1..4d711ba 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -12,6 +12,7 @@ import android.webkit.URLUtil; import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; +import acr.browser.lightning.utils.PermissionsManager; public class LightningDownloadListener implements DownloadListener { @@ -21,6 +22,7 @@ public class LightningDownloadListener implements DownloadListener { mContext = context; } + //TODO implement permissions for downloading @Override public void onDownloadStart(final String url, final String userAgent, final String contentDisposition, final String mimetype, long contentLength) { 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 28f9a4f..9122932 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -298,7 +298,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, if (item.isFolder()) { mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item); } else { - mBookmarksDialogBuilder.showLongPressLinkDialog(getContext(), item.getUrl()); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(getContext(), item); } } 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 964e897..2bc41fc 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -609,10 +609,10 @@ public class LightningView { } } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) { if (url != null) { - bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); + bookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl); + bookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, newUrl); } } } else { diff --git a/build.gradle b/build.gradle index 44b6898..d52a038 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,3 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() @@ -6,6 +5,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.3.1' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7' + classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.2.1' } } From 99e4773e453953066923fd8a2e5a4cb1a7fb139e Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Wed, 14 Oct 2015 22:55:39 -0400 Subject: [PATCH 29/58] Preliminary fix for permissions, fixed a new crash, formatted some code --- .../lightning/activity/BrowserActivity.java | 32 +++---- .../lightning/activity/SettingsActivity.java | 2 +- .../lightning/activity/TabsManager.java | 41 +++++---- .../lightning/download/FetchUrlMimeType.java | 13 ++- .../download/LightningDownloadListener.java | 68 +++++++++------ .../fragment/BookmarkSettingsFragment.java | 41 +++++++-- .../lightning/utils/PermissionsManager.java | 86 +++++++++++++++---- .../acr/browser/lightning/utils/Utils.java | 21 ++++- .../lightning/view/LightningChromeClient.java | 68 ++++++++------- .../browser/lightning/view/LightningView.java | 8 +- 10 files changed, 247 insertions(+), 133 deletions(-) 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 88df5b2..4953fee 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -11,14 +11,12 @@ 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; @@ -45,7 +43,6 @@ 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; @@ -77,7 +74,6 @@ 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; @@ -88,8 +84,6 @@ 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; @@ -109,7 +103,6 @@ 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; @@ -822,7 +815,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * displays the WebView contained in the LightningView Also handles the * removal of previous views * - * @param position the poition of the tab to display + * @param position the poition of the tab to display */ private synchronized void showTab(final int position) { final LightningView currentView = tabsManager.getCurrentTab(); @@ -1733,7 +1726,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.setTranslationY(0); if (view != null) { view.setTranslationY(height); - } + } } final LightningView currentTab = tabsManager.getCurrentTab(); if (currentTab == null) @@ -1755,9 +1748,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements show.setInterpolator(new DecelerateInterpolator()); if (view != null) { view.startAnimation(show); - } } } + } } /** @@ -1848,6 +1841,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } // 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 @@ -1880,7 +1874,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements boolean isConnected = isConnected(context); Log.d(Constants.TAG, "Network Connected: " + String.valueOf(isConnected)); tabsManager.notifyConnectioneStatus(isConnected); - } + } }; /** @@ -1894,7 +1888,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - PermissionsManager.getInstance().notifyPermissionsChange(permissions); + PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults); } @@ -2037,7 +2031,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Subscribe public void showCloseDialog(final TabEvents.ShowCloseDialog event) { - BrowserActivity.this.showCloseDialog(event.position); + BrowserActivity.this.showCloseDialog(event.position); } /** @@ -2098,13 +2092,13 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Subscribe public void newTabLongPress(final TabEvents.NewTabLongPress event) { - String url = mPreferences.getSavedUrl(); - if (url != null) { - BrowserActivity.this.newTab(url, true); + String url = mPreferences.getSavedUrl(); + if (url != null) { + BrowserActivity.this.newTab(url, true); - Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab); - } - mPreferences.setSavedUrl(null); + Utils.showSnackbar(BrowserActivity.this, R.string.deleted_tab); + } + mPreferences.setSavedUrl(null); } @Subscribe diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index d97c0da..a61dff2 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -61,7 +61,7 @@ public class SettingsActivity extends ThemableSettingsActivity { @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - PermissionsManager.getInstance().notifyPermissionsChange(permissions); + PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults); super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 19f159b..7156d2f 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -1,6 +1,5 @@ package acr.browser.lightning.activity; -import android.app.Activity; import android.content.Context; import android.support.annotation.Nullable; import android.webkit.WebView; @@ -11,7 +10,6 @@ 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; @@ -57,7 +55,7 @@ public class TabsManager { * 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 + * @return a copy of the current tabs list */ public List getTabsList() { return new ArrayList<>(mWebViewList); @@ -67,8 +65,8 @@ public class TabsManager { * 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 + * @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) { @@ -83,7 +81,7 @@ public class TabsManager { * Try to low memory pressure */ public void freeMemory() { - for (LightningView tab: mWebViewList) { + for (LightningView tab : mWebViewList) { tab.freeMemory(); } } @@ -92,7 +90,7 @@ public class TabsManager { * Shutdown the manager */ public synchronized void shutdown() { - for (LightningView tab: mWebViewList) { + for (LightningView tab : mWebViewList) { tab.onDestroy(); } mWebViewList.clear(); @@ -104,7 +102,7 @@ public class TabsManager { * @param context */ public synchronized void resume(final Context context) { - for (LightningView tab: mWebViewList) { + for (LightningView tab : mWebViewList) { tab.initializePreferences(null, context); } } @@ -115,15 +113,16 @@ public class TabsManager { * @param isConnected */ public synchronized void notifyConnectioneStatus(final boolean isConnected) { - for (LightningView tab: mWebViewList) { + for (LightningView tab : mWebViewList) { final WebView webView = tab.getWebView(); if (webView != null) { webView.setNetworkAvailable(isConnected); } } } + /** - * @return The number of currently opened tabs + * @return The number of currently opened tabs */ public int size() { return mWebViewList.size(); @@ -149,8 +148,8 @@ public class TabsManager { /** * 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 + * @param position The position of the tab to remove + * @return The removed tab reference or null */ @Nullable public synchronized LightningView deleteTab(final int position) { @@ -163,22 +162,23 @@ public class TabsManager { } /** - * Return the position of the given tab - * @param tab - * @return + * Return the position of the given tab. + * + * @param tab the tab to look for + * @return the position of the tab or -1 if the tab is not in the list */ public int positionOf(final LightningView tab) { return mWebViewList.indexOf(tab); } /** - * @return A string representation of the currently opened tabs + * @return A string representation of the currently opened tabs */ public String tabsString() { final StringBuilder builder = new StringBuilder(); - for (LightningView tab: mWebViewList) { + for (LightningView tab : mWebViewList) { final String url = tab.getUrl(); - if (url != null && !url.isEmpty()) { + if (!url.isEmpty()) { builder.append(url).append("|$|SEPARATOR|$|"); } } @@ -187,6 +187,7 @@ public class TabsManager { /** * Return the {@link WebView} associated to the current tab, or null if there is no current tab + * * @return a {@link WebView} or null */ @Nullable @@ -196,8 +197,10 @@ public class TabsManager { /** * TODO We should remove also this, but probably not + * * @return */ + @Nullable public LightningView getCurrentTab() { return mCurrentTab; } @@ -207,7 +210,7 @@ public class TabsManager { * 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 + * @return the selected tab or null if position is out of tabs range */ @Nullable public LightningView switchToTab(final int position) { 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 80d5995..3ba8e0c 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -6,6 +6,8 @@ package acr.browser.lightning.download; import android.app.DownloadManager; import android.content.Context; import android.os.Environment; +import android.os.Handler; +import android.os.Looper; import android.webkit.MimeTypeMap; import android.webkit.URLUtil; @@ -53,7 +55,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(); + final Bus eventBus = BrowserApp.getAppComponent().getBus(); String mimeType = null; String contentDisposition = null; HttpURLConnection connection = null; @@ -108,6 +110,13 @@ class FetchUrlMimeType extends Thread { DownloadManager manager = (DownloadManager) mContext .getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(mRequest); - evenBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + filename)); + Handler handler = new Handler(Looper.getMainLooper()); + final String file = filename; + handler.post(new Runnable() { + @Override + public void run() { + eventBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + file)); + } + }); } } 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 4d711ba..f58d24b 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,8 @@ */ package acr.browser.lightning.download; -import android.content.Context; +import android.Manifest; +import android.app.Activity; import android.content.DialogInterface; import android.support.v7.app.AlertDialog; import android.util.Log; @@ -16,40 +17,51 @@ import acr.browser.lightning.utils.PermissionsManager; public class LightningDownloadListener implements DownloadListener { - private final Context mContext; + private final Activity mActivity; - public LightningDownloadListener(Context context) { - mContext = context; + public LightningDownloadListener(Activity context) { + mActivity = context; } - //TODO implement permissions for downloading @Override public void onDownloadStart(final String url, final String userAgent, - final String contentDisposition, final String mimetype, long contentLength) { - String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + final String contentDisposition, final String mimetype, long contentLength) { + PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() { @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - DownloadHandler.onDownloadStart(mContext, url, userAgent, - contentDisposition, mimetype); - break; - - case DialogInterface.BUTTON_NEGATIVE: - break; - } + public void onGranted() { + String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + DownloadHandler.onDownloadStart(mActivity, url, userAgent, + contentDisposition, mimetype); + break; + + case DialogInterface.BUTTON_NEGATIVE: + break; + } + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog + builder.setTitle(fileName) + .setMessage(mActivity.getResources().getString(R.string.dialog_download)) + .setPositiveButton(mActivity.getResources().getString(R.string.action_download), + dialogClickListener) + .setNegativeButton(mActivity.getResources().getString(R.string.action_cancel), + dialogClickListener).show(); + Log.i(Constants.TAG, "Downloading" + fileName); + } + + @Override + public void onDenied(String permission) { + //TODO show message } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); // dialog - builder.setTitle(fileName) - .setMessage(mContext.getResources().getString(R.string.dialog_download)) - .setPositiveButton(mContext.getResources().getString(R.string.action_download), - dialogClickListener) - .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/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 8698603..ea8e980 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -88,7 +88,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref PermissionsManager permissionsManager = PermissionsManager.getInstance(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS); + permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, null); } } @@ -124,15 +124,40 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref public boolean onPreferenceClick(Preference preference) { switch (preference.getKey()) { case SETTINGS_EXPORT: - if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { - mBookmarkManager.exportBookmarks(getActivity()); - } +// if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { +// mBookmarkManager.exportBookmarks(getActivity()); +// } + PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, + new PermissionsManager.PermissionResult() { + @Override + public void onGranted() { + mBookmarkManager.exportBookmarks(getActivity()); + } + + @Override + public void onDenied(String permission) { + //TODO Show message + } + }); return true; case SETTINGS_IMPORT: - if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { - loadFileList(null); - createDialog(); - } +// if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { +// loadFileList(null); +// createDialog(); +// } + PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, + new PermissionsManager.PermissionResult() { + @Override + public void onGranted() { + loadFileList(null); + createDialog(); + } + + @Override + public void onDenied(String permission) { + //TODO Show message + } + }); return true; case SETTINGS_IMPORT_BROWSER: new ImportBookmarksTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); diff --git a/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java b/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java index c0cc104..93a6aea 100644 --- a/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java +++ b/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java @@ -4,8 +4,11 @@ import android.app.Activity; import android.content.pm.PackageManager; import android.os.Build; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -13,10 +16,11 @@ import java.util.Set; /** * Copyright 8/22/2015 Anthony Restaino */ -public class PermissionsManager { +public final class PermissionsManager { private static PermissionsManager mInstance; private final Set mPendingRequests = new HashSet<>(); + private final List mPendingActions = new ArrayList<>(); public static PermissionsManager getInstance() { if (mInstance == null) { @@ -25,34 +29,47 @@ public class PermissionsManager { return mInstance; } - public void requestPermissionsIfNecessary(Activity activity, @NonNull String[] permissions) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || activity == null) { + private void addPendingAction(@NonNull String[] permissions, @Nullable PermissionResult result) { + if (result == null) { + return; + } + result.addPermissions(permissions); + mPendingActions.add(result); + } + + public void requestPermissionsIfNecessary(@Nullable Activity activity, @NonNull String[] permissions, @Nullable PermissionResult result) { + if (activity == null) { + return; + } + addPendingAction(permissions, result); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + for (String perm : permissions) { + if (result != null) { + result.onResult(perm, PackageManager.PERMISSION_GRANTED); + } + } return; } List permList = new ArrayList<>(); for (String perm : permissions) { - if (activity.checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED - && !mPendingRequests.contains(perm)) { - permList.add(perm); + if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { + if (!mPendingRequests.contains(perm)) { + permList.add(perm); + } + } else { + if (result != null) { + result.onResult(perm, PackageManager.PERMISSION_GRANTED); + } } } if (!permList.isEmpty()) { String[] permsToRequest = permList.toArray(new String[permList.size()]); mPendingRequests.addAll(permList); - activity.requestPermissions(permsToRequest, 1); + ActivityCompat.requestPermissions(activity, permsToRequest, 1); } } - public static boolean checkPermission(Activity activity, @NonNull String permission) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return true; - } else if (activity == null) { - return false; - } - return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; - } - public static boolean checkPermissions(Activity activity, @NonNull String[] permissions) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { return true; @@ -66,9 +83,40 @@ public class PermissionsManager { return permissionsNecessary; } - public void notifyPermissionsChange(String[] permissions) { - for (String perm : permissions) { - mPendingRequests.remove(perm); + public void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) { + int size = permissions.length; + if (results.length < size) { + size = results.length; + } + for (int n = 0; n < size; n++) { + for (PermissionResult result : mPendingActions) { + result.onResult(permissions[n], results[n]); + mPendingRequests.remove(permissions[n]); + } + } + } + + public static abstract class PermissionResult { + + private Set mPermissions = new HashSet<>(); + + public abstract void onGranted(); + + public abstract void onDenied(String permission); + + public void onResult(String permission, int result) { + if (result == PackageManager.PERMISSION_GRANTED) { + mPermissions.remove(permission); + if (mPermissions.isEmpty()) { + onGranted(); + } + } else { + onDenied(permission); + } + } + + public void addPermissions(@NonNull String[] perms) { + Collections.addAll(mPermissions, perms); } } diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index c5c5985..d55a0fd 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -3,6 +3,7 @@ */ package acr.browser.lightning.utils; +import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; @@ -44,10 +45,22 @@ public final class Utils { public static void downloadFile(final Activity activity, final String url, final String userAgent, final String contentDisposition) { - String fileName = URLUtil.guessFileName(url, null, null); - DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null - ); - Log.i(Constants.TAG, "Downloading" + fileName); + PermissionsManager.getInstance().requestPermissionsIfNecessary(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() { + @Override + public void onGranted() { + String fileName = URLUtil.guessFileName(url, null, null); + DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null + ); + Log.i(Constants.TAG, "Downloading" + fileName); + } + + @Override + public void onDenied(String permission) { + // TODO Show Message + } + }); + } public static Intent newEmailIntent(String address, String subject, diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 7167582..886d935 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -61,12 +61,14 @@ class LightningChromeClient extends WebChromeClient { if (icon == null) return; mLightningView.mTitle.setFavicon(icon); - eventBus.post(new BrowserEvents.TabsChanged()); ; + 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) { @@ -112,35 +114,43 @@ class LightningChromeClient extends WebChromeClient { @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(); + PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS, new PermissionsManager.PermissionResult() { + @Override + public void onGranted() { + 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 void onDenied(String permission) { + //TODO show message and/or turn off setting + } + }); } @Override 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 2bc41fc..1b889d0 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -39,6 +39,7 @@ import java.io.FileOutputStream; import java.io.IOException; import javax.inject.Inject; + import java.util.ArrayList; import java.util.List; @@ -198,9 +199,6 @@ public class LightningView { if (!mIsIncognitoTab) { settings.setGeolocationEnabled(mPreferences.getLocationEnabled()); - if (mPreferences.getLocationEnabled() && !PermissionsManager.checkPermissions(mActivity, PERMISSIONS)) { - mPermissionsManager.requestPermissionsIfNecessary(mActivity, PERMISSIONS); - } } else { settings.setGeolocationEnabled(false); } @@ -527,6 +525,7 @@ 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) { @@ -591,6 +590,7 @@ public class LightningView { 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 @@ -741,7 +741,7 @@ public class LightningView { msg.setTarget(webViewHandler); mWebView.requestFocusNodeHref(msg); } - } + } } /** From ce0e02585c4f02e3607d7e76a1ab64f186f0b8cc Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Wed, 14 Oct 2015 23:23:04 -0400 Subject: [PATCH 30/58] Document the PermissionsManager --- .../download/LightningDownloadListener.java | 2 +- .../fragment/BookmarkSettingsFragment.java | 6 +- .../lightning/utils/PermissionsManager.java | 102 +++++++++++++----- .../acr/browser/lightning/utils/Utils.java | 2 +- .../lightning/view/LightningChromeClient.java | 3 +- 5 files changed, 79 insertions(+), 36 deletions(-) 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 f58d24b..bf6a67e 100644 --- a/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java +++ b/app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java @@ -26,7 +26,7 @@ public class LightningDownloadListener implements DownloadListener { @Override public void onDownloadStart(final String url, final String userAgent, final String contentDisposition, final String mimetype, long contentLength) { - PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(mActivity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() { @Override public void onGranted() { diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index ea8e980..66f37b0 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -88,7 +88,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref PermissionsManager permissionsManager = PermissionsManager.getInstance(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, null); + permissionsManager.requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, null); } } @@ -127,7 +127,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref // if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { // mBookmarkManager.exportBookmarks(getActivity()); // } - PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, + PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, new PermissionsManager.PermissionResult() { @Override public void onGranted() { @@ -145,7 +145,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref // loadFileList(null); // createDialog(); // } - PermissionsManager.getInstance().requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS, + PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, new PermissionsManager.PermissionResult() { @Override public void onGranted() { diff --git a/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java b/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java index 93a6aea..f8a2c91 100644 --- a/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java +++ b/app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java @@ -14,30 +14,53 @@ import java.util.List; import java.util.Set; /** - * Copyright 8/22/2015 Anthony Restaino + * A class to help you manage your permissions */ public final class PermissionsManager { - private static PermissionsManager mInstance; - private final Set mPendingRequests = new HashSet<>(); - private final List mPendingActions = new ArrayList<>(); + private final static PermissionsManager INSTANCE = new PermissionsManager(); + private final Set mPendingRequests = new HashSet<>(1); + private final List mPendingActions = new ArrayList<>(1); public static PermissionsManager getInstance() { - if (mInstance == null) { - mInstance = new PermissionsManager(); - } - return mInstance; + return INSTANCE; } - private void addPendingAction(@NonNull String[] permissions, @Nullable PermissionResult result) { + /** + * This method adds the {@link PermissionResult} to the current list + * of pending actions that will be completed when the permissions are + * received. The list of permissions passed to this method are registered + * in the PermissionResult object so that it will be notified of changes + * made to these permissions. + * + * @param permissions the required permissions for the result to be executed + * @param result the result to add to the current list of pending actions + */ + private synchronized void addPendingAction(@NonNull String[] permissions, @Nullable PermissionResult result) { if (result == null) { return; } - result.addPermissions(permissions); + result.registerPermissions(permissions); mPendingActions.add(result); } - public void requestPermissionsIfNecessary(@Nullable Activity activity, @NonNull String[] permissions, @Nullable PermissionResult result) { + /** + * This method should be used to execute a {@link PermissionResult} for the array + * of permissions passed to this method. This method will request the permissions if + * they need to be requested (i.e. we don't have permission yet) and will add the + * PermissionResult to the queue to be notified of permissions being granted or + * denied. In the case of pre-Android Marshmallow, permissions will be granted immediately. + * The Activity variable is nullable, but if it is null, the method will fail to execute. + * This is only nullable as a courtesy for Fragments where getActivity() may yeild null + * if the Fragment is not currently added to its parent Activity. + * + * @param activity the activity necessary to request the permissions + * @param permissions the list of permissions to request for the {@link PermissionResult} + * @param result the PermissionResult to notify when the permissions are granted or denied + */ + public synchronized void requestPermissionsIfNecessaryForResult(@Nullable Activity activity, + @NonNull String[] permissions, + @Nullable PermissionResult result) { if (activity == null) { return; } @@ -50,7 +73,7 @@ public final class PermissionsManager { } return; } - List permList = new ArrayList<>(); + List permList = new ArrayList<>(1); for (String perm : permissions) { if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) { if (!mPendingRequests.contains(perm)) { @@ -70,20 +93,16 @@ public final class PermissionsManager { } - public static boolean checkPermissions(Activity activity, @NonNull String[] permissions) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return true; - } else if (activity == null) { - return false; - } - boolean permissionsNecessary = true; - for (String perm : permissions) { - permissionsNecessary &= activity.checkSelfPermission(perm) == PackageManager.PERMISSION_GRANTED; - } - return permissionsNecessary; - } - - public void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) { + /** + * This method notifies the PermissionsManager that the permissions have change. It should + * be called from the Activity callback onRequestPermissionsResult() with the variables + * passed to that method. It will notify all the pending PermissionResult objects currently + * in the queue, and will remove the permissions request from the list of pending requests. + * + * @param permissions the permissions that have changed + * @param results the values for each permission + */ + public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) { int size = permissions.length; if (results.length < size) { size = results.length; @@ -96,15 +115,33 @@ public final class PermissionsManager { } } + /** + * This abstract class should be used to create an if/else action that the PermissionsManager + * can execute when the permissions you request are granted or denied. Simple use involves + * creating an anonymous instance of it and passing that instance to the + * requestPermissionsIfNecessaryForResult method. The result will be sent back to you as + * either onGranted (all permissions have been granted), or onDenied (a required permission + * has been denied). Ideally you put your functionality in the onGranted method and notify + * the user what won't work in the onDenied method. + */ public static abstract class PermissionResult { - private Set mPermissions = new HashSet<>(); + private final Set mPermissions = new HashSet<>(1); public abstract void onGranted(); public abstract void onDenied(String permission); - public void onResult(String permission, int result) { + /** + * This method is called when a particular permission has changed. + * This method will be called for all permissions, so this method determines + * if the permission affects the state or not and whether it can proceed with + * calling onGranted or if onDenied should be called. + * + * @param permission the permission that changed + * @param result the result for that permission + */ + public synchronized final void onResult(String permission, int result) { if (result == PackageManager.PERMISSION_GRANTED) { mPermissions.remove(permission); if (mPermissions.isEmpty()) { @@ -115,7 +152,14 @@ public final class PermissionsManager { } } - public void addPermissions(@NonNull String[] perms) { + /** + * This method registers the PermissionResult object for the specified permissions + * so that it will know which permissions to look for changes to. The PermissionResult + * will then know to look out for changes to these permissions. + * + * @param perms the permissions to listen for + */ + public synchronized final void registerPermissions(@NonNull String[] perms) { Collections.addAll(mPermissions, perms); } } diff --git a/app/src/main/java/acr/browser/lightning/utils/Utils.java b/app/src/main/java/acr/browser/lightning/utils/Utils.java index d55a0fd..282204c 100644 --- a/app/src/main/java/acr/browser/lightning/utils/Utils.java +++ b/app/src/main/java/acr/browser/lightning/utils/Utils.java @@ -45,7 +45,7 @@ public final class Utils { public static void downloadFile(final Activity activity, final String url, final String userAgent, final String contentDisposition) { - PermissionsManager.getInstance().requestPermissionsIfNecessary(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, + PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsManager.PermissionResult() { @Override public void onGranted() { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 886d935..cefb5be 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -1,7 +1,6 @@ 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; @@ -114,7 +113,7 @@ class LightningChromeClient extends WebChromeClient { @Override public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) { - PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS, new PermissionsManager.PermissionResult() { + PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(mActivity, PERMISSIONS, new PermissionsManager.PermissionResult() { @Override public void onGranted() { final boolean remember = true; From 88549bf1560b7b74becb4258efd0e9e48c6ec69b Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Wed, 14 Oct 2015 23:58:47 -0400 Subject: [PATCH 31/58] Fixed number of UI bugs recently introduced in Tabs changes merge from S. Pacifici --- .../lightning/fragment/BookmarksFragment.java | 30 +++++++++++++++++-- .../lightning/fragment/TabsFragment.java | 4 +-- .../lightning/view/LightningChromeClient.java | 5 +--- .../lightning/view/LightningWebClient.java | 1 + 4 files changed, 31 insertions(+), 9 deletions(-) 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 9122932..447a1b8 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,7 @@ package acr.browser.lightning.fragment; import android.content.Context; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.os.Bundle; @@ -36,16 +37,20 @@ import javax.inject.Inject; import acr.browser.lightning.R; import acr.browser.lightning.activity.BrowserActivity; +import acr.browser.lightning.activity.ReadingActivity; +import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.async.AsyncExecutor; import acr.browser.lightning.bus.BookmarkEvents; import acr.browser.lightning.bus.BrowserEvents; +import acr.browser.lightning.constant.Constants; import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.async.ImageDownloadTask; import acr.browser.lightning.utils.ThemeUtils; +import acr.browser.lightning.view.LightningView; /** * Created by Stefano Pacifici on 25/08/15. Based on Anthony C. Restaino's code. @@ -71,6 +76,9 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @Inject PreferenceManager mPreferenceManager; + @Inject + TabsManager mTabsManager; + // Adapter private BookmarkViewAdapter mBookmarkAdapter; @@ -165,6 +173,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, } }); setupNavigationButton(view, R.id.action_add_bookmark, R.id.icon_star); + setupNavigationButton(view, R.id.action_reading, R.id.icon_reading); + setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop); // Must be called here, only here we have a reference to the ListView new Thread(mInitBookmarkManager).run(); @@ -232,8 +242,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) { @@ -308,6 +318,22 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, case R.id.action_add_bookmark: mEventBus.post(new BookmarkEvents.WantToBookmarkCurrentPage()); break; + case R.id.action_reading: + LightningView currentTab = mTabsManager.getCurrentTab(); + if (currentTab != null) { + Intent read = new Intent(getActivity(), ReadingActivity.class); + read.putExtra(Constants.LOAD_READING_URL, currentTab.getUrl()); + startActivity(read); + } + break; + case R.id.action_toggle_desktop: + LightningView current = mTabsManager.getCurrentTab(); + if (current != null) { + current.toggleDesktopUA(getActivity()); + current.reload(); + // TODO add back drawer closing + } + break; default: break; } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index a0945ad..0e68097 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -29,7 +29,6 @@ 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; @@ -38,8 +37,6 @@ 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; @@ -114,6 +111,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View if (mShowInNavigationDrawer) { view = inflater.inflate(R.layout.tab_drawer, container, false); layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); + setupFrameLayoutButton(view, R.id.tab_header_button, R.id.plusIcon); 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); diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index cefb5be..7c4983c 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -57,11 +57,8 @@ class LightningChromeClient extends WebChromeClient { @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); } @@ -70,7 +67,7 @@ class LightningChromeClient extends WebChromeClient { * * @param icon the icon to cache */ - private void cacheFavicon(final String url, final Bitmap icon) { + private static void cacheFavicon(final String url, final Bitmap icon) { if (icon == null) return; final Uri uri = Uri.parse(url); if (uri.getHost() == null) { diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index b57556e..1d4667f 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -100,6 +100,7 @@ public class LightningWebClient extends WebViewClient { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { + mLightningView.mTitle.setFavicon(null); if (mLightningView.isShown()) { mActivity.updateUrl(url, false); mActivity.showActionBar(); From 72ee377a351549faa75423d833cde04e81a8ca72 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Thu, 15 Oct 2015 20:24:04 -0400 Subject: [PATCH 32/58] Fixed more bugs recently introduced. Hardened asynctasks against memory leaks. Fixed some other stuff --- .../lightning/activity/BrowserActivity.java | 132 ++++++++++-------- .../lightning/activity/ReadingActivity.java | 26 ++-- .../lightning/database/BookmarkLocalSync.java | 2 +- .../fragment/BookmarkSettingsFragment.java | 30 ++-- .../lightning/object/SearchAdapter.java | 2 +- .../browser/lightning/view/LightningView.java | 20 ++- 6 files changed, 130 insertions(+), 82 deletions(-) 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 4953fee..38d2de8 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -161,11 +161,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private ValueCallback mFilePathCallback; // Primatives - private boolean mFullScreen, mColorMode, mDarkTheme, - mIsNewIntent = false, - mIsFullScreen = false, - mIsImmersive = false, - mShowTabsInDrawer; + private boolean mFullScreen; + private boolean mDarkTheme; + private boolean mIsNewIntent = false; + private boolean mIsFullScreen = false; + private boolean mIsImmersive = false; + private boolean mShowTabsInDrawer; private int mOriginalOrientation, mBackgroundColor, mIdGenerator, mIconColor, mCurrentUiColor = Color.BLACK; private String mSearchText, mUntitledTitle, mHomepage, mCameraPhotoPath; @@ -405,7 +406,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements if (!hasFocus && currentView != null) { setIsLoading(currentView.getProgress() < 100); updateUrl(currentView.getUrl(), true); - } else if (hasFocus) { + } else if (hasFocus && currentView != null) { String url = currentView.getUrl(); if (url.startsWith(Constants.FILE)) { mSearch.setText(""); @@ -559,11 +560,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private void initializePreferences() { final LightningView currentView = tabsManager.getCurrentTab(); - final WebView currentWebView = currentView.getWebView(); + final WebView currentWebView = tabsManager.getCurrentWebView(); mFullScreen = mPreferences.getFullScreenEnabled(); - mColorMode = mPreferences.getColorModeEnabled(); - mColorMode &= !mDarkTheme; - if (!isIncognito() && !mColorMode && !mDarkTheme && mWebpageBitmap != null) { + boolean colorMode = mPreferences.getColorModeEnabled(); + colorMode &= !mDarkTheme; + if (!isIncognito() && !colorMode && !mDarkTheme && mWebpageBitmap != null) { changeToolbarBackground(mWebpageBitmap, null); } else if (!isIncognito() && currentView != null && !mDarkTheme && currentView.getFavicon() != null) { @@ -731,9 +732,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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); + if (currentView != null) { + Intent read = new Intent(this, ReadingActivity.class); + read.putExtra(Constants.LOAD_READING_URL, currentView.getUrl()); + startActivity(read); + } return true; default: return super.onOptionsItemSelected(item); @@ -822,6 +825,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements final WebView currentWebView = currentView != null ? currentView.getWebView() : null; final LightningView newView = tabsManager.switchToTab(position); final WebView newWebView = newView != null ? newView.getWebView() : null; + if (newView == null || newWebView == null) { + return; + } // Set the background color so the color mode color doesn't show through mBrowserFrame.setBackgroundColor(mBackgroundColor); @@ -946,7 +952,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } } - synchronized boolean newTab(String url, boolean show) { + private 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); @@ -984,11 +990,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements return; } -// What? int current = tabsManager.positionOf(currentTab); - if (current < 0) { - return; - } + if (!tabToDelete.getUrl().startsWith(Constants.FILE) && !isIncognito()) { mPreferences.setSavedUrl(tabToDelete.getUrl()); } @@ -1016,9 +1019,11 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements showTab(position - 1); mEventBus.post(new BrowserEvents.TabsChanged()); } else { + tabsManager.deleteTab(position); } } else { - if (currentTab.getUrl().startsWith(Constants.FILE) || currentTab.getUrl().equals(mHomepage)) { + if (currentTab != null && (currentTab.getUrl().startsWith(Constants.FILE) + || currentTab.getUrl().equals(mHomepage))) { closeActivity(); } else { tabsManager.deleteTab(position); @@ -1130,7 +1135,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements void saveOpenTabs() { if (mPreferences.getRestoreLostTabsEnabled()) { final String s = tabsManager.tabsString(); - mPreferences.setMemoryUrl(s.toString()); + mPreferences.setMemoryUrl(s); } } @@ -1192,8 +1197,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } String searchUrl = mSearchText + UrlUtils.QUERY_PLACE_HOLDER; query = query.trim(); - currentTab.stopLoading(); if (currentTab != null) { + currentTab.stopLoading(); loadUrlInCurrentView(UrlUtils.smartUrlFilter(query, true, searchUrl)); } } @@ -1318,30 +1323,34 @@ 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); 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(); + public void onItemClick(AdapterView adapterView, View view, int pos, long l) { + String url = null; + CharSequence urlString = ((TextView) view.findViewById(R.id.url)).getText(); + if (urlString != null) { + url = urlString.toString(); + } + if (url == null || url.startsWith(BrowserActivity.this.getString(R.string.suggestion))) { + CharSequence searchString = ((TextView) view.findViewById(R.id.title)).getText(); + if (searchString != null) { + url = searchString.toString(); } - } catch (NullPointerException e) { - Log.e("Browser Error: ", "NullPointerException on item click"); + } + if (url == null) { + return; + } + getUrl.setText(url); + searchTheWeb(url); + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(getUrl.getWindowToken(), 0); + final LightningView currentTab = tabsManager.getCurrentTab(); + if (currentTab != null) { + currentTab.requestFocus(); } } @@ -1521,7 +1530,9 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mFullscreenContainer.addView(mCustomView, COVER_SCREEN_PARAMS); decor.addView(mFullscreenContainer, COVER_SCREEN_PARAMS); setFullscreen(true, true); - currentTab.setVisibility(View.GONE); + if (currentTab != null) { + currentTab.setVisibility(View.GONE); + } if (view instanceof FrameLayout) { if (((FrameLayout) view).getFocusedChild() instanceof VideoView) { mVideoView = (VideoView) ((FrameLayout) view).getFocusedChild(); @@ -1633,16 +1644,20 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * the newly created WebView. */ @Override - public void onCreateWindow(Message resultMsg) { + public synchronized 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(); + LightningView newTab = tabsManager.getTabAtPosition(tabsManager.size() - 1); + if (newTab != null) { + final WebView webView = newTab.getWebView(); + if (webView != null) { + WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + transport.setWebView(webView); + resultMsg.sendToTarget(); + } + } } } @@ -1666,8 +1681,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements */ @Override public void hideActionBar() { - final LightningView currentTab = tabsManager.getCurrentTab(); - final WebView currentWebView = currentTab.getWebView(); + final WebView currentWebView = tabsManager.getCurrentWebView(); if (mFullScreen) { if (mBrowserFrame.findViewById(R.id.toolbar_layout) == null) { mUiLayout.removeView(mToolbarLayout); @@ -1675,21 +1689,21 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements mToolbarLayout.bringToFront(); Log.d(Constants.TAG, "Move view to browser frame"); mToolbarLayout.setTranslationY(0); - currentWebView.setTranslationY(mToolbarLayout.getHeight()); + if (currentWebView != null) { + currentWebView.setTranslationY(mToolbarLayout.getHeight()); + } } - if (mToolbarLayout == null || currentTab == null) + if (mToolbarLayout == null || currentWebView == 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); + currentWebView.setTranslationY(trans); } }; show.setDuration(250); @@ -1791,25 +1805,27 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @Override public void onClick(View v) { final LightningView currentTab = tabsManager.getCurrentTab(); - final WebView currentWebView = currentTab.getWebView(); + if (currentTab == null) { + return; + } 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) { + } else { currentTab.loadHomepage(); } break; case R.id.button_next: - currentWebView.findNext(false); + currentTab.findNext(); break; case R.id.button_back: - currentWebView.findNext(true); + currentTab.findPrevious(); break; case R.id.button_quit: - currentWebView.clearMatches(); + currentTab.clearFindMatches(); mSearchBar.setVisibility(View.GONE); break; case R.id.action_reading: @@ -1963,7 +1979,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @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(); @@ -1981,7 +1996,6 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements @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(); 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 e1847b6..d2733f5 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java @@ -21,6 +21,8 @@ import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; +import java.lang.ref.WeakReference; + import acr.browser.lightning.R; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; @@ -39,6 +41,7 @@ public class ReadingActivity extends AppCompatActivity { private PreferenceManager mPreferences; private int mTextSize; private ProgressDialog mProgressDialog; + private PageLoader mLoaderReference; private static final float XXLARGE = 30.0f; private static final float XLARGE = 26.0f; @@ -130,29 +133,33 @@ public class ReadingActivity extends AppCompatActivity { } if (getSupportActionBar() != null) getSupportActionBar().setTitle(Utils.getDomainName(mUrl)); - new PageLoader(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mUrl); + mLoaderReference = new PageLoader(this); + mLoaderReference.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mUrl); return true; } private class PageLoader extends AsyncTask { - private final Activity mActivity; + private final WeakReference mActivityReference; private String mTitleText; private String mBodyText; public PageLoader(Activity activity) { - mActivity = activity; + mActivityReference = new WeakReference<>(activity); } @Override protected void onPreExecute() { super.onPreExecute(); - mProgressDialog = new ProgressDialog(mActivity); - mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); - mProgressDialog.setCancelable(false); - mProgressDialog.setIndeterminate(true); - mProgressDialog.setMessage(mActivity.getString(R.string.loading)); - mProgressDialog.show(); + Activity activity = mActivityReference.get(); + if (activity != null) { + mProgressDialog = new ProgressDialog(activity); + mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + mProgressDialog.setCancelable(false); + mProgressDialog.setIndeterminate(true); + mProgressDialog.setMessage(activity.getString(R.string.loading)); + mProgressDialog.show(); + } } @Override @@ -224,6 +231,7 @@ public class ReadingActivity extends AppCompatActivity { mProgressDialog.dismiss(); mProgressDialog = null; } + mLoaderReference.cancel(true); super.onDestroy(); } diff --git a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java index c651f43..2857570 100644 --- a/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java +++ b/app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java @@ -26,7 +26,7 @@ public class BookmarkLocalSync { private final Context mContext; - public BookmarkLocalSync(Context context) { + public BookmarkLocalSync(@NonNull Context context) { mContext = context; } diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index 66f37b0..b51ec24 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -5,6 +5,7 @@ package acr.browser.lightning.fragment; import android.Manifest; import android.app.Activity; +import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Build; @@ -15,6 +16,7 @@ import android.preference.PreferenceFragment; import android.support.v7.app.AlertDialog; import java.io.File; +import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -45,9 +47,17 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; + private ImportBookmarksTask mImportTaskReference; private static final File mPath = new File(Environment.getExternalStorageDirectory().toString()); private class ImportBookmarksTask extends AsyncTask { + + private WeakReference mActivityReference; + + public ImportBookmarksTask(Activity activity) { + mActivityReference = new WeakReference<>(activity); + } + @Override protected Integer doInBackground(Void... params) { List list = null; @@ -67,10 +77,11 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @Override protected void onPostExecute(Integer num) { super.onPostExecute(num); - if (mActivity != null) { + Activity activity = mActivityReference.get(); + if (activity != null) { int number = num; - final String message = mActivity.getResources().getString(R.string.message_import); - Utils.showSnackbar(mActivity, number + " " + message); + final String message = activity.getResources().getString(R.string.message_import); + Utils.showSnackbar(activity, number + " " + message); } } } @@ -96,6 +107,9 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref public void onDestroy() { super.onDestroy(); mActivity = null; + if (mImportTaskReference != null) { + mImportTaskReference.cancel(false); + } } private void initPrefs() { @@ -124,9 +138,6 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref public boolean onPreferenceClick(Preference preference) { switch (preference.getKey()) { case SETTINGS_EXPORT: -// if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { -// mBookmarkManager.exportBookmarks(getActivity()); -// } PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, new PermissionsManager.PermissionResult() { @Override @@ -141,10 +152,6 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref }); return true; case SETTINGS_IMPORT: -// if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) { -// loadFileList(null); -// createDialog(); -// } PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, new PermissionsManager.PermissionResult() { @Override @@ -160,7 +167,8 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref }); return true; case SETTINGS_IMPORT_BROWSER: - new ImportBookmarksTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + mImportTaskReference = new ImportBookmarksTask(getActivity()); + mImportTaskReference.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return true; default: return false; 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 5789f9e..c79baee 100644 --- a/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java +++ b/app/src/main/java/acr/browser/lightning/object/SearchAdapter.java @@ -414,7 +414,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { return connectivity.getActiveNetworkInfo(); } - private List getFilteredList() { + private synchronized List getFilteredList() { List list = new ArrayList<>(5); synchronized (mBookmarks) { synchronized (mHistory) { 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 1b889d0..8bbd0d2 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -582,6 +582,24 @@ public class LightningView { } } + public synchronized void findNext() { + if (mWebView != null) { + mWebView.findNext(true); + } + } + + public synchronized void findPrevious() { + if (mWebView != null) { + mWebView.findNext(false); + } + } + + public synchronized void clearFindMatches() { + if (mWebView != null) { + mWebView.clearMatches(); + } + } + /** * Used by {@link LightningWebClient} * @@ -646,7 +664,7 @@ public class LightningView { } @Nullable - public WebView getWebView() { + public synchronized WebView getWebView() { return mWebView; } From 1c96b62eb6ba69085b9d5b1e21719cd1e8c7c016 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Thu, 15 Oct 2015 21:45:54 -0400 Subject: [PATCH 33/58] Add back SSL error detection that was removed, fixed static analysis warnings. --- .../lightning/activity/BrowserActivity.java | 2 +- .../lightning/activity/IncognitoActivity.java | 1 - .../lightning/activity/MainActivity.java | 1 - .../lightning/activity/TabsManager.java | 1 - .../activity/ThemableSettingsActivity.java | 1 - .../controller/BrowserController.java | 2 - .../lightning/database/HistoryDatabase.java | 3 +- .../dialog/LightningDialogBuilder.java | 1 - .../lightning/download/FetchUrlMimeType.java | 1 - .../fragment/BookmarkSettingsFragment.java | 3 +- .../lightning/fragment/BookmarksFragment.java | 7 +-- .../fragment/GeneralSettingsFragment.java | 1 - .../lightning/fragment/TabsFragment.java | 13 ++--- .../preference/PreferenceManager.java | 1 - .../reading/ArticleTextExtractor.java | 3 +- .../lightning/reading/HtmlFetcher.java | 50 ++++++++++-------- .../acr/browser/lightning/utils/AdBlock.java | 1 - .../browser/lightning/utils/IntentUtils.java | 1 - .../acr/browser/lightning/utils/WebUtils.java | 1 - .../lightning/view/LightningChromeClient.java | 2 +- .../browser/lightning/view/LightningView.java | 41 ++++++--------- .../lightning/view/LightningViewTitle.java | 2 +- .../lightning/view/LightningWebClient.java | 51 +++++++++++++++---- 23 files changed, 98 insertions(+), 92 deletions(-) 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 38d2de8..684ee5e 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -210,7 +210,7 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements private static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams( LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); - public abstract boolean isIncognito(); + protected abstract boolean isIncognito(); // abstract void initializeTabs(); 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 b46e42f..7a1149c 100644 --- a/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java @@ -7,7 +7,6 @@ import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import acr.browser.lightning.R; -import acr.browser.lightning.preference.PreferenceManager; @SuppressWarnings("deprecation") public class IncognitoActivity extends BrowserActivity { 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 808ea0c..a6974d9 100644 --- a/app/src/main/java/acr/browser/lightning/activity/MainActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/MainActivity.java @@ -7,7 +7,6 @@ import android.webkit.CookieManager; import android.webkit.CookieSyncManager; import acr.browser.lightning.R; -import acr.browser.lightning.preference.PreferenceManager; @SuppressWarnings("deprecation") public class MainActivity extends BrowserActivity { diff --git a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java index 7156d2f..7337b65 100644 --- a/app/src/main/java/acr/browser/lightning/activity/TabsManager.java +++ b/app/src/main/java/acr/browser/lightning/activity/TabsManager.java @@ -38,7 +38,6 @@ public class TabsManager { 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); 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 475c0ee..50abecb 100644 --- a/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java @@ -5,7 +5,6 @@ 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; public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivity { 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 a454386..2fc296f 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -3,13 +3,11 @@ */ package acr.browser.lightning.controller; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Message; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebChromeClient.CustomViewCallback; -import android.webkit.WebView; import acr.browser.lightning.view.LightningView; 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 36498fb..1e2e4ba 100644 --- a/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java +++ b/app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java @@ -16,7 +16,6 @@ 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 { @@ -73,7 +72,7 @@ public class HistoryDatabase extends SQLiteOpenHelper { mDatabase = this.getWritableDatabase(); } - public boolean isClosed() { + private boolean isClosed() { return mDatabase == null || !mDatabase.isOpen(); } diff --git a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java index b70d44d..93682ba 100644 --- a/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java +++ b/app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java @@ -6,7 +6,6 @@ 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; 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 3ba8e0c..bf34f3d 100644 --- a/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java +++ b/app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java @@ -20,7 +20,6 @@ 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; /** * This class is used to pull down the http headers of a given URL so that we diff --git a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java index b51ec24..26e5d53 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java @@ -5,7 +5,6 @@ package acr.browser.lightning.fragment; import android.Manifest; import android.app.Activity; -import android.content.Context; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Build; @@ -52,7 +51,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref private class ImportBookmarksTask extends AsyncTask { - private WeakReference mActivityReference; + private final WeakReference mActivityReference; public ImportBookmarksTask(Activity activity) { mActivityReference = new WeakReference<>(activity); 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 447a1b8..cde8686 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java @@ -36,7 +36,6 @@ import java.util.List; import javax.inject.Inject; import acr.browser.lightning.R; -import acr.browser.lightning.activity.BrowserActivity; import acr.browser.lightning.activity.ReadingActivity; import acr.browser.lightning.activity.TabsManager; import acr.browser.lightning.app.BrowserApp; @@ -95,8 +94,6 @@ 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 @@ -114,8 +111,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, BrowserApp.getAppComponent().inject(this); final Bundle arguments = getArguments(); final Context context = getContext(); - mIsIncognito = arguments.getBoolean(INCOGNITO_MODE, false); - boolean darkTheme = mPreferenceManager.getUseTheme() != 0 || mIsIncognito; + boolean isIncognito = arguments.getBoolean(INCOGNITO_MODE, false); + boolean darkTheme = mPreferenceManager.getUseTheme() != 0 || isIncognito; mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme); mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme); mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) : 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 37d53de..d3f6ac0 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java @@ -22,7 +22,6 @@ import android.widget.LinearLayout; import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.download.DownloadHandler; -import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index 0e68097..acab87c 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -21,6 +21,7 @@ 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.content.ContextCompat; import android.support.v4.view.ViewCompat; import android.support.v7.graphics.Palette; import android.support.v7.widget.LinearLayoutManager; @@ -249,6 +250,9 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View ViewCompat.jumpDrawablesToCurrentState(holder.exitButton); LightningView web = tabsManager.getTabAtPosition(position); + if (web == null) { + return; + } holder.txtTitle.setText(web.getTitle()); final Bitmap favicon = web.getFavicon(); @@ -326,14 +330,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View 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); - } + final int defaultColor = ContextCompat.getColor(getContext(), R.color.primary_color); if (mCurrentUiColor == Color.BLACK) { mCurrentUiColor = defaultColor; } 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 f087ea5..401a670 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -6,7 +6,6 @@ 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; diff --git a/app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java b/app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java index 07eb8ab..1de0507 100644 --- a/app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java +++ b/app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java @@ -491,8 +491,7 @@ public class ArticleTextExtractor { Element el = elems.get(0); if (el.hasAttr("content")) { dateStr = el.attr("content"); - Date parsedDate = parseDate(dateStr); - return parsedDate; + return parseDate(dateStr); } } diff --git a/app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java b/app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java index 1af5d3b..3c58342 100644 --- a/app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java +++ b/app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java @@ -33,6 +33,8 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; +import acr.browser.lightning.utils.Utils; + /** * Class to fetch articles. This class is thread safe. * @@ -49,28 +51,34 @@ public class HtmlFetcher { } public static void main(String[] args) throws Exception { - BufferedReader reader = new BufferedReader(new FileReader("urls.txt")); - String line; - Set existing = new LinkedHashSet<>(); - while ((line = reader.readLine()) != null) { - int index1 = line.indexOf('\"'); - int index2 = line.indexOf('\"', index1 + 1); - String url = line.substring(index1 + 1, index2); - String domainStr = SHelper.extractDomain(url, true); - String counterStr = ""; - // TODO more similarities - if (existing.contains(domainStr)) - counterStr = "2"; - else - existing.add(domainStr); - - String html = new HtmlFetcher().fetchAsString(url, 2000); - String outFile = domainStr + counterStr + ".html"; - BufferedWriter writer = new BufferedWriter(new FileWriter(outFile)); - writer.write(html); - writer.close(); + BufferedReader reader = null; + BufferedWriter writer = null; + try { + + reader = new BufferedReader(new FileReader("urls.txt")); + String line; + Set existing = new LinkedHashSet<>(); + while ((line = reader.readLine()) != null) { + int index1 = line.indexOf('\"'); + int index2 = line.indexOf('\"', index1 + 1); + String url = line.substring(index1 + 1, index2); + String domainStr = SHelper.extractDomain(url, true); + String counterStr = ""; + // TODO more similarities + if (existing.contains(domainStr)) + counterStr = "2"; + else + existing.add(domainStr); + + String html = new HtmlFetcher().fetchAsString(url, 2000); + String outFile = domainStr + counterStr + ".html"; + writer = new BufferedWriter(new FileWriter(outFile)); + writer.write(html); + } + } finally { + Utils.close(reader); + Utils.close(writer); } - reader.close(); } private String referrer = "http://jetsli.de/crawler"; 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 c434c33..82e9b61 100644 --- a/app/src/main/java/acr/browser/lightning/utils/AdBlock.java +++ b/app/src/main/java/acr/browser/lightning/utils/AdBlock.java @@ -15,7 +15,6 @@ import java.util.Set; import acr.browser.lightning.app.BrowserApp; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.preference.PreferenceManager; public class AdBlock { 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 dcb9d6b..21e6791 100644 --- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java @@ -2,7 +2,6 @@ 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 f05f2ae..609bedf 100644 --- a/app/src/main/java/acr/browser/lightning/utils/WebUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/WebUtils.java @@ -11,7 +11,6 @@ import android.webkit.WebView; import android.webkit.WebViewDatabase; import acr.browser.lightning.app.BrowserApp; -import acr.browser.lightning.database.HistoryDatabase; /** * Copyright 8/4/2015 Anthony Restaino diff --git a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java index 7c4983c..8f22b16 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java @@ -231,8 +231,8 @@ class LightningChromeClient extends WebChromeClient { 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, 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 8bbd0d2..715d295 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -4,7 +4,6 @@ package acr.browser.lightning.view; -import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; @@ -36,13 +35,9 @@ import com.squareup.otto.Bus; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.IOException; 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; @@ -53,7 +48,6 @@ import acr.browser.lightning.constant.StartPage; import acr.browser.lightning.dialog.LightningDialogBuilder; import acr.browser.lightning.download.LightningDownloadListener; import acr.browser.lightning.preference.PreferenceManager; -import acr.browser.lightning.utils.PermissionsManager; import acr.browser.lightning.utils.ProxyUtils; import acr.browser.lightning.utils.ThemeUtils; import acr.browser.lightning.utils.Utils; @@ -80,18 +74,16 @@ public class LightningView { 0, 0, -1.0f, 0, 255, // blue 0, 0, 0, 1.0f, 0 // alpha }; - private final PermissionsManager mPermissionsManager; - private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION}; - private final WebViewHandler webViewHandler = new WebViewHandler(); + private final WebViewHandler mWebViewHandler = new WebViewHandler(); @Inject - Bus eventBus; + Bus mEventBus; @Inject PreferenceManager mPreferences; @Inject - LightningDialogBuilder bookmarksDialogBuilder; + LightningDialogBuilder mBookmarksDialogBuilder; @SuppressLint("NewApi") public LightningView(BrowserActivity activity, String url, boolean darkTheme, boolean isIncognito) { @@ -100,7 +92,6 @@ public class LightningView { mWebView = new WebView(activity); mIsIncognitoTab = isIncognito; mTitle = new LightningViewTitle(activity, darkTheme); - mPermissionsManager = PermissionsManager.getInstance(); mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity(); @@ -410,7 +401,7 @@ public class LightningView { public void setForegroundTab(boolean isForeground) { isForegroundTab = isForeground; - eventBus.post(new BrowserEvents.TabsChanged()); + mEventBus.post(new BrowserEvents.TabsChanged()); } public boolean isForegroundTab() { @@ -568,7 +559,7 @@ public class LightningView { } } - public String getUserAgent() { + private String getUserAgent() { if (mWebView != null) { return mWebView.getSettings().getUserAgentString(); } else { @@ -620,36 +611,36 @@ public class LightningView { if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) { if (currentUrl.endsWith(HistoryPage.FILENAME)) { if (url != null) { - bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url); + mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl); } } else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) { if (url != null) { - bookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, url); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, url); } else if (result != null && result.getExtra() != null) { final String newUrl = result.getExtra(); - bookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(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()); + mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent()); } else { - bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); + mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); } } else { - bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url); + mBookmarksDialogBuilder.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()); + mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent()); } else { - bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl); + mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl); } } } @@ -754,9 +745,9 @@ public class LightningView { @Override public void onLongPress(MotionEvent e) { if (mCanTriggerLongPress) { - Message msg = webViewHandler.obtainMessage(); + Message msg = mWebViewHandler.obtainMessage(); if (msg != null) { - msg.setTarget(webViewHandler); + msg.setTarget(mWebViewHandler); mWebView.requestFocusNodeHref(msg); } } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java b/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java index 2452d85..f20dc86 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java @@ -60,7 +60,7 @@ class LightningViewTitle { return mFavicon; } - public Bitmap getDefaultIcon() { + public static 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 index 1d4667f..f814f01 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -27,6 +27,8 @@ import com.squareup.otto.Bus; import java.io.ByteArrayInputStream; import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; import acr.browser.lightning.R; import acr.browser.lightning.activity.BrowserActivity; @@ -42,7 +44,7 @@ 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 { +class LightningWebClient extends WebViewClient { private final BrowserActivity mActivity; private final LightningView mLightningView; @@ -70,6 +72,7 @@ public class LightningWebClient extends WebViewClient { return super.shouldInterceptRequest(view, request); } + @SuppressWarnings("deprecation") @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { if (mAdBlock.isAd(url)) { @@ -180,11 +183,45 @@ public class LightningWebClient extends WebViewClient { } } + private static 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(mActivity.getString(R.string.message_untrusted_certificate)) + builder.setMessage(alertMessage) .setCancelable(true) .setPositiveButton(mActivity.getString(R.string.action_yes), new DialogInterface.OnClickListener() { @@ -200,13 +237,7 @@ public class LightningWebClient extends WebViewClient { handler.cancel(); } }); - AlertDialog alert = builder.create(); - if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) { - alert.show(); - } else { - handler.proceed(); - } - + builder.create().show(); } @Override @@ -219,7 +250,6 @@ public class LightningWebClient extends WebViewClient { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { - resend.sendToTarget(); } }) @@ -227,7 +257,6 @@ public class LightningWebClient extends WebViewClient { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { - dontResend.sendToTarget(); } }); From 577efb76a41a7685689f0b0c337f10034484f6c1 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Thu, 15 Oct 2015 22:11:24 -0400 Subject: [PATCH 34/58] Fixed security vulnerability in the intent selector --- .../java/acr/browser/lightning/utils/IntentUtils.java | 9 +++++++-- .../acr/browser/lightning/view/LightningWebClient.java | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) 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..91944c7 100644 --- a/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java +++ b/app/src/main/java/acr/browser/lightning/utils/IntentUtils.java @@ -7,6 +7,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.Build; import android.util.Log; import android.webkit.WebView; @@ -39,6 +40,12 @@ public class IntentUtils { return false; } + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setComponent(null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { + intent.setSelector(null); + } + if (mActivity.getPackageManager().resolveActivity(intent, 0) == null) { String packagename = intent.getPackage(); if (packagename != null) { @@ -51,8 +58,6 @@ public class IntentUtils { return false; } } - intent.addCategory(Intent.CATEGORY_BROWSABLE); - intent.setComponent(null); if (tab != null) { intent.putExtra(mActivity.getPackageName() + ".Origin", 1); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java index f814f01..b27d524 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningWebClient.java @@ -293,6 +293,11 @@ class LightningWebClient extends WebViewClient { return false; } if (intent != null) { + intent.addCategory(Intent.CATEGORY_BROWSABLE); + intent.setComponent(null); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { + intent.setSelector(null); + } try { mActivity.startActivity(intent); } catch (ActivityNotFoundException e) { From 7bba86d96319b13464fcf1fa6dc6d6763f703478 Mon Sep 17 00:00:00 2001 From: Anthony Restaino Date: Thu, 15 Oct 2015 22:45:56 -0400 Subject: [PATCH 35/58] Fixed recently introduced UI bug in desktop tab mode. --- app/src/main/AndroidManifest.xml | 1 - .../lightning/activity/BrowserActivity.java | 19 ++-- .../controller/BrowserController.java | 16 ++- .../lightning/fragment/TabsFragment.java | 107 +++++------------- .../browser/lightning/view/LightningView.java | 17 ++- app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-v16/styles.xml | 8 ++ app/src/main/res/values/styles.xml | 1 - 8 files changed, 70 insertions(+), 100 deletions(-) create mode 100644 app/src/main/res/values-v16/styles.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c3d47ec..9b9b0a9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -88,7 +88,6 @@ - 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 684ee5e..9557061 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -28,6 +28,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; +import android.support.annotation.ColorInt; import android.support.annotation.IdRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -240,16 +241,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements 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); @@ -413,9 +410,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements } else { mSearch.setText(url); } - ((AutoCompleteTextView) v).selectAll(); // Hack to make sure - // the text gets - // selected + // Hack to make sure the text gets selected + ((AutoCompleteTextView) v).selectAll(); mIcon = mClearIcon; mSearch.setCompoundDrawables(null, null, mClearIcon, null); } @@ -1211,7 +1207,8 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements * @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) { + @Override + public 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; @@ -1259,6 +1256,12 @@ public abstract class BrowserActivity extends ThemableBrowserActivity implements }); } + @ColorInt + @Override + public int getUiColor() { + return mCurrentUiColor; + } + @Override public void updateUrl(String url, boolean shortUrl) { final LightningView currentTab = tabsManager.getCurrentTab(); 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 2fc296f..e5f860a 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -3,8 +3,13 @@ */ package acr.browser.lightning.controller; +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Message; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.View; import android.webkit.ValueCallback; import android.webkit.WebChromeClient.CustomViewCallback; @@ -13,6 +18,11 @@ import acr.browser.lightning.view.LightningView; public interface BrowserController { + void changeToolbarBackground(@NonNull Bitmap favicon, @Nullable Drawable drawable); + + @ColorInt + int getUiColor(); + void updateUrl(String title, boolean shortUrl); void updateProgress(int n); @@ -21,8 +31,6 @@ public interface BrowserController { void openFileChooser(ValueCallback uploadMsg); -// void onLongPress(); - void onShowCustomView(View view, CustomViewCallback callback); void onHideCustomView(); @@ -35,12 +43,8 @@ public interface BrowserController { void showActionBar(); - // void longClickPage(String url); - void showFileChooser(ValueCallback filePathCallback); void closeEmptyTab(); - // void updateBookmarkIndicator(String url); - } diff --git a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java index acab87c..cfa310a 100644 --- a/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java +++ b/app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java @@ -1,9 +1,6 @@ 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; @@ -13,7 +10,6 @@ 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; @@ -21,9 +17,7 @@ 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.content.ContextCompat; 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; @@ -46,14 +40,18 @@ 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.controller.BrowserController; 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 + * A fragment that holds and manages the tabs and interaction with the tabs. + * It is reliant on the BrowserController in order to get the current UI state + * of the browser. It also uses the BrowserController to signal that the UI needs + * to change. This class contains the adapter used by both the drawer tabs and + * the desktop tabs. It delegates touch events for the tab UI appropriately. */ public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener { @@ -70,16 +68,16 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View private int mIconColor; private boolean mColorMode = true; private boolean mShowInNavigationDrawer; - private int mCurrentUiColor = Color.BLACK; // TODO Only temporary private RecyclerView mRecyclerView; private LightningViewAdapter mTabsAdapter; + private BrowserController mUiController; @Inject TabsManager tabsManager; @Inject - Bus bus; + Bus mBus; @Inject PreferenceManager mPreferences; @@ -93,6 +91,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View super.onCreate(savedInstanceState); final Bundle arguments = getArguments(); final Context context = getContext(); + mUiController = (BrowserController) getActivity(); mIsIncognito = arguments.getBoolean(IS_INCOGNITO, false); mShowInNavigationDrawer = arguments.getBoolean(VERTICAL_MODE, true); mDarkTheme = mPreferences.getUseTheme() != 0 || mIsIncognito; @@ -106,7 +105,6 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final Bundle arguments = getArguments(); final View view; final LayoutManager layoutManager; if (mShowInNavigationDrawer) { @@ -148,7 +146,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public void onStart() { super.onStart(); - bus.register(this); + mBus.register(this); } @Override @@ -161,7 +159,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public void onStop() { super.onStop(); - bus.unregister(this); + mBus.unregister(this); } @Subscribe @@ -175,16 +173,16 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View public void onClick(View v) { switch (v.getId()) { case R.id.new_tab_button: - bus.post(new TabEvents.NewTab()); + mBus.post(new TabEvents.NewTab()); break; case R.id.action_back: - bus.post(new NavigationEvents.GoBack()); + mBus.post(new NavigationEvents.GoBack()); break; case R.id.action_forward: - bus.post(new NavigationEvents.GoForward()); + mBus.post(new NavigationEvents.GoForward()); break; case R.id.action_home: - bus.post(new NavigationEvents.GoHome()); + mBus.post(new NavigationEvents.GoHome()); default: break; } @@ -194,7 +192,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View public boolean onLongClick(View v) { switch (v.getId()) { case R.id.action_new_tab: - bus.post(new TabEvents.NewTabLongPress()); + mBus.post(new TabEvents.NewTabLongPress()); break; default: break; @@ -204,7 +202,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View public class LightningViewAdapter extends RecyclerView.Adapter { - private final int layoutResourceId; + private final int mLayoutResourceId; private final Drawable mBackgroundTabDrawable; private final Drawable mForegroundTabDrawable; private final Bitmap mForegroundTabBitmap; @@ -213,11 +211,11 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View private ColorFilter mFilter; private static final float DESATURATED = 0.5f; - private final boolean vertical; + private final boolean mDrawerTabs; public LightningViewAdapter(final boolean vertical) { - this.layoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal; - this.vertical = vertical; + this.mLayoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal; + this.mDrawerTabs = vertical; if (vertical) { mBackgroundTabDrawable = null; @@ -239,7 +237,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View @Override public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); - View view = inflater.inflate(layoutResourceId, viewGroup, false); + View view = inflater.inflate(mLayoutResourceId, viewGroup, false); return new LightningViewHolder(view); } @@ -263,10 +261,10 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View holder.txtTitle.setTextAppearance(getContext(), R.style.boldText); } Drawable foregroundDrawable; - if (!vertical) { + if (!mDrawerTabs) { foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap); if (!mIsIncognito && mColorMode) { - foregroundDrawable.setColorFilter(mCurrentUiColor, PorterDuff.Mode.SRC_IN); + foregroundDrawable.setColorFilter(mUiController.getUiColor(), PorterDuff.Mode.SRC_IN); } } else { foregroundDrawable = mForegroundTabDrawable; @@ -277,7 +275,7 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View holder.layout.setBackgroundDrawable(foregroundDrawable); } if (!mIsIncognito && mColorMode) { - changeToolbarBackground(favicon, foregroundDrawable); + mUiController.changeToolbarBackground(favicon, foregroundDrawable); } holder.favicon.setImageBitmap(favicon); } else { @@ -317,57 +315,6 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View 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 = ContextCompat.getColor(getContext(), 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) { @@ -394,17 +341,17 @@ public class TabsFragment extends Fragment implements View.OnClickListener, View public void onClick(View v) { if (v == exitButton) { // Close tab - bus.post(new TabEvents.CloseTab(getAdapterPosition())); + mBus.post(new TabEvents.CloseTab(getAdapterPosition())); } if (v == layout) { - bus.post(new TabEvents.ShowTab(getAdapterPosition())); + mBus.post(new TabEvents.ShowTab(getAdapterPosition())); } } @Override public boolean onLongClick(View v) { // Show close dialog - bus.post(new TabEvents.ShowCloseDialog(getAdapterPosition())); + mBus.post(new TabEvents.ShowCloseDialog(getAdapterPosition())); return true; } } 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 715d295..fa487fd 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -35,6 +35,7 @@ import com.squareup.otto.Bus; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.lang.ref.WeakReference; import javax.inject.Inject; @@ -74,7 +75,7 @@ public class LightningView { 0, 0, -1.0f, 0, 255, // blue 0, 0, 0, 1.0f, 0 // alpha }; - private final WebViewHandler mWebViewHandler = new WebViewHandler(); + private final WebViewHandler mWebViewHandler = new WebViewHandler(this); @Inject Bus mEventBus; @@ -773,12 +774,22 @@ public class LightningView { } } - private class WebViewHandler extends Handler { + private static class WebViewHandler extends Handler { + + private WeakReference mReference; + + public WebViewHandler(LightningView view) { + mReference = new WeakReference<>(view); + } + @Override public void handleMessage(Message msg) { super.handleMessage(msg); final String url = msg.getData().getString("url"); - longClickPage(url); + LightningView view = mReference.get(); + if (view != null) { + view.longClickPage(url); + } } } } diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 5c4c744..545b736 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -123,7 +123,6 @@ Licenze Open Source Cerca Blocca Annunci - Il certificato di questo sito non è sicuro. Vuoi procedere lo stesso? Reinvio Modulo Vuoi inviare nuovamente i dati? \nVorrebbe usare la tua posizione diff --git a/app/src/main/res/values-v16/styles.xml b/app/src/main/res/values-v16/styles.xml new file mode 100644 index 0000000..e5a495e --- /dev/null +++ b/app/src/main/res/values-v16/styles.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 53bd99c..a4f614a 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -123,7 +123,6 @@