Browse Source

Merge pull request #296 from stefano-cliqz/experimental_tabs

Experimental tabs
master
Anthony Restaino 9 years ago
parent
commit
5d55e480c9
  1. 2
      .gitignore
  2. 139
      app/app.iml
  3. 14
      app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java
  4. 13
      app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java
  5. 1137
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  6. 2129
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig
  7. 10
      app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
  8. 12
      app/src/main/java/acr/browser/lightning/activity/MainActivity.java
  9. 3
      app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
  10. 222
      app/src/main/java/acr/browser/lightning/activity/TabsManager.java
  11. 15
      app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java
  12. 5
      app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
  13. 32
      app/src/main/java/acr/browser/lightning/app/AppComponent.java
  14. 29
      app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
  15. 58
      app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
  16. 34
      app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java
  17. 65
      app/src/main/java/acr/browser/lightning/bus/TabEvents.java
  18. 5
      app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java
  19. 2
      app/src/main/java/acr/browser/lightning/constant/HistoryPage.java
  20. 5
      app/src/main/java/acr/browser/lightning/constant/StartPage.java
  21. 14
      app/src/main/java/acr/browser/lightning/controller/BrowserController.java
  22. 16
      app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
  23. 124
      app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java
  24. 75
      app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
  25. 16
      app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
  26. 18
      app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
  27. 41
      app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
  28. 45
      app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
  29. 42
      app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
  30. 107
      app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
  31. 27
      app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java
  32. 36
      app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
  33. 417
      app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java
  34. 30
      app/src/main/java/acr/browser/lightning/object/ClickHandler.java
  35. 23
      app/src/main/java/acr/browser/lightning/object/SearchAdapter.java
  36. 18
      app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
  37. 5
      app/src/main/java/acr/browser/lightning/utils/AdBlock.java
  38. 1
      app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
  39. 3
      app/src/main/java/acr/browser/lightning/utils/WebUtils.java
  40. 44
      app/src/main/java/acr/browser/lightning/view/IconCacheTask.java
  41. 250
      app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java
  42. 687
      app/src/main/java/acr/browser/lightning/view/LightningView.java
  43. 66
      app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java
  44. 276
      app/src/main/java/acr/browser/lightning/view/LightningWebClient.java
  45. 19
      app/src/main/res/layout/activity_main.xml
  46. 10
      app/src/main/res/layout/tab_drawer.xml
  47. 9
      app/src/main/res/layout/tab_strip.xml
  48. 7
      app/src/main/res/layout/toolbar.xml

2
.gitignore vendored

@ -50,3 +50,5 @@ out @@ -50,3 +50,5 @@ out
# Source:
# https://raw.githubusercontent.com/github/gitignore/master/Android.gitignore
# https://gitlab.com/fdroid/fdroidclient/raw/master/.gitignore
*.iml

139
app/app.iml

@ -1,139 +0,0 @@ @@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Lightning-Browser" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="lightningPlusDebug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleLightningPlusDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileLightningPlusDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleLightningPlusDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileLightningPlusDebugAndroidTestSources" />
<afterSyncTasks>
<task>generateLightningPlusDebugAndroidTestSources</task>
<task>generateLightningPlusDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/lightningPlus/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/lightningPlus/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/lightningPlus/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/lightningPlus/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/lightningPlus/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/lightningPlus/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/lightningPlus/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/lightningPlus/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/lightningPlus/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlusDebug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/lightningPlus/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/lightningPlus/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/lightningPlus/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/lightningPlus/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/lightningPlus/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/lightningPlus/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/palette-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.squareup.leakcanary/leakcanary-android/1.3.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/net.i2p.android/client/0.7/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="client-0.7" level="project" />
<orderEntry type="library" exported="" name="leakcanary-analyzer-1.3.1" level="project" />
<orderEntry type="library" exported="" name="jsr250-api-1.0" level="project" />
<orderEntry type="library" exported="" name="butterknife-7.0.1" level="project" />
<orderEntry type="library" exported="" name="dagger-2.0.1" level="project" />
<orderEntry type="library" exported="" name="leakcanary-watcher-1.3.1" level="project" />
<orderEntry type="library" exported="" name="otto-1.3.8" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />
<orderEntry type="library" exported="" name="haha-1.3" level="project" />
<orderEntry type="library" exported="" name="palette-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="design-23.0.1" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="javax.inject-1" level="project" />
<orderEntry type="library" exported="" name="jsoup-1.8.3" level="project" />
<orderEntry type="library" exported="" name="leakcanary-android-1.3.1" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.0.1" level="project" />
<orderEntry type="module" module-name="libnetcipher" exported="" />
</component>
</module>

14
app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java

@ -6,10 +6,13 @@ import android.content.DialogInterface; @@ -6,10 +6,13 @@ import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import com.squareup.otto.Bus;
import net.i2p.android.ui.I2PAndroidHelper;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@ -26,8 +29,11 @@ public class ProxyUtils { @@ -26,8 +29,11 @@ public class ProxyUtils {
private final PreferenceManager mPreferences;
private static ProxyUtils mInstance;
private final Bus mEventBus;
private ProxyUtils(Context context) {
mPreferences = PreferenceManager.getInstance();
mPreferences = BrowserApp.getAppComponent().getPreferenceManager();
mEventBus = BrowserApp.getAppComponent().getBus();
mI2PHelper = new I2PAndroidHelper(context.getApplicationContext());
}
@ -143,13 +149,13 @@ public class ProxyUtils { @@ -143,13 +149,13 @@ public class ProxyUtils {
}
public boolean isProxyReady(Activity activity) {
public boolean isProxyReady() {
if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) {
if (!mI2PHelper.isI2PAndroidRunning()) {
Utils.showSnackbar(activity, R.string.i2p_not_running);
mEventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_not_running));
return false;
} else if (!mI2PHelper.areTunnelsActive()) {
Utils.showSnackbar(activity, R.string.i2p_tunnels_not_ready);
mEventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_tunnels_not_ready));
return false;
}
}

13
app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java

@ -10,6 +10,7 @@ import net.i2p.android.ui.I2PAndroidHelper; @@ -10,6 +10,7 @@ import net.i2p.android.ui.I2PAndroidHelper;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@ -27,7 +28,7 @@ public class ProxyUtils { @@ -27,7 +28,7 @@ public class ProxyUtils {
private static ProxyUtils mInstance;
private ProxyUtils(Context context) {
mPreferences = PreferenceManager.getInstance();
mPreferences = BrowserApp.getAppComponent().getPreferenceManager();
mI2PHelper = new I2PAndroidHelper(context.getApplicationContext());
}
@ -143,13 +144,15 @@ public class ProxyUtils { @@ -143,13 +144,15 @@ public class ProxyUtils {
}
public boolean isProxyReady(Activity activity) {
public boolean isProxyReady() {
if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) {
if (!mI2PHelper.isI2PAndroidRunning()) {
Utils.showSnackbar(activity, R.string.i2p_not_running);
BrowserApp.getAppComponent().getBus()
.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_not_running));
return false;
} else if (!mI2PHelper.areTunnelsActive()) {
Utils.showSnackbar(activity, R.string.i2p_tunnels_not_ready);
BrowserApp.getAppComponent().getBus()
.post(new BrowserEvents.ShowSnackBarMessage(R.string.i2p_tunnels_not_ready));
return false;
}
}
@ -200,7 +203,7 @@ public class ProxyUtils { @@ -200,7 +203,7 @@ public class ProxyUtils {
break;
case Constants.PROXY_I2P:
I2PAndroidHelper ih = new I2PAndroidHelper(activity.getApplicationContext());
I2PAndroidHelper ih = new I2PAndroidHelper(BrowserApp.getAppContext());
if (!ih.isI2PAndroidInstalled()) {
choice = Constants.NO_PROXY;
ih.promptToInstall(activity);

1137
app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java

File diff suppressed because it is too large Load Diff

2129
app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java.orig

File diff suppressed because it is too large Load Diff

10
app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java

@ -18,13 +18,13 @@ public class IncognitoActivity extends BrowserActivity { @@ -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) {

12
app/src/main/java/acr/browser/lightning/activity/MainActivity.java

@ -18,14 +18,14 @@ public class MainActivity extends BrowserActivity { @@ -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) {

3
app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java

@ -22,6 +22,7 @@ import android.widget.SeekBar.OnSeekBarChangeListener; @@ -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 { @@ -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) {

222
app/src/main/java/acr/browser/lightning/activity/TabsManager.java

@ -0,0 +1,222 @@ @@ -0,0 +1,222 @@
package acr.browser.lightning.activity;
import android.app.Activity;
import android.content.Context;
import android.support.annotation.Nullable;
import android.webkit.WebView;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import acr.browser.lightning.controller.BrowserController;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.view.LightningView;
/**
* @author Stefano Pacifici
* @date 2015/09/14
*/
@Singleton
public class TabsManager {
private final List<LightningView> mWebViewList = new ArrayList<>();
private LightningView mCurrentTab;
@Inject
PreferenceManager mPreferenceManager;
@Inject
public TabsManager() {
}
public void restoreTabs(BrowserActivity activity, boolean darkTheme, boolean incognito) {
mWebViewList.clear();
mCurrentTab = null;
if (!incognito && mPreferenceManager.getRestoreLostTabsEnabled()) {
final String mem = mPreferenceManager.getMemoryUrl();
mPreferenceManager.setMemoryUrl("");
String[] array = Utils.getArray(mem);
int count = 0;
for (String urlString : array) {
if (!urlString.isEmpty()) {
newTab(activity, urlString, darkTheme, incognito);
}
}
}
if (mWebViewList.size() == 0) {
newTab(activity, null, darkTheme, incognito);
}
// mCurrentTab = mWebViewList.get(0);
}
/**
* Return a clone of the current tabs list. The list will not be updated, the user has to fetch
* a new copy when notified.
*
* @return a copy of the current tabs list
*/
public List<LightningView> getTabsList() {
return new ArrayList<>(mWebViewList);
}
/**
* Return the tab at the given position in tabs list, or null if position is not in tabs list
* range.
*
* @param position the index in tabs list
* @return the corespondent {@link LightningView}, or null if the index is invalid
*/
@Nullable
public LightningView getTabAtPosition(final int position) {
if (position < 0 || position >= mWebViewList.size()) {
return null;
}
return mWebViewList.get(position);
}
/**
* Try to low memory pressure
*/
public void freeMemory() {
for (LightningView tab: mWebViewList) {
tab.freeMemory();
}
}
/**
* Shutdown the manager
*/
public synchronized void shutdown() {
for (LightningView tab: mWebViewList) {
tab.onDestroy();
}
mWebViewList.clear();
}
/**
* Resume the tabs
*
* @param context
*/
public synchronized void resume(final Context context) {
for (LightningView tab: mWebViewList) {
tab.initializePreferences(null, context);
}
}
/**
* Forward network connection status to the webviews.
*
* @param isConnected
*/
public synchronized void notifyConnectioneStatus(final boolean isConnected) {
for (LightningView tab: mWebViewList) {
final WebView webView = tab.getWebView();
if (webView != null) {
webView.setNetworkAvailable(isConnected);
}
}
}
/**
* @return The number of currently opened tabs
*/
public int size() {
return mWebViewList.size();
}
/**
* Create and return a new tab. The tab is automatically added to the tabs list.
*
* @param activity
* @param url
* @param darkTheme
* @param isIncognito
* @return
*/
public synchronized LightningView newTab(final BrowserActivity activity,
final String url, final boolean darkTheme,
final boolean isIncognito) {
final LightningView tab = new LightningView(activity, url, darkTheme, isIncognito);
mWebViewList.add(tab);
return tab;
}
/**
* Remove a tab and return its reference or null if the position is not in tabs range
*
* @param position The position of the tab to remove
* @return The removed tab reference or null
*/
@Nullable
public synchronized LightningView deleteTab(final int position) {
if (position >= mWebViewList.size()) {
return null;
}
final LightningView tab = mWebViewList.remove(position);
tab.onDestroy();
return tab;
}
/**
* Return the position of the given tab
* @param tab
* @return
*/
public int positionOf(final LightningView tab) {
return mWebViewList.indexOf(tab);
}
/**
* @return A string representation of the currently opened tabs
*/
public String tabsString() {
final StringBuilder builder = new StringBuilder();
for (LightningView tab: mWebViewList) {
final String url = tab.getUrl();
if (url != null && !url.isEmpty()) {
builder.append(url).append("|$|SEPARATOR|$|");
}
}
return builder.toString();
}
/**
* Return the {@link WebView} associated to the current tab, or null if there is no current tab
* @return a {@link WebView} or null
*/
@Nullable
public WebView getCurrentWebView() {
return mCurrentTab != null ? mCurrentTab.getWebView() : null;
}
/**
* TODO We should remove also this, but probably not
* @return
*/
public LightningView getCurrentTab() {
return mCurrentTab;
}
/**
* Switch the current tab to the one at the given position. It returns the selected. After this
* call {@link TabsManager#getCurrentTab()} return the same reference returned by this method if
* position is valid.
*
* @return the selected tab or null if position is out of tabs range
*/
@Nullable
public LightningView switchToTab(final int position) {
if (position < 0 || position >= mWebViewList.size()) {
return null;
} else {
final LightningView tab = mWebViewList.get(position);
mCurrentTab = tab;
return tab;
}
}
}

15
app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java

@ -5,18 +5,25 @@ import android.content.res.Configuration; @@ -5,18 +5,25 @@ import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import javax.inject.Inject;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
public abstract class ThemableBrowserActivity extends AppCompatActivity {
@Inject
PreferenceManager mPreferences;
private int mTheme;
private boolean mShowTabsInDrawer;
@Override
protected void onCreate(Bundle savedInstanceState) {
mTheme = PreferenceManager.getInstance().getUseTheme();
mShowTabsInDrawer = PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet());
BrowserApp.getAppComponent().inject(this);
mTheme = mPreferences.getUseTheme();
mShowTabsInDrawer = mPreferences.getShowTabsInDrawer(!isTablet());
// set the theme
if (mTheme == 1) {
@ -30,8 +37,8 @@ public abstract class ThemableBrowserActivity extends AppCompatActivity { @@ -30,8 +37,8 @@ public abstract class ThemableBrowserActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
int theme = PreferenceManager.getInstance().getUseTheme();
boolean drawerTabs = PreferenceManager.getInstance().getShowTabsInDrawer(!isTablet());
int theme = mPreferences.getUseTheme();
boolean drawerTabs = mPreferences.getShowTabsInDrawer(!isTablet());
if (theme != mTheme || mShowTabsInDrawer != drawerTabs) {
restart();
}

5
app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java

@ -4,6 +4,7 @@ import android.graphics.drawable.ColorDrawable; @@ -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 @@ -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 @@ -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();
}
}

32
app/src/main/java/acr/browser/lightning/app/AppComponent.java

@ -1,13 +1,23 @@ @@ -1,13 +1,23 @@
package acr.browser.lightning.app;
import android.content.Context;
import com.squareup.otto.Bus;
import javax.inject.Singleton;
import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.activity.ThemableBrowserActivity;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.dialog.BookmarksDialogBuilder;
import acr.browser.lightning.database.HistoryDatabase;
import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.fragment.BookmarkSettingsFragment;
import acr.browser.lightning.fragment.BookmarksFragment;
import acr.browser.lightning.fragment.LightningPreferenceFragment;
import acr.browser.lightning.fragment.TabsFragment;
import acr.browser.lightning.object.SearchAdapter;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.view.LightningView;
import dagger.Component;
/**
@ -25,7 +35,25 @@ public interface AppComponent { @@ -25,7 +35,25 @@ public interface AppComponent {
void inject(SearchAdapter adapter);
void inject(BookmarksDialogBuilder builder);
void inject(LightningDialogBuilder builder);
void inject(BookmarkPage bookmarkPage);
void inject(TabsFragment fragment);
PreferenceManager getPreferenceManager();
void inject(LightningPreferenceFragment fragment);
BookmarkPage getBookmarkPage();
Bus getBus();
HistoryDatabase getHistoryDatabase();
Context getApplicationContext();
void inject(LightningView lightningView);
void inject(ThemableBrowserActivity activity);
}

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

@ -11,28 +11,6 @@ public final class BookmarkEvents { @@ -11,28 +11,6 @@ public final class BookmarkEvents {
// No instances
}
/**
* A bookmark was clicked
*/
public final static class Clicked {
public final HistoryItem bookmark;
public Clicked(final HistoryItem bookmark) {
this.bookmark = bookmark;
}
}
/**
* The user ask to open the bookmark as new tab
*/
public final static class AsNewTab {
public final HistoryItem bookmark;
public AsNewTab(final HistoryItem bookmark) {
this.bookmark = bookmark;
}
}
/**
* The user ask to delete the selected bookmark
*/
@ -61,13 +39,6 @@ public final class BookmarkEvents { @@ -61,13 +39,6 @@ public final class BookmarkEvents {
}
}
/**
* The {@link acr.browser.lightning.fragment.BookmarksFragment} want to know the url (and title)
* of the currently shown web page.
*/
// public static class WantInfoAboutCurrentPage {
// }
/**
* Sended by the {@link acr.browser.lightning.fragment.BookmarksFragment} when it wants to close
* itself (generally in reply to a {@link acr.browser.lightning.bus.BrowserEvents.UserPressedBack}

58
app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
package acr.browser.lightning.bus;
import android.support.annotation.StringRes;
/**
* Created by Stefano Pacifici on 26/08/15.
*/
@ -24,9 +26,8 @@ public final class BrowserEvents { @@ -24,9 +26,8 @@ public final class BrowserEvents {
}
/**
* Used to reply to {@link acr.browser.lightning.fragment.BookmarksFragment} message
* {@link acr.browser.lightning.bus.BookmarkEvents.WantInfoAboutCurrentPage}. This is generally
* used to update the {@link acr.browser.lightning.fragment.BookmarksFragment} interface.
* Notify the current page has a new url. This is generally used to update the
* {@link acr.browser.lightning.fragment.BookmarksFragment} interface.
*/
public static class CurrentPageUrl {
public final String url;
@ -41,4 +42,55 @@ public final class BrowserEvents { @@ -41,4 +42,55 @@ public final class BrowserEvents {
*/
public static class UserPressedBack {
}
/**
* Notify that the user closed or opened a tab
*/
public static class TabsChanged {
}
/**
*
*/
/**
* Notify the Browser to display a SnackBar in the main activity
*/
public static class ShowSnackBarMessage {
public final String message;
@StringRes
public final int stringRes;
public ShowSnackBarMessage(final String message) {
this.message = message;
this.stringRes = -1;
}
public ShowSnackBarMessage(@StringRes final int stringRes) {
this.message = null;
this.stringRes = stringRes;
}
}
/**
* The user want to open the given url in the current tab
*/
public final static class OpenUrlInCurrentTab {
public final String url;
public OpenUrlInCurrentTab(final String url) {
this.url = url;
}
}
/**
* The user ask to open the given url as new tab
*/
public final static class OpenUrlInNewTab {
public final String url;
public OpenUrlInNewTab(final String url) {
this.url = url;
}
}
}

34
app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
package acr.browser.lightning.bus;
/**
* Collections of navigation events, like go back or go forward
*
* @author Stefano Pacifici
* @date 2015/09/15
*/
public class NavigationEvents {
private NavigationEvents() {
// No instances please
}
/**
* Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses back
* button.
*/
public static class GoBack {
}
/**
* Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses forward
* button.
*/
public static class GoForward {
}
/**
* Fired by {@link acr.browser.lightning.fragment.TabsFragment} when the user presses the home
* button.
*/
public static class GoHome {
}
}

65
app/src/main/java/acr/browser/lightning/bus/TabEvents.java

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
package acr.browser.lightning.bus;
/**
* A collection of events been sent by {@link acr.browser.lightning.fragment.TabsFragment}
*
* @author Stefano Pacifici
* @date 2015/09/14
*/
public final class TabEvents {
private TabEvents() {
// No instances
}
/**
* Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the
* tab exit button
*/
public static class CloseTab {
public final int position;
public CloseTab(int position) {
this.position = position;
}
}
/**
* Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user click on the
* tab itself.
*/
public static class ShowTab {
public final int position;
public ShowTab(int position) {
this.position = position;
}
}
/**
* Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user long press on the
* tab itself.
*/
public static class ShowCloseDialog {
public final int position;
public ShowCloseDialog(int position) {
this.position = position;
}
}
/**
* Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user want to create a
* new tab.
*/
public static class NewTab {
}
/**
* Sended by {@link acr.browser.lightning.fragment.TabsFragment} when the user long presses on
* new tab button.
*/
public static class NewTabLongPress {
}
}

5
app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java

@ -62,7 +62,8 @@ public final class BookmarkPage { @@ -62,7 +62,8 @@ public final class BookmarkPage {
CACHE_DIR = context.getCacheDir();
}
public void buildBookmarkPage(final String folder, final List<HistoryItem> list) {
public void buildBookmarkPage(final String folder) {
final List<HistoryItem> 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 { @@ -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 {

2
app/src/main/java/acr/browser/lightning/constant/HistoryPage.java

@ -66,7 +66,7 @@ public class HistoryPage { @@ -66,7 +66,7 @@ public class HistoryPage {
}
private static List<HistoryItem> getWebHistory(Context context) {
HistoryDatabase databaseHandler = HistoryDatabase.getInstance();
HistoryDatabase databaseHandler = BrowserApp.getAppComponent().getHistoryDatabase();
return databaseHandler.getLastHundredItems();
}
}

5
app/src/main/java/acr/browser/lightning/constant/StartPage.java

@ -57,11 +57,12 @@ public class StartPage { @@ -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;

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

@ -23,18 +23,12 @@ public interface BrowserController { @@ -23,18 +23,12 @@ public interface BrowserController {
void openFileChooser(ValueCallback<Uri> uploadMsg);
void updateTabs();
void onLongPress();
// void onLongPress();
void onShowCustomView(View view, CustomViewCallback callback);
void onHideCustomView();
Bitmap getDefaultVideoPoster();
View getVideoLoadingProgressView();
void onCreateWindow(Message resultMsg);
void onCloseWindow(LightningView view);
@ -43,16 +37,12 @@ public interface BrowserController { @@ -43,16 +37,12 @@ public interface BrowserController {
void showActionBar();
void longClickPage(String url);
void openBookmarkPage(WebView view);
// void longClickPage(String url);
void showFileChooser(ValueCallback<Uri[]> filePathCallback);
void closeEmptyTab();
boolean proxyIsNotReady();
// void updateBookmarkIndicator(String url);
}

16
app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java

@ -12,9 +12,13 @@ import android.database.sqlite.SQLiteOpenHelper; @@ -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 { @@ -39,14 +43,8 @@ public class HistoryDatabase extends SQLiteOpenHelper {
private boolean mLock;
public static HistoryDatabase getInstance() {
if (mInstance == null || mInstance.isClosed()) {
mInstance = new HistoryDatabase(BrowserApp.getAppContext());
}
return mInstance;
}
private HistoryDatabase(Context context) {
@Inject
public HistoryDatabase(Context context) {
super(context.getApplicationContext(), DATABASE_NAME, null, DATABASE_VERSION);
mDatabase = this.getWritableDatabase();
}
@ -91,7 +89,7 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -91,7 +89,7 @@ public class HistoryDatabase extends SQLiteOpenHelper {
}
private void openIfNecessary() {
if (mDatabase == null) {
if (isClosed()) {
mDatabase = this.getWritableDatabase();
}
}

124
app/src/main/java/acr/browser/lightning/dialog/BookmarksDialogBuilder.java → app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java

@ -1,8 +1,13 @@ @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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();
}
}

75
app/src/main/java/acr/browser/lightning/download/DownloadHandler.java

@ -3,10 +3,8 @@ @@ -3,10 +3,8 @@
*/
package acr.browser.lightning.download;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@ -19,13 +17,17 @@ import android.util.Log; @@ -19,13 +17,17 @@ import android.util.Log;
import android.webkit.CookieManager;
import android.webkit.URLUtil;
import com.squareup.otto.Bus;
import java.io.File;
import java.io.IOException;
import acr.browser.lightning.BuildConfig;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.MainActivity;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
/**
* Handle download requests
@ -44,13 +46,13 @@ public class DownloadHandler { @@ -44,13 +46,13 @@ public class DownloadHandler {
* Notify the host application a download should be done, or that the data
* should be streamed if a streaming viewer is available.
*
* @param activity Activity requesting the download.
* @param url The full url to the content that should be downloaded
* @param userAgent User agent of the downloading application.
* @param contentDisposition Content-disposition http header, if present.
* @param mimetype The mimetype of the content reported by the server
* @param context The context in which the download was requested.
* @param url The full url to the content that should be downloaded
* @param userAgent User agent of the downloading application.
* @param contentDisposition Content-disposition http header, if present.
* @param mimetype The mimetype of the content reported by the server
*/
public static void onDownloadStart(Activity activity, String url, String userAgent,
public static void onDownloadStart(Context context, String url, String userAgent,
String contentDisposition, String mimetype) {
// if we're dealing wih A/V content that's not explicitly marked
// for download, check if it's streamable.
@ -61,18 +63,17 @@ public class DownloadHandler { @@ -61,18 +63,17 @@ public class DownloadHandler {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), mimetype);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ResolveInfo info = activity.getPackageManager().resolveActivity(intent,
ResolveInfo info = context.getPackageManager().resolveActivity(intent,
PackageManager.MATCH_DEFAULT_ONLY);
if (info != null) {
ComponentName myName = activity.getComponentName();
// If we resolved to ourselves, we don't want to attempt to
// load the url only to try and download it again.
if (!myName.getPackageName().equals(info.activityInfo.packageName)
|| !myName.getClassName().equals(info.activityInfo.name)) {
if (BuildConfig.APPLICATION_ID.equals(info.activityInfo.packageName)
|| MainActivity.class.getName().equals(info.activityInfo.name)) {
// someone (other than us) knows how to handle this mime
// type with this scheme, don't download.
try {
activity.startActivity(intent);
context.startActivity(intent);
return;
} catch (ActivityNotFoundException ex) {
// Best behavior is to fall back to a download in this
@ -81,8 +82,7 @@ public class DownloadHandler { @@ -81,8 +82,7 @@ public class DownloadHandler {
}
}
}
onDownloadStartNoStream(activity, url, userAgent, contentDisposition, mimetype
);
onDownloadStartNoStream(context, url, userAgent, contentDisposition, mimetype);
}
// This is to work around the fact that java.net.URI throws Exceptions
@ -119,17 +119,17 @@ public class DownloadHandler { @@ -119,17 +119,17 @@ public class DownloadHandler {
* Notify the host application a download should be done, even if there is a
* streaming viewer available for thise type.
*
* @param activity Activity requesting the download.
* @param context The context in which the download is requested.
* @param url The full url to the content that should be downloaded
* @param userAgent User agent of the downloading application.
* @param contentDisposition Content-disposition http header, if present.
* @param mimetype The mimetype of the content reported by the server
*/
/* package */
private static void onDownloadStartNoStream(final Activity activity, String url, String userAgent,
private static void onDownloadStartNoStream(final Context context, String url, String userAgent,
String contentDisposition, String mimetype) {
String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
final Bus eventBus = BrowserApp.getAppComponent().getBus();
final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
// Check to see if we have an SDCard
String status = Environment.getExternalStorageState();
@ -139,14 +139,14 @@ public class DownloadHandler { @@ -139,14 +139,14 @@ public class DownloadHandler {
// Check to see if the SDCard is busy, same as the music app
if (status.equals(Environment.MEDIA_SHARED)) {
msg = activity.getString(R.string.download_sdcard_busy_dlg_msg);
msg = context.getString(R.string.download_sdcard_busy_dlg_msg);
title = R.string.download_sdcard_busy_dlg_title;
} else {
msg = activity.getString(R.string.download_no_sdcard_dlg_msg, filename);
msg = context.getString(R.string.download_no_sdcard_dlg_msg, filename);
title = R.string.download_no_sdcard_dlg_title;
}
new AlertDialog.Builder(activity).setTitle(title)
new AlertDialog.Builder(context).setTitle(title)
.setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg)
.setPositiveButton(R.string.action_ok, null).show();
return;
@ -162,7 +162,7 @@ public class DownloadHandler { @@ -162,7 +162,7 @@ public class DownloadHandler {
// This only happens for very bad urls, we want to catch the
// exception here
Log.e(TAG, "Exception while trying to parse url '" + url + '\'', e);
Utils.showSnackbar(activity, R.string.problem_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_download));
return;
}
@ -172,7 +172,7 @@ public class DownloadHandler { @@ -172,7 +172,7 @@ public class DownloadHandler {
try {
request = new DownloadManager.Request(uri);
} catch (IllegalArgumentException e) {
Utils.showSnackbar(activity, R.string.cannot_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.cannot_download));
return;
}
request.setMimeType(mimetype);
@ -180,7 +180,7 @@ public class DownloadHandler { @@ -180,7 +180,7 @@ public class DownloadHandler {
// or, should it be set to one of several Environment.DIRECTORY* dirs
// depending on mimetype?
String location = PreferenceManager.getInstance().getDownloadDirectory();
String location = BrowserApp.getAppComponent().getPreferenceManager().getDownloadDirectory();
Uri downloadFolder;
if (location != null) {
location = addNecessarySlashes(location);
@ -188,18 +188,18 @@ public class DownloadHandler { @@ -188,18 +188,18 @@ public class DownloadHandler {
} else {
location = addNecessarySlashes(DEFAULT_DOWNLOAD_PATH);
downloadFolder = Uri.parse(location);
PreferenceManager.getInstance().setDownloadDirectory(location);
BrowserApp.getAppComponent().getPreferenceManager().setDownloadDirectory(location);
}
File dir = new File(downloadFolder.getPath());
if (!dir.isDirectory() && !dir.mkdirs()) {
// Cannot make the directory
Utils.showSnackbar(activity, R.string.problem_location_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
return;
}
if (!isWriteAccessAvailable(downloadFolder)) {
Utils.showSnackbar(activity, R.string.problem_location_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
return;
}
request.setDestinationUri(Uri.parse(Constants.FILE + location + filename));
@ -219,9 +219,9 @@ public class DownloadHandler { @@ -219,9 +219,9 @@ public class DownloadHandler {
}
// We must have long pressed on a link or image to download it. We
// are not sure of the mimetype in this case, so do a head request
new FetchUrlMimeType(activity, request, addressString, cookies, userAgent).start();
new FetchUrlMimeType(context, request, addressString, cookies, userAgent).start();
} else {
final DownloadManager manager = (DownloadManager) activity
final DownloadManager manager = (DownloadManager) context
.getSystemService(Context.DOWNLOAD_SERVICE);
new Thread() {
@Override
@ -231,15 +231,16 @@ public class DownloadHandler { @@ -231,15 +231,16 @@ public class DownloadHandler {
} catch (IllegalArgumentException e) {
// Probably got a bad URL or something
e.printStackTrace();
Utils.showSnackbar(activity, R.string.cannot_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.cannot_download));
} catch (SecurityException e) {
// TODO write a download utility that downloads files rather than rely on the system
// because the system can only handle Environment.getExternal... as a path
Utils.showSnackbar(activity, R.string.problem_location_download);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(R.string.problem_location_download));
}
}
}.start();
Utils.showSnackbar(activity, activity.getString(R.string.download_pending) + ' ' + filename);
eventBus.post(new BrowserEvents.ShowSnackBarMessage(
context.getString(R.string.download_pending) + ' ' + filename));
}
}
@ -320,12 +321,12 @@ public class DownloadHandler { @@ -320,12 +321,12 @@ public class DownloadHandler {
} catch (IOException ignored) {
return false;
}
}
}
public static String addNecessarySlashes(String originalPath) {
if (originalPath == null || originalPath.length() == 0) {
return "/";
}
}
if (originalPath.charAt(originalPath.length() - 1) != '/') {
originalPath = originalPath + '/';
}

16
app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java

@ -3,18 +3,21 @@ @@ -3,18 +3,21 @@
*/
package acr.browser.lightning.download;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.os.Environment;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
import com.squareup.otto.Bus;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.utils.Utils;
/**
@ -27,7 +30,7 @@ import acr.browser.lightning.utils.Utils; @@ -27,7 +30,7 @@ import acr.browser.lightning.utils.Utils;
*/
class FetchUrlMimeType extends Thread {
private final Activity mActivity;
private final Context mContext;
private final DownloadManager.Request mRequest;
@ -37,9 +40,9 @@ class FetchUrlMimeType extends Thread { @@ -37,9 +40,9 @@ class FetchUrlMimeType extends Thread {
private final String mUserAgent;
public FetchUrlMimeType(Activity activity, DownloadManager.Request request, String uri,
public FetchUrlMimeType(Context context, DownloadManager.Request request, String uri,
String cookies, String userAgent) {
mActivity = activity;
mContext = context;
mRequest = request;
mUri = uri;
mCookies = cookies;
@ -50,6 +53,7 @@ class FetchUrlMimeType extends Thread { @@ -50,6 +53,7 @@ class FetchUrlMimeType extends Thread {
public void run() {
// User agent is likely to be null, though the AndroidHttpClient
// seems ok with that.
final Bus evenBus = BrowserApp.getAppComponent().getBus();
String mimeType = null;
String contentDisposition = null;
HttpURLConnection connection = null;
@ -101,9 +105,9 @@ class FetchUrlMimeType extends Thread { @@ -101,9 +105,9 @@ class FetchUrlMimeType extends Thread {
}
// Start the download
DownloadManager manager = (DownloadManager) mActivity
DownloadManager manager = (DownloadManager) mContext
.getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(mRequest);
Utils.showSnackbar(mActivity, mActivity.getString(R.string.download_pending) + ' ' + filename);
evenBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + filename));
}
}

18
app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
*/
package acr.browser.lightning.download;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log;
@ -15,10 +15,10 @@ import acr.browser.lightning.constant.Constants; @@ -15,10 +15,10 @@ import acr.browser.lightning.constant.Constants;
public class LightningDownloadListener implements DownloadListener {
private final Activity mActivity;
private final Context mContext;
public LightningDownloadListener(Activity activity) {
mActivity = activity;
public LightningDownloadListener(Context context) {
mContext = context;
}
@Override
@ -30,7 +30,7 @@ public class LightningDownloadListener implements DownloadListener { @@ -30,7 +30,7 @@ public class LightningDownloadListener implements DownloadListener {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
DownloadHandler.onDownloadStart(mActivity, url, userAgent,
DownloadHandler.onDownloadStart(mContext, url, userAgent,
contentDisposition, mimetype);
break;
@ -40,12 +40,12 @@ public class LightningDownloadListener implements DownloadListener { @@ -40,12 +40,12 @@ public class LightningDownloadListener implements DownloadListener {
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); // dialog
AlertDialog.Builder builder = new AlertDialog.Builder(mContext); // dialog
builder.setTitle(fileName)
.setMessage(mActivity.getResources().getString(R.string.dialog_download))
.setPositiveButton(mActivity.getResources().getString(R.string.action_download),
.setMessage(mContext.getResources().getString(R.string.dialog_download))
.setPositiveButton(mContext.getResources().getString(R.string.action_download),
dialogClickListener)
.setNegativeButton(mActivity.getResources().getString(R.string.action_cancel),
.setNegativeButton(mContext.getResources().getString(R.string.action_cancel),
dialogClickListener).show();
Log.i(Constants.TAG, "Downloading" + fileName);

41
app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java

@ -8,7 +8,6 @@ import android.content.DialogInterface; @@ -8,7 +8,6 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import java.util.Arrays;
@ -16,9 +15,8 @@ import java.util.List; @@ -16,9 +15,8 @@ import java.util.List;
import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
public class AdvancedSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public class AdvancedSettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_NEWWINDOW = "allow_new_window";
private static final String SETTINGS_ENABLECOOKIES = "allow_cookies";
@ -29,7 +27,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -29,7 +27,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
private static final String SETTINGS_TEXTENCODING = "text_encoding";
private Activity mActivity;
private PreferenceManager mPreferences;
private CheckBoxPreference cbAllowPopups, cbenablecookies, cbcookiesInkognito, cbrestoreTabs;
private Preference renderingmode, urlcontent, textEncoding;
private CharSequence[] mUrlOptions;
@ -46,8 +43,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -46,8 +43,6 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
}
private void initPrefs() {
// mPreferences storage
mPreferences = PreferenceManager.getInstance();
renderingmode = findPreference(SETTINGS_RENDERINGMODE);
textEncoding = findPreference(SETTINGS_TEXTENCODING);
@ -65,7 +60,7 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -65,7 +60,7 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
cbcookiesInkognito.setOnPreferenceChangeListener(this);
cbrestoreTabs.setOnPreferenceChangeListener(this);
switch (mPreferences.getRenderingMode()) {
switch (mPreferenceManager.getRenderingMode()) {
case 0:
renderingmode.setSummary(getString(R.string.name_normal));
break;
@ -80,16 +75,16 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -80,16 +75,16 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
break;
}
textEncoding.setSummary(mPreferences.getTextEncoding());
textEncoding.setSummary(mPreferenceManager.getTextEncoding());
mUrlOptions = getResources().getStringArray(R.array.url_content_array);
int option = mPreferences.getUrlBoxContentChoice();
int option = mPreferenceManager.getUrlBoxContentChoice();
urlcontent.setSummary(mUrlOptions[option]);
cbAllowPopups.setChecked(mPreferences.getPopupsEnabled());
cbenablecookies.setChecked(mPreferences.getCookiesEnabled());
cbcookiesInkognito.setChecked(mPreferences.getIncognitoCookiesEnabled());
cbrestoreTabs.setChecked(mPreferences.getRestoreLostTabsEnabled());
cbAllowPopups.setChecked(mPreferenceManager.getPopupsEnabled());
cbenablecookies.setChecked(mPreferenceManager.getCookiesEnabled());
cbcookiesInkognito.setChecked(mPreferenceManager.getIncognitoCookiesEnabled());
cbrestoreTabs.setChecked(mPreferenceManager.getRestoreLostTabsEnabled());
}
@Override
@ -114,19 +109,19 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -114,19 +109,19 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
// switch preferences
switch (preference.getKey()) {
case SETTINGS_NEWWINDOW:
mPreferences.setPopupsEnabled((Boolean) newValue);
mPreferenceManager.setPopupsEnabled((Boolean) newValue);
cbAllowPopups.setChecked((Boolean) newValue);
return true;
case SETTINGS_ENABLECOOKIES:
mPreferences.setCookiesEnabled((Boolean) newValue);
mPreferenceManager.setCookiesEnabled((Boolean) newValue);
cbenablecookies.setChecked((Boolean) newValue);
return true;
case SETTINGS_COOKIESINKOGNITO:
mPreferences.setIncognitoCookiesEnabled((Boolean) newValue);
mPreferenceManager.setIncognitoCookiesEnabled((Boolean) newValue);
cbcookiesInkognito.setChecked((Boolean) newValue);
return true;
case SETTINGS_RESTORETABS:
mPreferences.setRestoreLostTabsEnabled((Boolean) newValue);
mPreferenceManager.setRestoreLostTabsEnabled((Boolean) newValue);
cbrestoreTabs.setChecked((Boolean) newValue);
return true;
default:
@ -142,12 +137,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -142,12 +137,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
mActivity.getString(R.string.name_grayscale),
mActivity.getString(R.string.name_inverted_grayscale)};
int n = mPreferences.getRenderingMode();
int n = mPreferenceManager.getRenderingMode();
picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setRenderingMode(which);
mPreferenceManager.setRenderingMode(which);
switch (which) {
case 0:
renderingmode.setSummary(getString(R.string.name_normal));
@ -172,12 +167,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -172,12 +167,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.text_encoding));
final List<String> textEncodingList = Arrays.asList(Constants.TEXT_ENCODINGS);
int n = textEncodingList.indexOf(mPreferences.getTextEncoding());
int n = textEncodingList.indexOf(mPreferenceManager.getTextEncoding());
picker.setSingleChoiceItems(Constants.TEXT_ENCODINGS, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setTextEncoding(Constants.TEXT_ENCODINGS[which]);
mPreferenceManager.setTextEncoding(Constants.TEXT_ENCODINGS[which]);
textEncoding.setSummary(Constants.TEXT_ENCODINGS[which]);
}
});
@ -189,12 +184,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref @@ -189,12 +184,12 @@ public class AdvancedSettingsFragment extends PreferenceFragment implements Pref
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.url_contents));
int n = mPreferences.getUrlBoxContentChoice();
int n = mPreferenceManager.getUrlBoxContentChoice();
picker.setSingleChoiceItems(mUrlOptions, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setUrlBoxContentChoice(which);
mPreferenceManager.setUrlBoxContentChoice(which);
if (which < mUrlOptions.length) {
urlcontent.setSummary(mUrlOptions[which]);
}

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

@ -1,6 +1,5 @@ @@ -1,6 +1,5 @@
package acr.browser.lightning.fragment;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
@ -43,7 +42,7 @@ import acr.browser.lightning.bus.BookmarkEvents; @@ -43,7 +42,7 @@ import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.dialog.BookmarksDialogBuilder;
import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.async.ImageDownloadTask;
import acr.browser.lightning.utils.ThemeUtils;
@ -53,6 +52,10 @@ import acr.browser.lightning.utils.ThemeUtils; @@ -53,6 +52,10 @@ import acr.browser.lightning.utils.ThemeUtils;
*/
public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
private final static String TAG = BookmarksFragment.class.getSimpleName();
public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE";
// Managers
@Inject
BookmarkManager mBookmarkManager;
@ -63,7 +66,10 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -63,7 +66,10 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
// Dialog builder
@Inject
BookmarksDialogBuilder mBookmarksDialogBuilder;
LightningDialogBuilder mBookmarksDialogBuilder;
@Inject
PreferenceManager mPreferenceManager;
// Adapter
private BookmarkViewAdapter mBookmarkAdapter;
@ -81,6 +87,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -81,6 +87,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
// Colors
private int mIconColor, mScrollIndex;
private boolean mIsIncognito;
// Init asynchronously the bookmark manager
private final Runnable mInitBookmarkManager = new Runnable() {
@Override
@ -96,6 +104,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -96,6 +104,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BrowserApp.getAppComponent().inject(this);
final Bundle arguments = getArguments();
final Context context = getContext();
mIsIncognito = arguments.getBoolean(INCOGNITO_MODE, false);
boolean darkTheme = mPreferenceManager.getUseTheme() != 0 || mIsIncognito;
mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme);
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) :
ThemeUtils.getIconLightThemeColor(context);
}
// Handle bookmark click
@ -107,7 +123,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -107,7 +123,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
mScrollIndex = mBookmarksListView.getFirstVisiblePosition();
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(item.getTitle(), true), true);
} else {
mEventBus.post(new BookmarkEvents.Clicked(item));
mEventBus.post(new BrowserEvents.OpenUrlInCurrentTab(item.getUrl()));
}
}
};
@ -135,6 +151,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -135,6 +151,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
mBookmarksListView.setOnItemClickListener(mItemClickListener);
mBookmarksListView.setOnItemLongClickListener(mItemLongClickListener);
mBookmarkTitleImage = (ImageView) view.findViewById(R.id.starIcon);
mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
mBookmarkImage = (ImageView) view.findViewById(R.id.icon_star);
final View backView = view.findViewById(R.id.bookmark_back_button);
backView.setOnClickListener(new View.OnClickListener() {
@ -154,20 +171,6 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -154,20 +171,6 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
// TODO remove dependency on BrowserActivity
super.onActivityCreated(savedInstanceState);
final Activity activity = getActivity();
final PreferenceManager preferenceManager = PreferenceManager.getInstance();
boolean darkTheme = preferenceManager.getUseTheme() != 0 || ((BrowserActivity) activity).isIncognito();
mWebpageBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_webpage, darkTheme);
mFolderBitmap = ThemeUtils.getThemedBitmap(activity, R.drawable.ic_folder, darkTheme);
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(activity) :
ThemeUtils.getIconLightThemeColor(activity);
mBookmarkTitleImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}
@Override
public void onStart() {
super.onStart();
@ -229,8 +232,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -229,8 +232,8 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
if (event.item.isFolder()) {
setBookmarkDataSet(mBookmarkManager.getBookmarksFromFolder(null, true), false);
} else {
mBookmarkAdapter.notifyDataSetChanged();
}
mBookmarkAdapter.notifyDataSetChanged();
}
}
private void setBookmarkDataSet(List<HistoryItem> items, boolean animate) {
@ -295,7 +298,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -295,7 +298,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
if (item.isFolder()) {
mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item);
} else {
mBookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item);
mBookmarksDialogBuilder.showLongPressLinkDialog(getContext(), item.getUrl());
}
}

42
app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java

@ -8,7 +8,6 @@ import android.content.DialogInterface; @@ -8,7 +8,6 @@ import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -19,9 +18,8 @@ import android.widget.SeekBar; @@ -19,9 +18,8 @@ import android.widget.SeekBar;
import android.widget.TextView;
import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager;
public class DisplaySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public class DisplaySettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_HIDESTATUSBAR = "fullScreenOption";
private static final String SETTINGS_FULLSCREEN = "fullscreen";
@ -38,7 +36,6 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -38,7 +36,6 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
private static final float XSMALL = 10.0f;
private Activity mActivity;
private PreferenceManager mPreferences;
private CheckBoxPreference cbstatus, cbfullscreen, cbviewport, cboverview, cbreflow;
private Preference theme;
private String[] mThemeOptions;
@ -57,9 +54,8 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -57,9 +54,8 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
private void initPrefs() {
// mPreferences storage
mPreferences = PreferenceManager.getInstance();
mThemeOptions = this.getResources().getStringArray(R.array.themes);
mCurrentTheme = mPreferences.getUseTheme();
mCurrentTheme = mPreferenceManager.getUseTheme();
theme = findPreference(SETTINGS_THEME);
Preference textsize = findPreference(SETTINGS_TEXTSIZE);
@ -77,13 +73,13 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -77,13 +73,13 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
cboverview.setOnPreferenceChangeListener(this);
cbreflow.setOnPreferenceChangeListener(this);
cbstatus.setChecked(mPreferences.getHideStatusBarEnabled());
cbfullscreen.setChecked(mPreferences.getFullScreenEnabled());
cbviewport.setChecked(mPreferences.getUseWideViewportEnabled());
cboverview.setChecked(mPreferences.getOverviewModeEnabled());
cbreflow.setChecked(mPreferences.getTextReflowEnabled());
cbstatus.setChecked(mPreferenceManager.getHideStatusBarEnabled());
cbfullscreen.setChecked(mPreferenceManager.getFullScreenEnabled());
cbviewport.setChecked(mPreferenceManager.getUseWideViewportEnabled());
cboverview.setChecked(mPreferenceManager.getOverviewModeEnabled());
cbreflow.setChecked(mPreferenceManager.getTextReflowEnabled());
theme.setSummary(mThemeOptions[mPreferences.getUseTheme()]);
theme.setSummary(mThemeOptions[mPreferenceManager.getUseTheme()]);
}
@Override
@ -105,23 +101,23 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -105,23 +101,23 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
// switch preferences
switch (preference.getKey()) {
case SETTINGS_HIDESTATUSBAR:
mPreferences.setHideStatusBarEnabled((Boolean) newValue);
mPreferenceManager.setHideStatusBarEnabled((Boolean) newValue);
cbstatus.setChecked((Boolean) newValue);
return true;
case SETTINGS_FULLSCREEN:
mPreferences.setFullScreenEnabled((Boolean) newValue);
mPreferenceManager.setFullScreenEnabled((Boolean) newValue);
cbfullscreen.setChecked((Boolean) newValue);
return true;
case SETTINGS_VIEWPORT:
mPreferences.setUseWideViewportEnabled((Boolean) newValue);
mPreferenceManager.setUseWideViewportEnabled((Boolean) newValue);
cbviewport.setChecked((Boolean) newValue);
return true;
case SETTINGS_OVERVIEWMODE:
mPreferences.setOverviewModeEnabled((Boolean) newValue);
mPreferenceManager.setOverviewModeEnabled((Boolean) newValue);
cboverview.setChecked((Boolean) newValue);
return true;
case SETTINGS_REFLOW:
mPreferences.setTextReflowEnabled((Boolean) newValue);
mPreferenceManager.setTextReflowEnabled((Boolean) newValue);
cbreflow.setChecked((Boolean) newValue);
return true;
default:
@ -142,14 +138,14 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -142,14 +138,14 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
bar.setOnSeekBarChangeListener(new TextSeekBarListener(sample));
final int MAX = 5;
bar.setMax(MAX);
bar.setProgress(MAX - mPreferences.getTextSize());
bar.setProgress(MAX - mPreferenceManager.getTextSize());
builder.setView(view);
builder.setTitle(R.string.title_text_size);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
mPreferences.setTextSize(MAX - bar.getProgress());
mPreferenceManager.setTextSize(MAX - bar.getProgress());
}
});
@ -179,12 +175,12 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -179,12 +175,12 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.theme));
int n = mPreferences.getUseTheme();
int n = mPreferenceManager.getUseTheme();
picker.setSingleChoiceItems(mThemeOptions, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setUseTheme(which);
mPreferenceManager.setUseTheme(which);
if (which < mThemeOptions.length) {
theme.setSummary(mThemeOptions[which]);
}
@ -195,7 +191,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -195,7 +191,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
if (mCurrentTheme != mPreferences.getUseTheme()) {
if (mCurrentTheme != mPreferenceManager.getUseTheme()) {
getActivity().onBackPressed();
}
}
@ -203,7 +199,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe @@ -203,7 +199,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
picker.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if (mCurrentTheme != mPreferences.getUseTheme()) {
if (mCurrentTheme != mPreferenceManager.getUseTheme()) {
getActivity().onBackPressed();
}
}

107
app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java

@ -9,7 +9,6 @@ import android.os.Bundle; @@ -9,7 +9,6 @@ import android.os.Bundle;
import android.os.Environment;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
@ -28,7 +27,7 @@ import acr.browser.lightning.utils.ProxyUtils; @@ -28,7 +27,7 @@ import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
public class GeneralSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public class GeneralSettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_PROXY = "proxy";
private static final String SETTINGS_FLASH = "cb_flash";
@ -45,7 +44,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -45,7 +44,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private Activity mActivity;
private static final int API = android.os.Build.VERSION.SDK_INT;
private PreferenceManager mPreferences;
private CharSequence[] mProxyChoices;
private Preference proxy, useragent, downloadloc, home, searchengine;
private String mDownloadLocation;
@ -65,9 +63,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -65,9 +63,6 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
}
private void initPrefs() {
// mPreferences storage
mPreferences = PreferenceManager.getInstance();
proxy = findPreference(SETTINGS_PROXY);
useragent = findPreference(SETTINGS_USERAGENT);
downloadloc = findPreference(SETTINGS_DOWNLOAD);
@ -95,23 +90,23 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -95,23 +90,23 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
cbgooglesuggest.setOnPreferenceChangeListener(this);
cbDrawerTabs.setOnPreferenceChangeListener(this);
mAgentChoice = mPreferences.getUserAgentChoice();
mHomepage = mPreferences.getHomepage();
mDownloadLocation = mPreferences.getDownloadDirectory();
mAgentChoice = mPreferenceManager.getUserAgentChoice();
mHomepage = mPreferenceManager.getHomepage();
mDownloadLocation = mPreferenceManager.getDownloadDirectory();
mProxyChoices = getResources().getStringArray(R.array.proxy_choices_array);
int choice = mPreferences.getProxyChoice();
int choice = mPreferenceManager.getProxyChoice();
if (choice == Constants.PROXY_MANUAL) {
proxy.setSummary(mPreferences.getProxyHost() + ':' + mPreferences.getProxyPort());
proxy.setSummary(mPreferenceManager.getProxyHost() + ':' + mPreferenceManager.getProxyPort());
} else {
proxy.setSummary(mProxyChoices[choice]);
}
if (API >= 19) {
mPreferences.setFlashSupport(0);
mPreferenceManager.setFlashSupport(0);
}
setSearchEngineSummary(mPreferences.getSearchChoice());
setSearchEngineSummary(mPreferenceManager.getSearchChoice());
downloadloc.setSummary(mDownloadLocation);
@ -139,9 +134,9 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -139,9 +134,9 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
useragent.setSummary(getResources().getString(R.string.agent_custom));
}
int flashNum = mPreferences.getFlashSupport();
boolean imagesBool = mPreferences.getBlockImagesEnabled();
boolean enableJSBool = mPreferences.getJavaScriptEnabled();
int flashNum = mPreferenceManager.getFlashSupport();
boolean imagesBool = mPreferenceManager.getBlockImagesEnabled();
boolean enableJSBool = mPreferenceManager.getJavaScriptEnabled();
cbAds.setEnabled(Constants.FULL_VERSION);
cbFlash.setEnabled(API < 19);
@ -149,17 +144,17 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -149,17 +144,17 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
cbImages.setChecked(imagesBool);
cbJsScript.setChecked(enableJSBool);
cbFlash.setChecked(flashNum > 0);
cbAds.setChecked(Constants.FULL_VERSION && mPreferences.getAdBlockEnabled());
cbColorMode.setChecked(mPreferences.getColorModeEnabled());
cbgooglesuggest.setChecked(mPreferences.getGoogleSearchSuggestionsEnabled());
cbDrawerTabs.setChecked(mPreferences.getShowTabsInDrawer(true));
cbAds.setChecked(Constants.FULL_VERSION && mPreferenceManager.getAdBlockEnabled());
cbColorMode.setChecked(mPreferenceManager.getColorModeEnabled());
cbgooglesuggest.setChecked(mPreferenceManager.getGoogleSearchSuggestionsEnabled());
cbDrawerTabs.setChecked(mPreferenceManager.getShowTabsInDrawer(true));
}
private void searchUrlPicker() {
final AlertDialog.Builder urlPicker = new AlertDialog.Builder(mActivity);
urlPicker.setTitle(getResources().getString(R.string.custom_url));
final EditText getSearchUrl = new EditText(mActivity);
String mSearchUrl = mPreferences.getSearchUrl();
String mSearchUrl = mPreferenceManager.getSearchUrl();
getSearchUrl.setText(mSearchUrl);
urlPicker.setView(getSearchUrl);
urlPicker.setPositiveButton(getResources().getString(R.string.action_ok),
@ -167,7 +162,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -167,7 +162,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getSearchUrl.getText().toString();
mPreferences.setSearchUrl(text);
mPreferenceManager.setSearchUrl(text);
searchengine.setSummary(getResources().getString(R.string.custom_url) + ": "
+ text);
}
@ -184,7 +179,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -184,7 +179,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
mPreferences.setFlashSupport(1);
mPreferenceManager.setFlashSupport(1);
}
})
.setNegativeButton(getResources().getString(R.string.action_auto),
@ -192,13 +187,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -192,13 +187,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setFlashSupport(2);
mPreferenceManager.setFlashSupport(2);
}
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
mPreferences.setFlashSupport(0);
mPreferenceManager.setFlashSupport(0);
}
});
@ -209,7 +204,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -209,7 +204,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void proxyChoicePicker() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.http_proxy));
picker.setSingleChoiceItems(mProxyChoices, mPreferences.getProxyChoice(),
picker.setSingleChoiceItems(mProxyChoices, mPreferenceManager.getProxyChoice(),
new DialogInterface.OnClickListener() {
@Override
@ -234,7 +229,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -234,7 +229,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
break;
}
mPreferences.setProxyChoice(choice);
mPreferenceManager.setProxyChoice(choice);
if (choice < mProxyChoices.length)
proxy.setSummary(mProxyChoices[choice]);
}
@ -252,8 +247,8 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -252,8 +247,8 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
filterArray[0] = new InputFilter.LengthFilter(maxCharacters - 1);
eProxyPort.setFilters(filterArray);
eProxyHost.setText(mPreferences.getProxyHost());
eProxyPort.setText(Integer.toString(mPreferences.getProxyPort()));
eProxyHost.setText(mPreferenceManager.getProxyHost());
eProxyPort.setText(Integer.toString(mPreferenceManager.getProxyPort()));
new AlertDialog.Builder(mActivity)
.setTitle(R.string.manual_proxy)
@ -268,10 +263,10 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -268,10 +263,10 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
// larger than max integer
proxyPort = Integer.parseInt(eProxyPort.getText().toString());
} catch (NumberFormatException ignored) {
proxyPort = mPreferences.getProxyPort();
proxyPort = mPreferenceManager.getProxyPort();
}
mPreferences.setProxyHost(proxyHost);
mPreferences.setProxyPort(proxyPort);
mPreferenceManager.setProxyHost(proxyHost);
mPreferenceManager.setProxyPort(proxyPort);
proxy.setSummary(proxyHost + ':' + proxyPort);
}
}).show();
@ -285,13 +280,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -285,13 +280,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
"DuckDuckGo (Privacy)", "DuckDuckGo Lite (Privacy)", "Baidu (Chinese)",
"Yandex (Russian)"};
int n = mPreferences.getSearchChoice();
int n = mPreferenceManager.getSearchChoice();
picker.setSingleChoiceItems(chars, n, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setSearchChoice(which);
mPreferenceManager.setSearchChoice(which);
setSearchEngineSummary(which);
}
});
@ -302,7 +297,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -302,7 +297,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void homepageDialog() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.home));
mHomepage = mPreferences.getHomepage();
mHomepage = mPreferenceManager.getHomepage();
int n;
if (mHomepage.contains("about:home")) {
n = 1;
@ -320,15 +315,15 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -320,15 +315,15 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
switch (which + 1) {
case 1:
mPreferences.setHomepage("about:home");
mPreferenceManager.setHomepage("about:home");
home.setSummary(getResources().getString(R.string.action_homepage));
break;
case 2:
mPreferences.setHomepage("about:blank");
mPreferenceManager.setHomepage("about:blank");
home.setSummary(getResources().getString(R.string.action_blank));
break;
case 3:
mPreferences.setHomepage("about:bookmarks");
mPreferenceManager.setHomepage("about:bookmarks");
home.setSummary(getResources().getString(R.string.action_bookmarks));
break;
case 4:
@ -345,7 +340,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -345,7 +340,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
final AlertDialog.Builder homePicker = new AlertDialog.Builder(mActivity);
homePicker.setTitle(getResources().getString(R.string.title_custom_homepage));
final EditText getHome = new EditText(mActivity);
mHomepage = mPreferences.getHomepage();
mHomepage = mPreferenceManager.getHomepage();
if (!mHomepage.startsWith("about:")) {
getHome.setText(mHomepage);
} else {
@ -357,7 +352,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -357,7 +352,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getHome.getText().toString();
mPreferences.setHomepage(text);
mPreferenceManager.setHomepage(text);
home.setSummary(text);
}
});
@ -367,7 +362,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -367,7 +362,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void downloadLocDialog() {
AlertDialog.Builder picker = new AlertDialog.Builder(mActivity);
picker.setTitle(getResources().getString(R.string.title_download_location));
mDownloadLocation = mPreferences.getDownloadDirectory();
mDownloadLocation = mPreferenceManager.getDownloadDirectory();
int n;
if (mDownloadLocation.contains(Environment.DIRECTORY_DOWNLOADS)) {
n = 0;
@ -381,7 +376,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -381,7 +376,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
mPreferences.setDownloadDirectory(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
mPreferenceManager.setDownloadDirectory(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
downloadloc.setSummary(DownloadHandler.DEFAULT_DOWNLOAD_PATH);
break;
case 1:
@ -397,12 +392,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -397,12 +392,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
private void agentDialog() {
AlertDialog.Builder agentPicker = new AlertDialog.Builder(mActivity);
agentPicker.setTitle(getResources().getString(R.string.title_user_agent));
mAgentChoice = mPreferences.getUserAgentChoice();
mAgentChoice = mPreferenceManager.getUserAgentChoice();
agentPicker.setSingleChoiceItems(R.array.user_agent, mAgentChoice - 1,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mPreferences.setUserAgentChoice(which + 1);
mPreferenceManager.setUserAgentChoice(which + 1);
switch (which + 1) {
case 1:
useragent.setSummary(getResources().getString(R.string.agent_default));
@ -434,7 +429,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -434,7 +429,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public void onClick(DialogInterface dialog, int which) {
String text = getAgent.getText().toString();
mPreferences.setUserAgentString(text);
mPreferenceManager.setUserAgentString(text);
useragent.setSummary(getResources().getString(R.string.agent_custom));
}
});
@ -448,12 +443,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -448,12 +443,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
final EditText getDownload = new EditText(mActivity);
getDownload.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
getDownload.setText(PreferenceManager.getInstance().getDownloadDirectory());
getDownload.setText(mPreferenceManager.getDownloadDirectory());
final int errorColor = ContextCompat.getColor(getActivity(), R.color.error_red);
final int regularColor = ThemeUtils.getTextColor(getActivity());
getDownload.setTextColor(regularColor);
getDownload.addTextChangedListener(new DownloadLocationTextWatcher(getDownload, errorColor, regularColor));
getDownload.setText(mPreferences.getDownloadDirectory());
getDownload.setText(mPreferenceManager.getDownloadDirectory());
layout.addView(getDownload);
downLocationPicker.setView(layout);
@ -463,7 +458,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -463,7 +458,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
public void onClick(DialogInterface dialog, int which) {
String text = getDownload.getText().toString();
text = DownloadHandler.addNecessarySlashes(text);
mPreferences.setDownloadDirectory(text);
mPreferenceManager.setDownloadDirectory(text);
downloadloc.setSummary(text);
}
});
@ -538,37 +533,37 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -538,37 +533,37 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
if (cbFlash.isChecked()) {
getFlashChoice();
} else {
mPreferences.setFlashSupport(0);
mPreferenceManager.setFlashSupport(0);
}
if (!Utils.isFlashInstalled(mActivity) && cbFlash.isChecked()) {
Utils.createInformativeDialog(mActivity, R.string.title_warning, R.string.dialog_adobe_not_installed);
cbFlash.setEnabled(false);
mPreferences.setFlashSupport(0);
mPreferenceManager.setFlashSupport(0);
}
cbFlash.setChecked((Boolean) newValue);
return true;
case SETTINGS_ADS:
mPreferences.setAdBlockEnabled((Boolean) newValue);
mPreferenceManager.setAdBlockEnabled((Boolean) newValue);
cbAds.setChecked((Boolean) newValue);
return true;
case SETTINGS_IMAGES:
mPreferences.setBlockImagesEnabled((Boolean) newValue);
mPreferenceManager.setBlockImagesEnabled((Boolean) newValue);
cbImages.setChecked((Boolean) newValue);
return true;
case SETTINGS_JAVASCRIPT:
mPreferences.setJavaScriptEnabled((Boolean) newValue);
mPreferenceManager.setJavaScriptEnabled((Boolean) newValue);
cbJsScript.setChecked((Boolean) newValue);
return true;
case SETTINGS_COLORMODE:
mPreferences.setColorModeEnabled((Boolean) newValue);
mPreferenceManager.setColorModeEnabled((Boolean) newValue);
cbColorMode.setChecked((Boolean) newValue);
return true;
case SETTINGS_GOOGLESUGGESTIONS:
mPreferences.setGoogleSearchSuggestionsEnabled((Boolean) newValue);
mPreferenceManager.setGoogleSearchSuggestionsEnabled((Boolean) newValue);
cbgooglesuggest.setChecked((Boolean) newValue);
return true;
case SETTINGS_DRAWERTABS:
mPreferences.setShowTabsInDrawer((Boolean) newValue);
mPreferenceManager.setShowTabsInDrawer((Boolean) newValue);
cbDrawerTabs.setChecked((Boolean) newValue);
default:
return false;

27
app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package acr.browser.lightning.fragment;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import javax.inject.Inject;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.preference.PreferenceManager;
/**
* Simplify {@link PreferenceManager} inject in all the PreferenceFragments
*
* @author Stefano Pacifici
* @date 2015/09/16
*/
public class LightningPreferenceFragment extends PreferenceFragment {
@Inject
PreferenceManager mPreferenceManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BrowserApp.getAppComponent().inject(this);
}
}

36
app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java

@ -11,16 +11,14 @@ import android.os.Handler; @@ -11,16 +11,14 @@ import android.os.Handler;
import android.os.Message;
import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.webkit.WebView;
import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.utils.WebUtils;
public class PrivacySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public class PrivacySettingsFragment extends LightningPreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
private static final String SETTINGS_LOCATION = "location";
private static final String SETTINGS_THIRDPCOOKIES = "third_party";
@ -35,7 +33,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -35,7 +33,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
private static final String SETTINGS_WEBSTORAGEEXIT = "clear_webstorage_exit";
private Activity mActivity;
private PreferenceManager mPreferences;
private CheckBoxPreference cblocation, cb3cookies, cbsavepasswords, cbcacheexit, cbhistoryexit,
cbcookiesexit, cbwebstorageexit;
private Handler messageHandler;
@ -52,9 +49,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -52,9 +49,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
}
private void initPrefs() {
// mPreferences storage
mPreferences = PreferenceManager.getInstance();
Preference clearcache = findPreference(SETTINGS_CLEARCACHE);
Preference clearhistory = findPreference(SETTINGS_CLEARHISTORY);
Preference clearcookies = findPreference(SETTINGS_CLEARCOOKIES);
@ -81,13 +75,13 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -81,13 +75,13 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
cbcookiesexit.setOnPreferenceChangeListener(this);
cbwebstorageexit.setOnPreferenceChangeListener(this);
cblocation.setChecked(mPreferences.getLocationEnabled());
cbsavepasswords.setChecked(mPreferences.getSavePasswordsEnabled());
cbcacheexit.setChecked(mPreferences.getClearCacheExit());
cbhistoryexit.setChecked(mPreferences.getClearHistoryExitEnabled());
cbcookiesexit.setChecked(mPreferences.getClearCookiesExitEnabled());
cb3cookies.setChecked(mPreferences.getBlockThirdPartyCookiesEnabled());
cbwebstorageexit.setChecked(mPreferences.getClearWebStorageExitEnabled());
cblocation.setChecked(mPreferenceManager.getLocationEnabled());
cbsavepasswords.setChecked(mPreferenceManager.getSavePasswordsEnabled());
cbcacheexit.setChecked(mPreferenceManager.getClearCacheExit());
cbhistoryexit.setChecked(mPreferenceManager.getClearHistoryExitEnabled());
cbcookiesexit.setChecked(mPreferenceManager.getClearCookiesExitEnabled());
cb3cookies.setChecked(mPreferenceManager.getBlockThirdPartyCookiesEnabled());
cbwebstorageexit.setChecked(mPreferenceManager.getClearWebStorageExitEnabled());
cb3cookies.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
@ -203,31 +197,31 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -203,31 +197,31 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
// switch preferences
switch (preference.getKey()) {
case SETTINGS_LOCATION:
mPreferences.setLocationEnabled((Boolean) newValue);
mPreferenceManager.setLocationEnabled((Boolean) newValue);
cblocation.setChecked((Boolean) newValue);
return true;
case SETTINGS_THIRDPCOOKIES:
mPreferences.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
mPreferenceManager.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
cb3cookies.setChecked((Boolean) newValue);
return true;
case SETTINGS_SAVEPASSWORD:
mPreferences.setSavePasswordsEnabled((Boolean) newValue);
mPreferenceManager.setSavePasswordsEnabled((Boolean) newValue);
cbsavepasswords.setChecked((Boolean) newValue);
return true;
case SETTINGS_CACHEEXIT:
mPreferences.setClearCacheExit((Boolean) newValue);
mPreferenceManager.setClearCacheExit((Boolean) newValue);
cbcacheexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_HISTORYEXIT:
mPreferences.setClearHistoryExitEnabled((Boolean) newValue);
mPreferenceManager.setClearHistoryExitEnabled((Boolean) newValue);
cbhistoryexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_COOKIEEXIT:
mPreferences.setClearCookiesExitEnabled((Boolean) newValue);
mPreferenceManager.setClearCookiesExitEnabled((Boolean) newValue);
cbcookiesexit.setChecked((Boolean) newValue);
return true;
case SETTINGS_WEBSTORAGEEXIT:
mPreferences.setClearWebStorageExitEnabled((Boolean) newValue);
mPreferenceManager.setClearWebStorageExitEnabled((Boolean) newValue);
cbwebstorageexit.setChecked((Boolean) newValue);
return true;
default:

417
app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java

@ -0,0 +1,417 @@ @@ -0,0 +1,417 @@
package acr.browser.lightning.fragment;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import java.util.List;
import javax.inject.Inject;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.bus.NavigationEvents;
import acr.browser.lightning.bus.TabEvents;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.view.LightningView;
/**
* @author Stefano Pacifici based on Anthony C. Restaino's code
* @date 2015/09/14
*/
public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
private static final String TAG = TabsFragment.class.getSimpleName();
/**
* Arguments boolean to tell the fragment it is displayed in the drawner or on the tab strip
* If true, the fragment is in the left drawner in the strip otherwise.
*/
public static final String VERTICAL_MODE = TAG + ".VERTICAL_MODE";
public static final String IS_INCOGNITO = TAG + ".IS_INCOGNITO";
private boolean mIsIncognito, mDarkTheme;
private int mIconColor;
private boolean mColorMode = true;
private boolean mShowInNavigationDrawer;
private int mCurrentUiColor = Color.BLACK; // TODO Only temporary
private RecyclerView mRecyclerView;
private LightningViewAdapter mTabsAdapter;
@Inject
TabsManager tabsManager;
@Inject
Bus bus;
@Inject
PreferenceManager mPreferences;
public TabsFragment() {
BrowserApp.getAppComponent().inject(this);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle arguments = getArguments();
final Context context = getContext();
mIsIncognito = arguments.getBoolean(IS_INCOGNITO, false);
mShowInNavigationDrawer = arguments.getBoolean(VERTICAL_MODE, true);
mDarkTheme = mPreferences.getUseTheme() != 0 || mIsIncognito;
mColorMode = mPreferences.getColorModeEnabled();
mColorMode &= !mDarkTheme;
mIconColor = mDarkTheme ?
ThemeUtils.getIconDarkThemeColor(context) :
ThemeUtils.getIconLightThemeColor(context);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final Bundle arguments = getArguments();
final View view;
final LayoutManager layoutManager;
if (mShowInNavigationDrawer) {
view = inflater.inflate(R.layout.tab_drawer, container, false);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
setupFrameLayoutButton(view, R.id.new_tab_button, R.id.icon_plus);
setupFrameLayoutButton(view, R.id.action_back, R.id.icon_back);
setupFrameLayoutButton(view, R.id.action_forward, R.id.icon_forward);
setupFrameLayoutButton(view, R.id.action_home, R.id.icon_home);
} else {
view = inflater.inflate(R.layout.tab_strip, container, false);
layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
}
mRecyclerView = (RecyclerView) view.findViewById(R.id.tabs_list);
mRecyclerView.setLayoutManager(layoutManager);
mTabsAdapter = new LightningViewAdapter(mShowInNavigationDrawer);
mRecyclerView.setAdapter(mTabsAdapter);
mRecyclerView.setHasFixedSize(true);
return view;
}
private void setupFrameLayoutButton(@NonNull final View root, @IdRes final int buttonId,
@IdRes final int imageId) {
final View frameButton = root.findViewById(buttonId);
final ImageView buttonImage = (ImageView) root.findViewById(imageId);
frameButton.setOnClickListener(this);
frameButton.setOnLongClickListener(this);
buttonImage.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mRecyclerView = null;
mTabsAdapter = null;
}
@Override
public void onStart() {
super.onStart();
bus.register(this);
}
@Override
public void onResume() {
super.onResume();
// Force adapter refresh
mTabsAdapter.notifyDataSetChanged();
}
@Override
public void onStop() {
super.onStop();
bus.unregister(this);
}
@Subscribe
public void tabsChanged(final BrowserEvents.TabsChanged event) {
if (mTabsAdapter != null) {
mTabsAdapter.notifyDataSetChanged();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.new_tab_button:
bus.post(new TabEvents.NewTab());
break;
case R.id.action_back:
bus.post(new NavigationEvents.GoBack());
break;
case R.id.action_forward:
bus.post(new NavigationEvents.GoForward());
break;
case R.id.action_home:
bus.post(new NavigationEvents.GoHome());
default:
break;
}
}
@Override
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.action_new_tab:
bus.post(new TabEvents.NewTabLongPress());
break;
default:
break;
}
return true;
}
public class LightningViewAdapter extends RecyclerView.Adapter<LightningViewAdapter.LightningViewHolder> {
private final int layoutResourceId;
private final Drawable mBackgroundTabDrawable;
private final Drawable mForegroundTabDrawable;
private final Bitmap mForegroundTabBitmap;
private ColorMatrix mColorMatrix;
private Paint mPaint;
private ColorFilter mFilter;
private static final float DESATURATED = 0.5f;
private final boolean vertical;
public LightningViewAdapter(final boolean vertical) {
this.layoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal;
this.vertical = vertical;
if (vertical) {
mBackgroundTabDrawable = null;
mForegroundTabBitmap = null;
mForegroundTabDrawable = ThemeUtils.getSelectedBackground(getContext(), mDarkTheme);
} else {
int backgroundColor = Utils.mixTwoColors(ThemeUtils.getPrimaryColor(getContext()), Color.BLACK, 0.75f);
Bitmap backgroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
Utils.drawTrapezoid(new Canvas(backgroundTabBitmap), backgroundColor, true);
mBackgroundTabDrawable = new BitmapDrawable(getResources(), backgroundTabBitmap);
int foregroundColor = ThemeUtils.getPrimaryColor(getContext());
mForegroundTabBitmap = Bitmap.createBitmap(Utils.dpToPx(175), Utils.dpToPx(30), Bitmap.Config.ARGB_8888);
Utils.drawTrapezoid(new Canvas(mForegroundTabBitmap), foregroundColor, false);
mForegroundTabDrawable = null;
}
}
@Override
public LightningViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
View view = inflater.inflate(layoutResourceId, viewGroup, false);
return new LightningViewHolder(view);
}
@Override
public void onBindViewHolder(final LightningViewHolder holder, int position) {
holder.exitButton.setTag(position);
ViewCompat.jumpDrawablesToCurrentState(holder.exitButton);
LightningView web = tabsManager.getTabAtPosition(position);
holder.txtTitle.setText(web.getTitle());
final Bitmap favicon = web.getFavicon();
if (web.isForegroundTab()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.txtTitle.setTextAppearance(R.style.boldText);
} else {
holder.txtTitle.setTextAppearance(getContext(), R.style.boldText);
}
Drawable foregroundDrawable;
if (!vertical) {
foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap);
if (!mIsIncognito && mColorMode) {
foregroundDrawable.setColorFilter(mCurrentUiColor, PorterDuff.Mode.SRC_IN);
}
} else {
foregroundDrawable = mForegroundTabDrawable;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.layout.setBackground(foregroundDrawable);
} else {
holder.layout.setBackgroundDrawable(foregroundDrawable);
}
if (!mIsIncognito && mColorMode) {
changeToolbarBackground(favicon, foregroundDrawable);
}
holder.favicon.setImageBitmap(favicon);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.txtTitle.setTextAppearance(R.style.normalText);
} else {
holder.txtTitle.setTextAppearance(getContext(), R.style.normalText);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.layout.setBackground(mBackgroundTabDrawable);
} else {
holder.layout.setBackgroundDrawable(mBackgroundTabDrawable);
}
holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon));
}
}
@Override
public int getItemCount() {
return tabsManager.size();
}
public Bitmap getDesaturatedBitmap(Bitmap favicon) {
Bitmap grayscaleBitmap = Bitmap.createBitmap(favicon.getWidth(),
favicon.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(grayscaleBitmap);
if (mColorMatrix == null || mFilter == null || mPaint == null) {
mPaint = new Paint();
mColorMatrix = new ColorMatrix();
mColorMatrix.setSaturation(DESATURATED);
mFilter = new ColorMatrixColorFilter(mColorMatrix);
mPaint.setColorFilter(mFilter);
}
c.drawBitmap(favicon, 0, 0, mPaint);
return grayscaleBitmap;
}
/**
* Animates the color of the toolbar from one color to another. Optionally animates
* the color of the tab background, for use when the tabs are displayed on the top
* of the screen.
*
* @param favicon the Bitmap to extract the color from
* @param tabBackground the optional LinearLayout to color
*/
private void changeToolbarBackground(@NonNull Bitmap favicon, @Nullable final Drawable tabBackground) {
if (mShowInNavigationDrawer) {
return;
}
final int defaultColor;
final Resources resources = getResources();
final ColorDrawable mBackground = new ColorDrawable();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
defaultColor = resources.getColor(R.color.primary_color, null);
} else {
defaultColor = resources.getColor(R.color.primary_color);
}
if (mCurrentUiColor == Color.BLACK) {
mCurrentUiColor = defaultColor;
}
Palette.from(favicon).generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
// OR with opaque black to remove transparency glitches
int color = 0xff000000 | palette.getVibrantColor(defaultColor);
int finalColor = Utils.mixTwoColors(defaultColor, color, 0.25f);
ValueAnimator anim = ValueAnimator.ofInt(mCurrentUiColor, finalColor);
anim.setEvaluator(new ArgbEvaluator());
// final Window window = getWindow();
// TODO Check this
// if (!mShowInNavigationDrawer) {
// window.setBackgroundDrawable(new ColorDrawable(Color.BLACK));
// }
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final int color = (Integer) animation.getAnimatedValue();
if (tabBackground != null) {
tabBackground.setColorFilter(color, PorterDuff.Mode.SRC_IN);
}
mCurrentUiColor = color;
}
});
anim.setDuration(300);
anim.start();
}
});
}
public class LightningViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public LightningViewHolder(View view) {
super(view);
txtTitle = (TextView) view.findViewById(R.id.textTab);
favicon = (ImageView) view.findViewById(R.id.faviconTab);
exit = (ImageView) view.findViewById(R.id.deleteButton);
layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
exitButton.setOnClickListener(this);
layout.setOnClickListener(this);
layout.setOnLongClickListener(this);
}
final TextView txtTitle;
final ImageView favicon;
final ImageView exit;
final FrameLayout exitButton;
final LinearLayout layout;
@Override
public void onClick(View v) {
if (v == exitButton) {
// Close tab
bus.post(new TabEvents.CloseTab(getAdapterPosition()));
}
if (v == layout) {
bus.post(new TabEvents.ShowTab(getAdapterPosition()));
}
}
@Override
public boolean onLongClick(View v) {
// Show close dialog
bus.post(new TabEvents.ShowCloseDialog(getAdapterPosition()));
return true;
}
}
}
}

30
app/src/main/java/acr/browser/lightning/object/ClickHandler.java

@ -1,30 +0,0 @@ @@ -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);
}
}

23
app/src/main/java/acr/browser/lightning/object/SearchAdapter.java

@ -56,14 +56,11 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -56,14 +56,11 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
private final List<HistoryItem> mFilteredList = new ArrayList<>(5);
private final List<HistoryItem> mAllBookmarks = new ArrayList<>(5);
private final Object mLock = new Object();
private HistoryDatabase mDatabaseHandler;
private final Context mContext;
private boolean mUseGoogle = true;
private boolean mIsExecuting = false;
private final boolean mDarkTheme;
private final boolean mIncognito;
@Inject
BookmarkManager mBookmarkManager;
private static final String CACHE_FILE_TYPE = ".sgg";
private static final String ENCODING = "ISO-8859-1";
private static final long INTERVAL_DAY = 86400000;
@ -75,11 +72,19 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -75,11 +72,19 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
private final Drawable mHistoryDrawable;
private final Drawable mBookmarkDrawable;
@Inject
HistoryDatabase mDatabaseHandler;
@Inject
BookmarkManager mBookmarkManager;
@Inject
PreferenceManager mPreferenceManager;
public SearchAdapter(Context context, boolean dark, boolean incognito) {
BrowserApp.getAppComponent().inject(this);
mDatabaseHandler = HistoryDatabase.getInstance();
mAllBookmarks.addAll(mBookmarkManager.getAllBookmarks(true));
mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
mUseGoogle = mPreferenceManager.getGoogleSearchSuggestionsEnabled();
mContext = context;
mSearchSubtitle = mContext.getString(R.string.suggestion);
mDarkTheme = dark || incognito;
@ -114,13 +119,12 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -114,13 +119,12 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
}
public void refreshPreferences() {
mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
mUseGoogle = mPreferenceManager.getGoogleSearchSuggestionsEnabled();
if (!mUseGoogle) {
synchronized (mSuggestions) {
mSuggestions.clear();
}
}
mDatabaseHandler = HistoryDatabase.getInstance();
}
public void refreshBookmarks() {
@ -244,13 +248,10 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -244,13 +248,10 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
mBookmarks.add(mAllBookmarks.get(n));
counter++;
}
}
}
}
if (mDatabaseHandler == null || mDatabaseHandler.isClosed()) {
mDatabaseHandler = HistoryDatabase.getInstance();
}
List<HistoryItem> historyList = mDatabaseHandler.findItemsContaining(constraint.toString());
synchronized (mHistory) {
mHistory.clear();

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

@ -1,11 +1,16 @@ @@ -1,11 +1,16 @@
package acr.browser.lightning.preference;
import android.content.Context;
import android.content.SharedPreferences;
import javax.inject.Inject;
import javax.inject.Singleton;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
@Singleton
public class PreferenceManager {
private static class Name {
@ -56,20 +61,13 @@ public class PreferenceManager { @@ -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() {

5
app/src/main/java/acr/browser/lightning/utils/AdBlock.java

@ -13,6 +13,7 @@ import java.util.HashSet; @@ -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 { @@ -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) {

1
app/src/main/java/acr/browser/lightning/utils/IntentUtils.java

@ -2,6 +2,7 @@ package acr.browser.lightning.utils; @@ -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;

3
app/src/main/java/acr/browser/lightning/utils/WebUtils.java

@ -10,6 +10,7 @@ import android.webkit.WebStorage; @@ -10,6 +10,7 @@ import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.database.HistoryDatabase;
/**
@ -34,7 +35,7 @@ public class WebUtils { @@ -34,7 +35,7 @@ public class WebUtils {
}
public static void clearHistory(@NonNull Context context) {
HistoryDatabase.getInstance().deleteHistory();
BrowserApp.getAppComponent().getHistoryDatabase().deleteHistory();
WebViewDatabase m = WebViewDatabase.getInstance(context);
m.clearFormData();
m.clearHttpAuthUsernamePassword();

44
app/src/main/java/acr/browser/lightning/view/IconCacheTask.java

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
package acr.browser.lightning.view;
import android.graphics.Bitmap;
import android.net.Uri;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.utils.Utils;
/**
* @author Anthony C. Restaino
* @date 2015/09/29
*/
class IconCacheTask implements Runnable{
private final Uri uri;
private final Bitmap icon;
public IconCacheTask(Uri uri, Bitmap icon) {
this.uri = uri;
this.icon = icon;
}
@Override
public void run() {
String hash = String.valueOf(uri.getHost().hashCode());
Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
FileOutputStream fos = null;
try {
File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
fos = new FileOutputStream(image);
icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
Utils.close(fos);
}
}
}

250
app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java

@ -0,0 +1,250 @@ @@ -0,0 +1,250 @@
package acr.browser.lightning.view;
import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.GeolocationPermissions;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import com.squareup.otto.Bus;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.utils.PermissionsManager;
import acr.browser.lightning.utils.Utils;
/**
* @author Stefano Pacifici based on Anthony C. Restaino code
* @date 2015/09/21
*/
class LightningChromeClient extends WebChromeClient {
private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
private final BrowserActivity mActivity;
private final LightningView mLightningView;
private final Bus eventBus;
LightningChromeClient(BrowserActivity activity, LightningView lightningView) {
mActivity = activity;
mLightningView = lightningView;
eventBus = BrowserApp.getAppComponent().getBus();
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (mLightningView.isShown()) {
mActivity.updateProgress(newProgress);
}
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
if (icon == null)
return;
mLightningView.mTitle.setFavicon(icon);
eventBus.post(new BrowserEvents.TabsChanged()); ;
cacheFavicon(view.getUrl(), icon);
}
/**
* Naive caching of the favicon according to the domain name of the URL
* @param icon the icon to cache
*/
private void cacheFavicon(final String url, final Bitmap icon) {
if (icon == null) return;
final Uri uri = Uri.parse(url);
if (uri.getHost() == null) {
return;
}
new Thread(new Runnable() {
@Override
public void run() {
String hash = String.valueOf(uri.getHost().hashCode());
Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
FileOutputStream fos = null;
try {
File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
fos = new FileOutputStream(image);
icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
Utils.close(fos);
}
}
}).start();
}
@Override
public void onReceivedTitle(WebView view, String title) {
if (title != null && !title.isEmpty()) {
mLightningView.mTitle.setTitle(title);
} else {
mLightningView.mTitle.setTitle(mActivity.getString(R.string.untitled));
}
eventBus.post(new BrowserEvents.TabsChanged());
if (view != null) {
mActivity.updateHistory(title, view.getUrl());
}
}
@Override
public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) {
PermissionsManager.getInstance().requestPermissionsIfNecessary(mActivity, PERMISSIONS);
final boolean remember = true;
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(mActivity.getString(R.string.location));
String org;
if (origin.length() > 50) {
org = origin.subSequence(0, 50) + "...";
} else {
org = origin;
}
builder.setMessage(org + mActivity.getString(R.string.message_location))
.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.action_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, true, remember);
}
})
.setNegativeButton(mActivity.getString(R.string.action_dont_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, false, remember);
}
});
AlertDialog alert = builder.create();
alert.show();
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
Message resultMsg) {
mActivity.onCreateWindow(resultMsg);
return true;
}
@Override
public void onCloseWindow(WebView window) {
mActivity.onCloseWindow(mLightningView);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mActivity.openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mActivity.openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mActivity.openFileChooser(uploadMsg);
}
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
mActivity.showFileChooser(filePathCallback);
return true;
}
/**
* Obtain an image that is displayed as a placeholder on a video until the video has initialized
* and can begin loading.
*
* @return a Bitmap that can be used as a place holder for videos.
*/
@Override
public Bitmap getDefaultVideoPoster() {
final Resources resources = mActivity.getResources();
return BitmapFactory.decodeResource(resources, android.R.drawable.spinner_background);
}
/**
* Inflate a view to send to a LightningView when it needs to display a video and has to
* show a loading dialog. Inflates a progress view and returns it.
*
* @return A view that should be used to display the state
* of a video's loading progress.
*/
@Override
public View getVideoLoadingProgressView() {
LayoutInflater inflater = LayoutInflater.from(mActivity);
return inflater.inflate(R.layout.video_loading_progress, null);
}
@Override
public void onHideCustomView() {
mActivity.onHideCustomView();
super.onHideCustomView();
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
// While these lines might look like they work, in practice,
// Full-screen videos won't work correctly. I may test this out some
// more
// if (view instanceof FrameLayout) {
// FrameLayout frame = (FrameLayout) view;
// if (frame.getFocusedChild() instanceof VideoView) {
// VideoView video = (VideoView) frame.getFocusedChild();
// video.stopPlayback();
// frame.removeView(video);
// video.setVisibility(View.GONE);
// }
// } else {
mActivity.onShowCustomView(view, callback);
// }
super.onShowCustomView(view, callback);
}
@Override
@Deprecated
public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) {
// While these lines might look like they work, in practice,
// Full-screen videos won't work correctly. I may test this out some
// more
// if (view instanceof FrameLayout) {
// FrameLayout frame = (FrameLayout) view;
// if (frame.getFocusedChild() instanceof VideoView) {
// VideoView video = (VideoView) frame.getFocusedChild();
// video.stopPlayback();
// frame.removeView(video);
// video.setVisibility(View.GONE);
// }
// } else {
mActivity.onShowCustomView(view, callback);
// }
super.onShowCustomView(view, requestedOrientation, callback);
}
}

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

@ -6,26 +6,18 @@ package acr.browser.lightning.view; @@ -6,26 +6,18 @@ package acr.browser.lightning.view;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.net.MailTo;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.text.InputType;
import android.text.method.PasswordTransformationMethod;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
@ -34,60 +26,48 @@ import android.view.View; @@ -34,60 +26,48 @@ import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.LinearLayout;
import java.io.ByteArrayInputStream;
import com.squareup.otto.Bus;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.constant.StartPage;
import acr.browser.lightning.controller.BrowserController;
import acr.browser.lightning.dialog.LightningDialogBuilder;
import acr.browser.lightning.download.LightningDownloadListener;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.AdBlock;
import acr.browser.lightning.utils.IntentUtils;
import acr.browser.lightning.utils.PermissionsManager;
import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
public class LightningView {
private final Title mTitle;
final LightningViewTitle mTitle;
private WebView mWebView;
private final boolean mIsIncognitoTab;
private final BrowserController mBrowserController;
final boolean mIsIncognitoTab;
private final GestureDetector mGestureDetector;
private final Activity mActivity;
private final BrowserActivity mActivity;
private static String mHomepage;
private static String mDefaultUserAgent;
// TODO fix so that mWebpageBitmap can be static - static changes the icon when switching from light to dark and then back to light
private final Bitmap mWebpageBitmap;
private static PreferenceManager mPreferences;
private final AdBlock mAdBlock;
private final IntentUtils mIntentUtils;
private final Paint mPaint = new Paint();
private boolean isForegroundTab;
private boolean mTextReflow = false;
private boolean mInvertPage = false;
private boolean mToggleDesktop = false;
private static float mMaxFling;
@ -101,24 +81,28 @@ public class LightningView { @@ -101,24 +81,28 @@ public class LightningView {
};
private final PermissionsManager mPermissionsManager;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
private final WebViewHandler webViewHandler = new WebViewHandler();
@SuppressLint("NewApi")
public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito, BrowserController controller) {
@Inject
Bus eventBus;
@Inject
PreferenceManager mPreferences;
@Inject
LightningDialogBuilder bookmarksDialogBuilder;
@SuppressLint("NewApi")
public LightningView(BrowserActivity activity, String url, boolean darkTheme, boolean isIncognito) {
BrowserApp.getAppComponent().inject(this);
mActivity = activity;
mWebView = new WebView(activity);
mIsIncognitoTab = isIncognito;
mTitle = new Title(activity, darkTheme);
mAdBlock = AdBlock.getInstance(activity.getApplicationContext());
mTitle = new LightningViewTitle(activity, darkTheme);
mPermissionsManager = PermissionsManager.getInstance();
mWebpageBitmap = mTitle.mDefaultIcon;
mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity();
mBrowserController = controller;
mIntentUtils = new IntentUtils(mActivity);
mWebView.setDrawingCacheBackgroundColor(Color.WHITE);
mWebView.setFocusableInTouchMode(true);
mWebView.setFocusable(true);
@ -135,8 +119,8 @@ public class LightningView { @@ -135,8 +119,8 @@ public class LightningView {
mWebView.setScrollbarFadingEnabled(true);
mWebView.setSaveEnabled(true);
mWebView.setNetworkAvailable(true);
mWebView.setWebChromeClient(new LightningChromeClient(activity));
mWebView.setWebViewClient(new LightningWebClient(activity));
mWebView.setWebChromeClient(new LightningChromeClient(activity, this));
mWebView.setWebViewClient(new LightningWebClient(activity, this));
mWebView.setDownloadListener(new LightningDownloadListener(activity));
mGestureDetector = new GestureDetector(activity, new CustomGestureListener());
mWebView.setOnTouchListener(new TouchListener());
@ -162,12 +146,37 @@ public class LightningView { @@ -162,12 +146,37 @@ public class LightningView {
if (mHomepage.startsWith("about:home")) {
mWebView.loadUrl(StartPage.getHomepage(mActivity));
} else if (mHomepage.startsWith("about:bookmarks")) {
mBrowserController.openBookmarkPage(mWebView);
loadBookmarkpage();
} else {
mWebView.loadUrl(mHomepage);
}
}
/**
* Load the HTML bookmarks page in this view
*/
public void loadBookmarkpage() {
if (mWebView == null)
return;
Bitmap folderIcon = ThemeUtils.getThemedBitmap(mActivity, R.drawable.ic_folder, false);
FileOutputStream outputStream = null;
File image = new File(mActivity.getCacheDir(), "folder.png");
try {
outputStream = new FileOutputStream(image);
folderIcon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
folderIcon.recycle();
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
Utils.close(outputStream);
}
File bookmarkWebPage = new File(mActivity.getFilesDir(), Constants.BOOKMARKS_FILENAME);
BrowserApp.getAppComponent().getBookmarkPage().buildBookmarkPage(null);
mWebView.loadUrl(Constants.FILE + bookmarkWebPage);
}
/**
* Initialize the preference driven settings of the WebView
*
@ -182,12 +191,9 @@ public class LightningView { @@ -182,12 +191,9 @@ public class LightningView {
} else if (settings == null) {
settings = mWebView.getSettings();
}
mPreferences = PreferenceManager.getInstance();
settings.setDefaultTextEncodingName(mPreferences.getTextEncoding());
mHomepage = mPreferences.getHomepage();
mAdBlock.updatePreference();
setColorMode(mPreferences.getRenderingMode());
if (!mIsIncognitoTab) {
@ -242,7 +248,6 @@ public class LightningView { @@ -242,7 +248,6 @@ public class LightningView {
}
if (mPreferences.getTextReflowEnabled()) {
mTextReflow = true;
settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
if (API >= android.os.Build.VERSION_CODES.KITKAT) {
try {
@ -254,7 +259,6 @@ public class LightningView { @@ -254,7 +259,6 @@ public class LightningView {
}
}
} else {
mTextReflow = false;
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
}
@ -408,7 +412,7 @@ public class LightningView { @@ -408,7 +412,7 @@ public class LightningView {
public void setForegroundTab(boolean isForeground) {
isForegroundTab = isForeground;
mBrowserController.updateTabs();
eventBus.post(new BrowserEvents.TabsChanged());
}
public boolean isForegroundTab() {
@ -511,7 +515,7 @@ public class LightningView { @@ -511,7 +515,7 @@ public class LightningView {
public synchronized void reload() {
// Check if configured proxy is available
if (mBrowserController.proxyIsNotReady()) {
if (!ProxyUtils.getInstance().isProxyReady()) {
// User has been notified
return;
}
@ -579,6 +583,60 @@ public class LightningView { @@ -579,6 +583,60 @@ public class LightningView {
}
}
/**
* Used by {@link LightningWebClient}
*
* @return true if the page is in inverted mode, false otherwise
*/
public boolean getInvertePage() {
return mInvertPage;
}
/**
* handles a long click on the page, parameter String url
* is the url that should have been obtained from the WebView touch node
* thingy, if it is null, this method tries to deal with it and find a workaround
*/
private void longClickPage(final String url) {
final WebView.HitTestResult result = mWebView.getHitTestResult();
String currentUrl = mWebView.getUrl();
if (currentUrl != null && currentUrl.startsWith(Constants.FILE)) {
if (currentUrl.endsWith(HistoryPage.FILENAME)) {
if (url != null) {
bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url);
} else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra();
bookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl);
}
} else if (currentUrl.endsWith(Constants.BOOKMARKS_FILENAME)) {
if (url != null) {
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
} else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra();
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
}
}
} else {
if (url != null) {
if (result != null) {
if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
bookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent());
} else {
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
}
} else {
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
}
} else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra();
if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
bookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent());
} else {
bookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
}
}
}
}
public boolean canGoBack() {
return mWebView != null && mWebView.canGoBack();
}
@ -598,8 +656,7 @@ public class LightningView { @@ -598,8 +656,7 @@ public class LightningView {
public synchronized void loadUrl(String url) {
// Check if configured proxy is available
if (mBrowserController.proxyIsNotReady()) {
// User has been notified
if (!ProxyUtils.getInstance().isProxyReady()) {
return;
}
@ -621,500 +678,6 @@ public class LightningView { @@ -621,500 +678,6 @@ public class LightningView {
}
}
private static class IconCacheTask implements Runnable {
private final Uri uri;
private final Bitmap icon;
public IconCacheTask(Uri uri, Bitmap icon) {
this.uri = uri;
this.icon = icon;
}
@Override
public void run() {
String hash = String.valueOf(uri.getHost().hashCode());
Log.d(Constants.TAG, "Caching icon for " + uri.getHost());
FileOutputStream fos = null;
try {
File image = new File(BrowserApp.getAppContext().getCacheDir(), hash + ".png");
fos = new FileOutputStream(image);
icon.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
Utils.close(fos);
}
}
}
public class LightningWebClient extends WebViewClient {
final Activity mActivity;
LightningWebClient(Activity activity) {
mActivity = activity;
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mAdBlock.isAd(request.getUrl().toString())) {
ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
return new WebResourceResponse("text/plain", "utf-8", EMPTY);
}
}
return super.shouldInterceptRequest(view, request);
}
@SuppressWarnings("deprecation")
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (mAdBlock.isAd(url)) {
ByteArrayInputStream EMPTY = new ByteArrayInputStream("".getBytes());
return new WebResourceResponse("text/plain", "utf-8", EMPTY);
}
return null;
}
@SuppressLint("NewApi")
@Override
public void onPageFinished(WebView view, String url) {
if (view.isShown()) {
mBrowserController.updateUrl(url, true);
view.postInvalidate();
}
if (view.getTitle() == null || view.getTitle().isEmpty()) {
mTitle.setTitle(mActivity.getString(R.string.untitled));
} else {
mTitle.setTitle(view.getTitle());
}
if (API >= android.os.Build.VERSION_CODES.KITKAT && mInvertPage) {
view.evaluateJavascript(Constants.JAVASCRIPT_INVERT_PAGE, null);
}
mBrowserController.updateTabs();
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
if (isShown()) {
mBrowserController.updateUrl(url, false);
mBrowserController.showActionBar();
}
mTitle.setFavicon(mWebpageBitmap);
mBrowserController.updateTabs();
}
@Override
public void onReceivedHttpAuthRequest(final WebView view, @NonNull final HttpAuthHandler handler,
final String host, final String realm) {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
final EditText name = new EditText(mActivity);
final EditText password = new EditText(mActivity);
LinearLayout passLayout = new LinearLayout(mActivity);
passLayout.setOrientation(LinearLayout.VERTICAL);
passLayout.addView(name);
passLayout.addView(password);
name.setHint(mActivity.getString(R.string.hint_username));
name.setSingleLine();
password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
password.setSingleLine();
password.setTransformationMethod(new PasswordTransformationMethod());
password.setHint(mActivity.getString(R.string.hint_password));
builder.setTitle(mActivity.getString(R.string.title_sign_in));
builder.setView(passLayout);
builder.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.title_sign_in),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
String user = name.getText().toString();
String pass = password.getText().toString();
handler.proceed(user.trim(), pass.trim());
Log.d(Constants.TAG, "Request Login");
}
})
.setNegativeButton(mActivity.getString(R.string.action_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
handler.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
private boolean mIsRunning = false;
private float mZoomScale = 0.0f;
@SuppressLint("NewApi")
@Override
public void onScaleChanged(final WebView view, final float oldScale, final float newScale) {
if (view.isShown() && mTextReflow && API >= android.os.Build.VERSION_CODES.KITKAT) {
if (mIsRunning)
return;
if (Math.abs(mZoomScale - newScale) > 0.01f) {
mIsRunning = view.postDelayed(new Runnable() {
@Override
public void run() {
mZoomScale = newScale;
view.evaluateJavascript(Constants.JAVASCRIPT_TEXT_REFLOW, null);
mIsRunning = false;
}
}, 100);
}
}
}
private List<Integer> getAllSslErrorMessageCodes(SslError error) {
List<Integer> 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<Integer> errorCodeMessageCodes = getAllSslErrorMessageCodes(error);
StringBuilder stringBuilder = new StringBuilder();
for (Integer messageCode : errorCodeMessageCodes) {
stringBuilder.append(" - ").append(mActivity.getString(messageCode)).append('\n');
}
String alertMessage =
mActivity.getString(R.string.message_insecure_connection, stringBuilder.toString());
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(mActivity.getString(R.string.title_warning));
builder.setMessage(alertMessage)
.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.action_yes),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
handler.proceed();
}
})
.setNegativeButton(mActivity.getString(R.string.action_no),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
handler.cancel();
}
});
builder.create().show();
}
@Override
public void onFormResubmission(WebView view, @NonNull final Message dontResend, final Message resend) {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(mActivity.getString(R.string.title_form_resubmission));
builder.setMessage(mActivity.getString(R.string.message_form_resubmission))
.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.action_yes),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
resend.sendToTarget();
}
})
.setNegativeButton(mActivity.getString(R.string.action_no),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dontResend.sendToTarget();
}
});
AlertDialog alert = builder.create();
alert.show();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// Check if configured proxy is available
if (mBrowserController.proxyIsNotReady()) {
// User has been notified
return true;
}
if (mIsIncognitoTab) {
return super.shouldOverrideUrlLoading(view, url);
}
if (url.startsWith("about:")) {
return super.shouldOverrideUrlLoading(view, url);
}
if (url.contains("mailto:")) {
MailTo mailTo = MailTo.parse(url);
Intent i = Utils.newEmailIntent(mailTo.getTo(), mailTo.getSubject(),
mailTo.getBody(), mailTo.getCc());
mActivity.startActivity(i);
view.reload();
return true;
} else if (url.startsWith("intent://")) {
Intent intent;
try {
intent = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
} catch (URISyntaxException ex) {
return false;
}
if (intent != null) {
try {
mActivity.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(Constants.TAG, "ActivityNotFoundException");
}
return true;
}
}
return mIntentUtils.startActivityForUrl(mWebView, url);
}
}
public class LightningChromeClient extends WebChromeClient {
final Activity mActivity;
LightningChromeClient(Activity activity) {
mActivity = activity;
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (isShown()) {
mBrowserController.updateProgress(newProgress);
}
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
if (icon == null)
return;
mTitle.setFavicon(icon);
mBrowserController.updateTabs();
cacheFavicon(icon);
}
@Override
public void onReceivedTitle(WebView view, String title) {
if (title != null && !title.isEmpty()) {
mTitle.setTitle(title);
} else {
mTitle.setTitle(mActivity.getString(R.string.untitled));
}
mBrowserController.updateTabs();
if (view != null)
mBrowserController.updateHistory(title, view.getUrl());
}
@Override
public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) {
mPermissionsManager.requestPermissionsIfNecessary(mActivity, PERMISSIONS);
final boolean remember = true;
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(mActivity.getString(R.string.location));
String org;
if (origin.length() > 50) {
org = origin.subSequence(0, 50) + "...";
} else {
org = origin;
}
builder.setMessage(org + mActivity.getString(R.string.message_location))
.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.action_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, true, remember);
}
})
.setNegativeButton(mActivity.getString(R.string.action_dont_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, false, remember);
}
});
AlertDialog alert = builder.create();
alert.show();
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
Message resultMsg) {
mBrowserController.onCreateWindow(resultMsg);
return true;
}
@Override
public void onCloseWindow(WebView window) {
mBrowserController.onCloseWindow(LightningView.this);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mBrowserController.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mBrowserController.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mBrowserController.openFileChooser(uploadMsg);
}
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
mBrowserController.showFileChooser(filePathCallback);
return true;
}
@Override
public Bitmap getDefaultVideoPoster() {
return mBrowserController.getDefaultVideoPoster();
}
@Override
public View getVideoLoadingProgressView() {
return mBrowserController.getVideoLoadingProgressView();
}
@Override
public void onHideCustomView() {
mBrowserController.onHideCustomView();
super.onHideCustomView();
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
// While these lines might look like they work, in practice,
// Full-screen videos won't work correctly. I may test this out some
// more
// if (view instanceof FrameLayout) {
// FrameLayout frame = (FrameLayout) view;
// if (frame.getFocusedChild() instanceof VideoView) {
// VideoView video = (VideoView) frame.getFocusedChild();
// video.stopPlayback();
// frame.removeView(video);
// video.setVisibility(View.GONE);
// }
// } else {
mBrowserController.onShowCustomView(view, callback);
// }
super.onShowCustomView(view, callback);
}
@SuppressWarnings("deprecation")
@Override
@Deprecated
public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) {
// While these lines might look like they work, in practice,
// Full-screen videos won't work correctly. I may test this out some
// more
// if (view instanceof FrameLayout) {
// FrameLayout frame = (FrameLayout) view;
// if (frame.getFocusedChild() instanceof VideoView) {
// VideoView video = (VideoView) frame.getFocusedChild();
// video.stopPlayback();
// frame.removeView(video);
// video.setVisibility(View.GONE);
// }
// } else {
mBrowserController.onShowCustomView(view, callback);
// }
super.onShowCustomView(view, requestedOrientation, callback);
}
}
public class Title {
private Bitmap mFavicon;
private String mTitle;
private final Bitmap mDefaultIcon;
public Title(Context context, boolean darkTheme) {
mDefaultIcon = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
mFavicon = mDefaultIcon;
mTitle = mActivity.getString(R.string.action_new_tab);
}
public void setFavicon(Bitmap favicon) {
if (favicon == null) {
mFavicon = mDefaultIcon;
} else {
mFavicon = Utils.padFavicon(favicon);
}
}
public void setTitle(String title) {
if (title == null) {
mTitle = "";
} else {
mTitle = title;
}
}
public void setTitleAndFavicon(String title, Bitmap favicon) {
mTitle = title;
if (favicon == null) {
mFavicon = mDefaultIcon;
} else {
mFavicon = Utils.padFavicon(favicon);
}
}
public String getTitle() {
return mTitle;
}
public Bitmap getFavicon() {
return mFavicon;
}
}
private class TouchListener implements OnTouchListener {
float mLocation;
@ -1137,9 +700,9 @@ public class LightningView { @@ -1137,9 +700,9 @@ public class LightningView {
} else if (mAction == MotionEvent.ACTION_UP) {
final float distance = (mY - mLocation);
if (distance > SCROLL_UP_THRESHOLD && view.getScrollY() < SCROLL_UP_THRESHOLD) {
mBrowserController.showActionBar();
mActivity.showActionBar();
} else if (distance < -SCROLL_UP_THRESHOLD) {
mBrowserController.hideActionBar();
mActivity.hideActionBar();
}
mLocation = 0;
}
@ -1154,9 +717,9 @@ public class LightningView { @@ -1154,9 +717,9 @@ public class LightningView {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int power = (int) (velocityY * 100 / mMaxFling);
if (power < -10) {
mBrowserController.hideActionBar();
mActivity.hideActionBar();
} else if (power > 15) {
mBrowserController.showActionBar();
mActivity.showActionBar();
}
return super.onFling(e1, e2, velocityX, velocityY);
}
@ -1172,8 +735,13 @@ public class LightningView { @@ -1172,8 +735,13 @@ public class LightningView {
@Override
public void onLongPress(MotionEvent e) {
if (mCanTriggerLongPress)
mBrowserController.onLongPress();
if (mCanTriggerLongPress) {
Message msg = webViewHandler.obtainMessage();
if (msg != null) {
msg.setTarget(webViewHandler);
mWebView.requestFocusNodeHref(msg);
}
}
}
/**
@ -1195,4 +763,13 @@ public class LightningView { @@ -1195,4 +763,13 @@ public class LightningView {
mCanTriggerLongPress = true;
}
}
private class WebViewHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
final String url = msg.getData().getString("url");
longClickPage(url);
}
}
}

66
app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java

@ -0,0 +1,66 @@ @@ -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;
}
}

276
app/src/main/java/acr/browser/lightning/view/LightningWebClient.java

@ -0,0 +1,276 @@ @@ -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);
}
}

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

@ -25,7 +25,14 @@ @@ -25,7 +25,14 @@
<include layout="@layout/search_interface" />
</LinearLayout>
<include layout="@layout/tab_drawer" />
<FrameLayout
android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent"
android:background="?attr/drawerBackground"
android:id="@+id/left_drawer"
android:fitsSystemWindows="true"
android:layout_gravity="start"
android:weightSum="1" />
<FrameLayout
android:weightSum="1"
@ -34,14 +41,8 @@ @@ -34,14 +41,8 @@
android:id="@+id/right_drawer"
android:background="?attr/drawerBackground"
android:layout_width="@dimen/navigation_width"
android:layout_height="match_parent">
<fragment
android:id="@+id/bookmark_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="acr.browser.lightning.fragment.BookmarksFragment" />
</FrameLayout>
<!-- include layout="@layout/bookmark_drawer" / -->
android:layout_height="match_parent" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>

10
app/src/main/res/layout/tab_drawer.xml

@ -1,12 +1,9 @@ @@ -1,12 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/left_drawer"
android:layout_width="@dimen/navigation_width"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="?attr/drawerBackground"
android:clickable="true"
android:fitsSystemWindows="true"
android:orientation="vertical">
<LinearLayout
@ -45,12 +42,13 @@ @@ -45,12 +42,13 @@
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/left_drawer_list"
android:id="@+id/tabs_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
android:dividerHeight="0dp" />
android:dividerHeight="0dp"
android:overScrollMode="ifContentScrolls" />
<LinearLayout
android:layout_width="match_parent"

9
app/src/main/res/layout/tab_strip.xml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/black"
android:overScrollMode="never"
android:scrollbars="none"
android:id="@+id/tabs_list" />

7
app/src/main/res/layout/toolbar.xml

@ -8,13 +8,10 @@ @@ -8,13 +8,10 @@
android:elevation="2dp"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/twv_list"
<FrameLayout
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="@color/black"
android:overScrollMode="never"
android:scrollbars="none" />
android:id="@+id/tabs_toolbar_container"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"

Loading…
Cancel
Save