Browse Source

Merge pull request #1 from ravjit-cliqz/dev

Moved deleting logic to tabs manager
master
Stefano Pacifici 9 years ago
parent
commit
1eb2407543
  1. 3
      .travis.yml
  2. 12
      README.md
  3. 43
      app/build.gradle
  4. 12
      app/proguard-project.txt
  5. 14
      app/src/LightningLite/java/acr/browser/lightning/utils/ProxyUtils.java
  6. 13
      app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java
  7. 13
      app/src/main/AndroidManifest.xml
  8. 1382
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  9. 15
      app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
  10. 17
      app/src/main/java/acr/browser/lightning/activity/MainActivity.java
  11. 21
      app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
  12. 4
      app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java
  13. 289
      app/src/main/java/acr/browser/lightning/activity/TabsManager.java
  14. 15
      app/src/main/java/acr/browser/lightning/activity/ThemableBrowserActivity.java
  15. 6
      app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
  16. 32
      app/src/main/java/acr/browser/lightning/app/AppComponent.java
  17. 11
      app/src/main/java/acr/browser/lightning/app/BrowserApp.java
  18. 29
      app/src/main/java/acr/browser/lightning/bus/BookmarkEvents.java
  19. 58
      app/src/main/java/acr/browser/lightning/bus/BrowserEvents.java
  20. 34
      app/src/main/java/acr/browser/lightning/bus/NavigationEvents.java
  21. 65
      app/src/main/java/acr/browser/lightning/bus/TabEvents.java
  22. 18
      app/src/main/java/acr/browser/lightning/constant/BookmarkPage.java
  23. 5
      app/src/main/java/acr/browser/lightning/constant/Constants.java
  24. 2
      app/src/main/java/acr/browser/lightning/constant/HistoryPage.java
  25. 7
      app/src/main/java/acr/browser/lightning/constant/StartPage.java
  26. 36
      app/src/main/java/acr/browser/lightning/controller/UIController.java
  27. 4
      app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java
  28. 66
      app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
  29. 125
      app/src/main/java/acr/browser/lightning/dialog/LightningDialogBuilder.java
  30. 69
      app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
  31. 26
      app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
  32. 18
      app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
  33. 8
      app/src/main/java/acr/browser/lightning/download/WebAddress.java
  34. 41
      app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
  35. 49
      app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java
  36. 69
      app/src/main/java/acr/browser/lightning/fragment/BookmarksFragment.java
  37. 42
      app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
  38. 138
      app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
  39. 27
      app/src/main/java/acr/browser/lightning/fragment/LightningPreferenceFragment.java
  40. 80
      app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
  41. 359
      app/src/main/java/acr/browser/lightning/fragment/TabsFragment.java
  42. 30
      app/src/main/java/acr/browser/lightning/object/ClickHandler.java
  43. 32
      app/src/main/java/acr/browser/lightning/object/SearchAdapter.java
  44. 37
      app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
  45. 3
      app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java
  46. 16
      app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java
  47. 2
      app/src/main/java/acr/browser/lightning/reading/OutputFormatter.java
  48. 2
      app/src/main/java/acr/browser/lightning/reading/SHelper.java
  49. 6
      app/src/main/java/acr/browser/lightning/utils/AdBlock.java
  50. 11
      app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
  51. 75
      app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java
  52. 17
      app/src/main/java/acr/browser/lightning/utils/UrlUtils.java
  53. 15
      app/src/main/java/acr/browser/lightning/utils/Utils.java
  54. 4
      app/src/main/java/acr/browser/lightning/utils/WebUtils.java
  55. 44
      app/src/main/java/acr/browser/lightning/view/IconCacheTask.java
  56. 233
      app/src/main/java/acr/browser/lightning/view/LightningChromeClient.java
  57. 729
      app/src/main/java/acr/browser/lightning/view/LightningView.java
  58. 66
      app/src/main/java/acr/browser/lightning/view/LightningViewTitle.java
  59. 319
      app/src/main/java/acr/browser/lightning/view/LightningWebClient.java
  60. 19
      app/src/main/res/layout/activity_main.xml
  61. 29
      app/src/main/res/layout/tab_drawer.xml
  62. 9
      app/src/main/res/layout/tab_strip.xml
  63. 7
      app/src/main/res/layout/toolbar.xml
  64. 33
      app/src/main/res/values-de/strings.xml
  65. 1
      app/src/main/res/values-es/strings.xml
  66. 1
      app/src/main/res/values-gr/strings.xml
  67. 1
      app/src/main/res/values-hu/strings.xml
  68. 229
      app/src/main/res/values-it/strings.xml
  69. 1
      app/src/main/res/values-ja/strings.xml
  70. 1
      app/src/main/res/values-ko/strings.xml
  71. 78
      app/src/main/res/values-pl/strings.xml
  72. 1
      app/src/main/res/values-pt/strings.xml
  73. 1
      app/src/main/res/values-ru/strings.xml
  74. 50
      app/src/main/res/values-sr/strings.xml
  75. 1
      app/src/main/res/values-tr/strings.xml
  76. 8
      app/src/main/res/values-v16/styles.xml
  77. 1
      app/src/main/res/values-zh-rCN/strings.xml
  78. 10
      app/src/main/res/values/strings.xml
  79. 1
      app/src/main/res/values/styles.xml
  80. 30
      app/src/main/res/xml/preference_privacy.xml
  81. 2
      build.gradle

3
.travis.yml

@ -2,8 +2,8 @@ language: android @@ -2,8 +2,8 @@ language: android
sudo: false
android:
components:
- build-tools-23.0.1
- build-tools-22.0.1
- build-tools-23.0.0
- android-23
- android-22
- extra-android-support
@ -17,3 +17,4 @@ before_install: @@ -17,3 +17,4 @@ before_install:
install:
- ./gradlew
script:
- ./gradlew assembleRelease

12
README.md

@ -4,7 +4,11 @@ @@ -4,7 +4,11 @@
####Download
* [Download APK from here](https://github.com/anthonycr/Lightning-Browser/releases)
* [Download from Google Play](https://play.google.com/store/apps/details?id=acr.browser.barebones)
* [Download from F-Droid](https://f-droid.org/repository/browse/?fdfilter=lightning&fdid=acr.browser.lightning)
* [Download Free from Google Play](https://play.google.com/store/apps/details?id=acr.browser.barebones)
* [Download Paid from Google Play](https://play.google.com/store/apps/details?id=acr.browser.lightning)
####Master Branch
* [![Build Status](https://travis-ci.org/anthonycr/Lightning-Browser.svg?branch=master)](https://travis-ci.org/anthonycr/Lightning-Browser)
@ -46,12 +50,14 @@ @@ -46,12 +50,14 @@
* Please add translations/translation fixes as you see need
####Contributing
* [The Trello Board](https://trello.com/b/Gwjx8MC3/lightning-browser)
* Contributions are always welcome
* If you want a feature and can code, feel free to fork and add the change yourself and make a pull request
* PLEASE use the ````dev```` branch when contributing as the ````master```` branch is supposed to be for stable builds. I will not reject your pull request if you make it on master, but it will annoy me and make my life harder.
* Code Style
* Standard Java camel case
* Member variables are preceded with an 'm'
* Hungarian Notation
* Prefix member variables with 'm'
* Prefix static member variables with 's'
* Use 4 spaces instead of a tab (\t)
####Setting Up the Project

43
app/build.gradle

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'com.getkeepsafe.dexcount'
android {
compileSdkVersion 23
@ -7,7 +8,7 @@ android { @@ -7,7 +8,7 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionName "4.2.0a"
versionName "4.2.3.1"
}
sourceSets {
lightningPlus.setRoot('src/LightningPlus')
@ -30,40 +31,64 @@ android { @@ -30,40 +31,64 @@ android {
lightningPlus {
buildConfigField "boolean", "FULL_VERSION", "true"
applicationId "acr.browser.lightning"
versionCode 81
versionCode 85
}
lightningLite {
buildConfigField "boolean", "FULL_VERSION", "false"
applicationId "acr.browser.barebones"
versionCode 82
versionCode 86
}
}
lintOptions {
abortOnError true
}
packagingOptions {
exclude '.readme'
}
}
dexcount {
includeClasses = false
includeFieldCount = false
printAsTree = true
orderByMethodCount = true
verbose = false
}
dependencies {
compile 'com.android.support:palette-v7:23.0.1'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
// support libraries
compile 'com.android.support:palette-v7:23.1.0'
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:design:23.1.0'
compile 'com.android.support:recyclerview-v7:23.1.0'
// html parsing fo reading mode
compile 'org.jsoup:jsoup:1.8.3'
// event bus
compile 'com.squareup:otto:1.3.8'
// dependency injection
compile 'com.google.dagger:dagger:2.0.1'
apt 'com.google.dagger:dagger-compiler:2.0.1'
// view binding
compile 'com.jakewharton:butterknife:7.0.1'
// Only Lightning Plus needs the proxy libraries
compile 'net.i2p.android:client:0.7'
// permissions
compile 'com.anthonycr.grant:permissions:1.0'
// proxy support
compile 'net.i2p.android:client:0.7'
// Use the following code to update the libnetcipher submodule
// git submodule foreach git reset --hard
// git submodule update --remote
compile(project(':libnetcipher'))
// memory leak analysis
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
provided 'javax.annotation:jsr250-api:1.0'
}

12
app/proguard-project.txt

@ -50,6 +50,18 @@ @@ -50,6 +50,18 @@
public static *** i(...);
}
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
# this will fix a force close in ReadingActivity
-keep public class org.jsoup.** {
public *;

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);

13
app/src/main/AndroidManifest.xml

@ -47,6 +47,18 @@ @@ -47,6 +47,18 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="application/xhtml+xml"/>
<data android:mimeType="application/vnd.wap.xhtml+xml"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="about" />
@ -88,7 +100,6 @@ @@ -88,7 +100,6 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="" />
<data android:scheme="http" />
<data android:scheme="https" />
</intent-filter>

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

File diff suppressed because it is too large Load Diff

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

@ -2,12 +2,13 @@ package acr.browser.lightning.activity; @@ -2,12 +2,13 @@ package acr.browser.lightning.activity;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Menu;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager;
@SuppressWarnings("deprecation")
public class IncognitoActivity extends BrowserActivity {
@ -18,13 +19,13 @@ public class IncognitoActivity extends BrowserActivity { @@ -18,13 +19,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) {
@ -45,7 +46,7 @@ public class IncognitoActivity extends BrowserActivity { @@ -45,7 +46,7 @@ public class IncognitoActivity extends BrowserActivity {
}
@Override
public void updateHistory(String title, String url) {
public void updateHistory(@Nullable String title, @NonNull String url) {
// addItemToHistory(title, url);
}

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

@ -2,12 +2,13 @@ package acr.browser.lightning.activity; @@ -2,12 +2,13 @@ package acr.browser.lightning.activity;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Menu;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager;
@SuppressWarnings("deprecation")
public class MainActivity extends BrowserActivity {
@ -18,14 +19,14 @@ public class MainActivity extends BrowserActivity { @@ -18,14 +19,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) {
@ -46,7 +47,7 @@ public class MainActivity extends BrowserActivity { @@ -46,7 +47,7 @@ public class MainActivity extends BrowserActivity {
}
@Override
public void updateHistory(String title, String url) {
public void updateHistory(@Nullable String title, @NonNull String url) {
addItemToHistory(title, url);
}

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

@ -21,7 +21,10 @@ import android.widget.SeekBar; @@ -21,7 +21,10 @@ import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import java.lang.ref.WeakReference;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.reading.HtmlFetcher;
@ -38,6 +41,7 @@ public class ReadingActivity extends AppCompatActivity { @@ -38,6 +41,7 @@ public class ReadingActivity extends AppCompatActivity {
private PreferenceManager mPreferences;
private int mTextSize;
private ProgressDialog mProgressDialog;
private PageLoader mLoaderReference;
private static final float XXLARGE = 30.0f;
private static final float XLARGE = 26.0f;
@ -49,7 +53,7 @@ public class ReadingActivity extends AppCompatActivity { @@ -49,7 +53,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) {
@ -129,30 +133,34 @@ public class ReadingActivity extends AppCompatActivity { @@ -129,30 +133,34 @@ public class ReadingActivity extends AppCompatActivity {
}
if (getSupportActionBar() != null)
getSupportActionBar().setTitle(Utils.getDomainName(mUrl));
new PageLoader(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mUrl);
mLoaderReference = new PageLoader(this);
mLoaderReference.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mUrl);
return true;
}
private class PageLoader extends AsyncTask<String, Void, Void> {
private final Activity mActivity;
private final WeakReference<Activity> mActivityReference;
private String mTitleText;
private String mBodyText;
public PageLoader(Activity activity) {
mActivity = activity;
mActivityReference = new WeakReference<>(activity);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(mActivity);
Activity activity = mActivityReference.get();
if (activity != null) {
mProgressDialog = new ProgressDialog(activity);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setCancelable(false);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setMessage(mActivity.getString(R.string.loading));
mProgressDialog.setMessage(activity.getString(R.string.loading));
mProgressDialog.show();
}
}
@Override
protected Void doInBackground(String... params) {
@ -223,6 +231,7 @@ public class ReadingActivity extends AppCompatActivity { @@ -223,6 +231,7 @@ public class ReadingActivity extends AppCompatActivity {
mProgressDialog.dismiss();
mProgressDialog = null;
}
mLoaderReference.cancel(true);
super.onDestroy();
}

4
app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java

@ -15,7 +15,7 @@ import java.util.ArrayList; @@ -15,7 +15,7 @@ import java.util.ArrayList;
import java.util.List;
import acr.browser.lightning.R;
import acr.browser.lightning.utils.PermissionsManager;
import com.anthonycr.grant.PermissionsManager;
public class SettingsActivity extends ThemableSettingsActivity {
@ -61,7 +61,7 @@ public class SettingsActivity extends ThemableSettingsActivity { @@ -61,7 +61,7 @@ public class SettingsActivity extends ThemableSettingsActivity {
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
PermissionsManager.getInstance().notifyPermissionsChange(permissions);
PermissionsManager.getInstance().notifyPermissionsChange(permissions, grantResults);
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

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

@ -0,0 +1,289 @@ @@ -0,0 +1,289 @@
package acr.browser.lightning.activity;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.webkit.WebView;
import com.squareup.otto.Bus;
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.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.UrlUtils;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.view.LightningView;
/**
* @author Stefano Pacifici
* @date 2015/09/14
*/
@Singleton
public class TabsManager {
private static final String TAG = TabsManager.class.getSimpleName();
private final List<LightningView> mWebViewList = new ArrayList<>();
private LightningView mCurrentTab;
@Inject
PreferenceManager mPreferenceManager;
@Inject
Bus mEventBus;
@Inject
public TabsManager() {}
public synchronized void restoreTabsAndHandleIntent(final Activity activity,
final Intent intent,
final boolean incognito) {
String url = null;
if (intent != null) {
url = intent.getDataString();
}
mWebViewList.clear();
mCurrentTab = null;
if (!incognito && mPreferenceManager.getRestoreLostTabsEnabled()) {
final String mem = mPreferenceManager.getMemoryUrl();
mPreferenceManager.setMemoryUrl("");
String[] array = Utils.getArray(mem);
for (String urlString : array) {
if (!urlString.isEmpty()) {
newTab(activity, urlString, incognito);
}
}
}
if (url != null) {
if (url.startsWith(Constants.FILE)) {
final String urlToLoad = url;
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setCancelable(true)
.setTitle(R.string.title_warning)
.setMessage(R.string.message_blocked_local)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.action_open, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
newTab(activity, urlToLoad, incognito);
}
})
.show();
} else {
newTab(activity, url, incognito);
}
}
if (mWebViewList.size() == 0) {
newTab(activity, null, incognito);
}
}
/**
* 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 synchronized LightningView getTabAtPosition(final int position) {
if (position < 0 || position >= mWebViewList.size()) {
return null;
}
return mWebViewList.get(position);
}
/**
* Try to low memory pressure
*/
public synchronized void freeMemory() {
for (LightningView tab : mWebViewList) {
tab.freeMemory();
}
}
/**
* Shutdown the manager
*/
public synchronized void shutdown() {
for (LightningView tab : mWebViewList) {
tab.onDestroy();
}
mWebViewList.clear();
mCurrentTab = null;
}
/**
* 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 notifyConnectionStatus(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 synchronized 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 isIncognito
* @return
*/
public synchronized LightningView newTab(final Activity activity,
final String url,
final boolean isIncognito) {
final LightningView tab = new LightningView(activity, url, 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 removeTab(final int position) {
if (position >= mWebViewList.size()) {
return null;
}
final LightningView tab = mWebViewList.remove(position);
if (mCurrentTab == tab) {
mCurrentTab = null;
}
tab.onDestroy();
Log.d(Constants.TAG, tab.toString());
return tab;
}
public synchronized void deleteTab(int position) {
final LightningView currentTab = getCurrentTab();
int current = positionOf(currentTab);
if (current == position) {
if (size() == 1) {
mCurrentTab = null;
} else if (current < size() - 1 ) {
// There is another tab after this one
mCurrentTab = getTabAtPosition(current + 1);
} else {
mCurrentTab = getTabAtPosition(current - 1);
}
removeTab(current);
} else {
removeTab(position);
}
}
/**
* Return the position of the given tab.
*
* @param tab the tab to look for
* @return the position of the tab or -1 if the tab is not in the list
*/
public synchronized 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.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 synchronized WebView getCurrentWebView() {
return mCurrentTab != null ? mCurrentTab.getWebView() : null;
}
/**
* TODO We should remove also this, but probably not
*
* @return
*/
@Nullable
public synchronized 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 synchronized LightningView switchToTab(final int position) {
if (position < 0 || position >= mWebViewList.size()) {
Log.e(TAG, "Returning a null LightningView requested for position: " + position);
return null;
} else {
final LightningView tab = mWebViewList.get(position);
if (tab != null) {
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();
}

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

@ -4,7 +4,7 @@ import android.graphics.drawable.ColorDrawable; @@ -4,7 +4,7 @@ import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.utils.ThemeUtils;
public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivity {
@ -13,7 +13,7 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi @@ -13,7 +13,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 +32,7 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi @@ -32,7 +32,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);
}

11
app/src/main/java/acr/browser/lightning/app/BrowserApp.java

@ -7,19 +7,24 @@ import com.squareup.leakcanary.LeakCanary; @@ -7,19 +7,24 @@ import com.squareup.leakcanary.LeakCanary;
public class BrowserApp extends Application {
private static Context context;
private static Context sContext;
private static AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
LeakCanary.install(this);
buildDepencyGraph();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
sContext = base;
}
public static Context getAppContext() {
return context;
return sContext;
}
public static AppComponent getAppComponent() {

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

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

@ -20,11 +20,16 @@ import acr.browser.lightning.utils.Utils; @@ -20,11 +20,16 @@ import acr.browser.lightning.utils.Utils;
public final class BookmarkPage {
/**
* The bookmark page standard suffix
*/
public static final String FILENAME = "bookmarks.html";
private static final String HEADING = "<!DOCTYPE html><html xmlns=http://www.w3.org/1999/xhtml>\n" +
"<head>\n" +
"<meta content=en-us http-equiv=Content-Language />\n" +
"<meta content='text/html; charset=utf-8' http-equiv=Content-Type />\n" +
"<meta name=viewport content='width=device-width, initial-scale=1.0'>\n" +
"<meta name=viewport content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no'>\n" +
"<title>" +
BrowserApp.getAppContext().getString(R.string.action_bookmarks) +
"</title>\n" +
@ -62,12 +67,13 @@ public final class BookmarkPage { @@ -62,12 +67,13 @@ 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);
bookmarkWebPage = new File(FILES_DIR, FILENAME);
} else {
bookmarkWebPage = new File(FILES_DIR, folder + '-' + Constants.BOOKMARKS_FILENAME);
bookmarkWebPage = new File(FILES_DIR, folder + '-' + FILENAME);
}
final StringBuilder bookmarkBuilder = new StringBuilder(BookmarkPage.HEADING);
@ -76,14 +82,14 @@ public final class BookmarkPage { @@ -76,14 +82,14 @@ public final class BookmarkPage {
final HistoryItem item = list.get(n);
bookmarkBuilder.append(BookmarkPage.PART1);
if (item.isFolder()) {
final File folderPage = new File(FILES_DIR, item.getTitle() + '-' + Constants.BOOKMARKS_FILENAME);
final File folderPage = new File(FILES_DIR, item.getTitle() + '-' + FILENAME);
bookmarkBuilder.append(Constants.FILE).append(folderPage);
bookmarkBuilder.append(BookmarkPage.PART2);
bookmarkBuilder.append(folderIconPath);
new Thread(new Runnable() {
@Override
public void run() {
buildBookmarkPage(item.getTitle(), manager.getBookmarksFromFolder(item.getTitle(), true));
buildBookmarkPage(item.getTitle());
}
}).run();
} else {

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

@ -43,11 +43,6 @@ public final class Constants { @@ -43,11 +43,6 @@ public final class Constants {
public static final int PROXY_I2P = 2;
public static final int PROXY_MANUAL = 3;
/**
* The bookmark page standard suffix
*/
public static final String BOOKMARKS_FILENAME = "bookmarks.html";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String[] TEXT_ENCODINGS = {"ISO-8859-1", "UTF-8", "GBK", "Big5", "ISO-2022-JP", "SHIFT_JS", "EUC-JP", "EUC-KR"};

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();
}
}

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

@ -16,7 +16,7 @@ import acr.browser.lightning.utils.Utils; @@ -16,7 +16,7 @@ import acr.browser.lightning.utils.Utils;
public class StartPage {
private static final String FILENAME = "homepage.html";
public static final String FILENAME = "homepage.html";
private static final String HEAD = "<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\">"
+ "<head>"
@ -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;

36
app/src/main/java/acr/browser/lightning/controller/BrowserController.java → app/src/main/java/acr/browser/lightning/controller/UIController.java

@ -4,36 +4,40 @@ @@ -4,36 +4,40 @@
package acr.browser.lightning.controller;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Message;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient.CustomViewCallback;
import android.webkit.WebView;
import acr.browser.lightning.view.LightningView;
public interface BrowserController {
public interface UIController {
void updateUrl(String title, boolean shortUrl);
void changeToolbarBackground(@NonNull Bitmap favicon, @Nullable Drawable drawable);
void updateProgress(int n);
@ColorInt
int getUiColor();
void updateHistory(String title, String url);
boolean getUseDarkTheme();
void openFileChooser(ValueCallback<Uri> uploadMsg);
void updateUrl(@Nullable String title, boolean shortUrl);
void updateTabs();
void updateProgress(int n);
void onLongPress();
void updateHistory(@Nullable String title, @NonNull String url);
void onShowCustomView(View view, CustomViewCallback callback);
void openFileChooser(ValueCallback<Uri> uploadMsg);
void onHideCustomView();
void onShowCustomView(View view, CustomViewCallback callback);
Bitmap getDefaultVideoPoster();
void onShowCustomView(View view, CustomViewCallback callback, int requestedOrienation);
View getVideoLoadingProgressView();
void onHideCustomView();
void onCreateWindow(Message resultMsg);
@ -43,16 +47,8 @@ public interface BrowserController { @@ -43,16 +47,8 @@ public interface BrowserController {
void showActionBar();
void longClickPage(String url);
void openBookmarkPage(WebView view);
void showFileChooser(ValueCallback<Uri[]> filePathCallback);
void closeEmptyTab();
boolean proxyIsNotReady();
// void updateBookmarkIndicator(String url);
}

4
app/src/main/java/acr/browser/lightning/database/BookmarkLocalSync.java

@ -26,7 +26,7 @@ public class BookmarkLocalSync { @@ -26,7 +26,7 @@ public class BookmarkLocalSync {
private final Context mContext;
public BookmarkLocalSync(Context context) {
public BookmarkLocalSync(@NonNull Context context) {
mContext = context;
}
@ -72,7 +72,7 @@ public class BookmarkLocalSync { @@ -72,7 +72,7 @@ public class BookmarkLocalSync {
if (!isChromeSupported()) {
return list;
}
Cursor cursor = getStockCursor();
Cursor cursor = getChromeCursor();
try {
if (cursor != null) {
for (int n = 0; n < cursor.getColumnCount(); n++) {

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

@ -8,13 +8,18 @@ import android.content.Context; @@ -8,13 +8,18 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
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
@ -35,18 +40,8 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -35,18 +40,8 @@ public class HistoryDatabase extends SQLiteOpenHelper {
private SQLiteDatabase mDatabase;
private static HistoryDatabase mInstance;
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();
}
@ -69,70 +64,61 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -69,70 +64,61 @@ public class HistoryDatabase extends SQLiteOpenHelper {
onCreate(db);
}
public void deleteHistory() {
public synchronized void deleteHistory() {
mDatabase.delete(TABLE_HISTORY, null, null);
mDatabase.close();
mDatabase = this.getWritableDatabase();
}
public boolean isClosed() {
private synchronized boolean isClosed() {
return mDatabase == null || !mDatabase.isOpen();
}
@Override
public synchronized void close() {
if (!mLock) {
if (mDatabase != null) {
mDatabase.close();
mDatabase = null;
}
}
super.close();
}
private void openIfNecessary() {
if (mDatabase == null) {
if (isClosed()) {
mDatabase = this.getWritableDatabase();
}
}
public synchronized void deleteHistoryItem(String url) {
mLock = true;
openIfNecessary();
mDatabase.delete(TABLE_HISTORY, KEY_URL + " = ?", new String[]{url});
mLock = false;
}
public synchronized void visitHistoryItem(String url, String title) {
mLock = true;
public synchronized void visitHistoryItem(@NonNull String url, @Nullable String title) {
openIfNecessary();
ContentValues values = new ContentValues();
values.put(KEY_TITLE, title);
values.put(KEY_TITLE, title == null ? "" : title);
values.put(KEY_TIME_VISITED, System.currentTimeMillis());
Cursor q = mDatabase.query(false, TABLE_HISTORY, new String[]{KEY_URL},
KEY_URL + " = ?", new String[]{url}, null, null, null, "1");
if (q.getCount() > 0) {
mDatabase.update(TABLE_HISTORY, values, KEY_URL + " = ?", new String[]{url});
} else {
addHistoryItem(new HistoryItem(url, title));
addHistoryItem(new HistoryItem(url, title == null ? "" : title));
}
q.close();
mLock = false;
}
private synchronized void addHistoryItem(HistoryItem item) {
mLock = true;
private synchronized void addHistoryItem(@NonNull HistoryItem item) {
openIfNecessary();
ContentValues values = new ContentValues();
values.put(KEY_URL, item.getUrl());
values.put(KEY_TITLE, item.getTitle());
values.put(KEY_TIME_VISITED, System.currentTimeMillis());
mDatabase.insert(TABLE_HISTORY, null, values);
mLock = false;
}
String getHistoryItem(String url) {
mLock = true;
synchronized String getHistoryItem(String url) {
openIfNecessary();
Cursor cursor = mDatabase.query(TABLE_HISTORY, new String[]{KEY_ID, KEY_URL, KEY_TITLE},
KEY_URL + " = ?", new String[]{url}, null, null, null, null);
@ -143,14 +129,15 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -143,14 +129,15 @@ public class HistoryDatabase extends SQLiteOpenHelper {
cursor.close();
}
mLock = false;
return m;
}
public List<HistoryItem> findItemsContaining(String search) {
mLock = true;
public synchronized List<HistoryItem> findItemsContaining(@Nullable String search) {
openIfNecessary();
List<HistoryItem> itemList = new ArrayList<>(5);
if (search == null) {
return itemList;
}
String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " WHERE " + KEY_TITLE + " LIKE '%"
+ search + "%' OR " + KEY_URL + " LIKE '%" + search + "%' " + "ORDER BY "
+ KEY_TIME_VISITED + " DESC LIMIT 5";
@ -168,12 +155,10 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -168,12 +155,10 @@ public class HistoryDatabase extends SQLiteOpenHelper {
} while (cursor.moveToNext() && n < 5);
}
cursor.close();
mLock = false;
return itemList;
}
public List<HistoryItem> getLastHundredItems() {
mLock = true;
public synchronized List<HistoryItem> getLastHundredItems() {
openIfNecessary();
List<HistoryItem> itemList = new ArrayList<>(100);
String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " ORDER BY " + KEY_TIME_VISITED
@ -192,12 +177,10 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -192,12 +177,10 @@ public class HistoryDatabase extends SQLiteOpenHelper {
} while (cursor.moveToNext() && counter < 100);
}
cursor.close();
mLock = false;
return itemList;
}
public List<HistoryItem> getAllHistoryItems() {
mLock = true;
public synchronized List<HistoryItem> getAllHistoryItems() {
openIfNecessary();
List<HistoryItem> itemList = new ArrayList<>();
String selectQuery = "SELECT * FROM " + TABLE_HISTORY + " ORDER BY " + KEY_TIME_VISITED
@ -215,18 +198,15 @@ public class HistoryDatabase extends SQLiteOpenHelper { @@ -215,18 +198,15 @@ public class HistoryDatabase extends SQLiteOpenHelper {
} while (cursor.moveToNext());
}
cursor.close();
mLock = false;
return itemList;
}
public int getHistoryItemsCount() {
mLock = true;
public synchronized int getHistoryItemsCount() {
openIfNecessary();
String countQuery = "SELECT * FROM " + TABLE_HISTORY;
Cursor cursor = mDatabase.rawQuery(countQuery, null);
int n = cursor.getCount();
cursor.close();
mLock = false;
return n;
}
}

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

@ -1,8 +1,12 @@ @@ -1,8 +1,12 @@
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.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.ArrayAdapter;
@ -19,24 +23,33 @@ import javax.inject.Inject; @@ -19,24 +23,33 @@ 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.BookmarkPage;
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,13 +59,13 @@ public class BookmarksDialogBuilder { @@ -46,13 +59,13 @@ 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)) {
if (url.startsWith(Constants.FILE) && url.endsWith(BookmarkPage.FILENAME)) {
// TODO hacky, make a better bookmark mechanism in the future
final Uri uri = Uri.parse(url);
final String filename = uri.getLastPathSegment();
final String folderTitle = filename.substring(0, filename.length() - Constants.BOOKMARKS_FILENAME.length() - 1);
final String folderTitle = filename.substring(0, filename.length() - BookmarkPage.FILENAME.length() - 1);
item = new HistoryItem();
item.setIsFolder(true);
item.setTitle(folderTitle);
@ -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,100 @@ public class BookmarksDialogBuilder { @@ -197,4 +210,100 @@ 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:
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();
}
}

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

@ -3,15 +3,14 @@ @@ -3,15 +3,14 @@
*/
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;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
@ -19,13 +18,17 @@ import android.util.Log; @@ -19,13 +18,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 +47,13 @@ public class DownloadHandler { @@ -44,13 +47,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 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 +64,22 @@ public class DownloadHandler { @@ -61,18 +64,22 @@ 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,
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setComponent(null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
intent.setSelector(null);
}
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 +88,7 @@ public class DownloadHandler { @@ -81,8 +88,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 +125,17 @@ public class DownloadHandler { @@ -119,17 +125,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 +145,14 @@ public class DownloadHandler { @@ -139,14 +145,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 +168,7 @@ public class DownloadHandler { @@ -162,7 +168,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 +178,7 @@ public class DownloadHandler { @@ -172,7 +178,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 +186,7 @@ public class DownloadHandler { @@ -180,7 +186,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 +194,18 @@ public class DownloadHandler { @@ -188,18 +194,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 +225,9 @@ public class DownloadHandler { @@ -219,9 +225,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 +237,16 @@ public class DownloadHandler { @@ -231,15 +237,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));
}
}

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

@ -3,19 +3,23 @@ @@ -3,19 +3,23 @@
*/
package acr.browser.lightning.download;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.webkit.MimeTypeMap;
import android.webkit.URLUtil;
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.utils.Utils;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
/**
* This class is used to pull down the http headers of a given URL so that we
@ -27,7 +31,7 @@ import acr.browser.lightning.utils.Utils; @@ -27,7 +31,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 +41,9 @@ class FetchUrlMimeType extends Thread { @@ -37,9 +41,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 +54,7 @@ class FetchUrlMimeType extends Thread { @@ -50,6 +54,7 @@ class FetchUrlMimeType extends Thread {
public void run() {
// User agent is likely to be null, though the AndroidHttpClient
// seems ok with that.
final Bus eventBus = BrowserApp.getAppComponent().getBus();
String mimeType = null;
String contentDisposition = null;
HttpURLConnection connection = null;
@ -101,9 +106,16 @@ class FetchUrlMimeType extends Thread { @@ -101,9 +106,16 @@ 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);
Handler handler = new Handler(Looper.getMainLooper());
final String file = filename;
handler.post(new Runnable() {
@Override
public void run() {
eventBus.post(new BrowserEvents.ShowSnackBarMessage(mContext.getString(R.string.download_pending) + ' ' + file));
}
});
}
}

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

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
*/
package acr.browser.lightning.download;
import android.Manifest;
import android.app.Activity;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
@ -12,18 +13,25 @@ import android.webkit.URLUtil; @@ -12,18 +13,25 @@ import android.webkit.URLUtil;
import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants;
import com.anthonycr.grant.PermissionsManager;
import com.anthonycr.grant.PermissionsResultAction;
public class LightningDownloadListener implements DownloadListener {
private final Activity mActivity;
public LightningDownloadListener(Activity activity) {
mActivity = activity;
public LightningDownloadListener(Activity context) {
mActivity = context;
}
@Override
public void onDownloadStart(final String url, final String userAgent,
final String contentDisposition, final String mimetype, long contentLength) {
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(mActivity,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
new PermissionsResultAction() {
@Override
public void onGranted() {
String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
@Override
@ -48,6 +56,12 @@ public class LightningDownloadListener implements DownloadListener { @@ -48,6 +56,12 @@ public class LightningDownloadListener implements DownloadListener {
.setNegativeButton(mActivity.getResources().getString(R.string.action_cancel),
dialogClickListener).show();
Log.i(Constants.TAG, "Downloading" + fileName);
}
@Override
public void onDenied(String permission) {
//TODO show message
}
});
}
}

8
app/src/main/java/acr/browser/lightning/download/WebAddress.java

@ -35,11 +35,11 @@ class WebAddress { @@ -35,11 +35,11 @@ class WebAddress {
private static final int MATCH_GROUP_PORT = 4;
private static final int MATCH_GROUP_PATH = 5;
private static final Pattern sAddressPattern = Pattern.compile(
/* scheme */"(?:(http|https|file)\\:\\/\\/)?" +
/* authority */"(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?:\\:[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
/* scheme */"(?:(http|https|file)://)?" +
/* authority */"(?:([-A-Za-z0-9$_.+!*'(),;?&=]+(?::[-A-Za-z0-9$_.+!*'(),;?&=]+)?)@)?" +
/* host */"([" + GOOD_IRI_CHAR + "%_-][" + GOOD_IRI_CHAR + "%_\\.-]*|\\[[0-9a-fA-F:\\.]+\\])?" +
/* port */"(?:\\:([0-9]*))?" +
/* path */"(\\/?[^#]*)?" +
/* port */"(?::([0-9]*))?" +
/* path */"(/?[^#]*)?" +
/* anchor */".*", Pattern.CASE_INSENSITIVE);
/**

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]);
}

49
app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java

@ -15,6 +15,7 @@ import android.preference.PreferenceFragment; @@ -15,6 +15,7 @@ import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
@ -26,7 +27,8 @@ import acr.browser.lightning.app.BrowserApp; @@ -26,7 +27,8 @@ import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.database.BookmarkLocalSync;
import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.utils.PermissionsManager;
import com.anthonycr.grant.PermissionsManager;
import com.anthonycr.grant.PermissionsResultAction;
import acr.browser.lightning.utils.Utils;
public class BookmarkSettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener {
@ -45,9 +47,17 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @@ -45,9 +47,17 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private ImportBookmarksTask mImportTaskReference;
private static final File mPath = new File(Environment.getExternalStorageDirectory().toString());
private class ImportBookmarksTask extends AsyncTask<Void, Void, Integer> {
private final WeakReference<Activity> mActivityReference;
public ImportBookmarksTask(Activity activity) {
mActivityReference = new WeakReference<>(activity);
}
@Override
protected Integer doInBackground(Void... params) {
List<HistoryItem> list = null;
@ -67,10 +77,11 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @@ -67,10 +77,11 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
@Override
protected void onPostExecute(Integer num) {
super.onPostExecute(num);
if (mActivity != null) {
Activity activity = mActivityReference.get();
if (activity != null) {
int number = num;
final String message = mActivity.getResources().getString(R.string.message_import);
Utils.showSnackbar(mActivity, number + " " + message);
final String message = activity.getResources().getString(R.string.message_import);
Utils.showSnackbar(activity, number + " " + message);
}
}
}
@ -88,7 +99,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @@ -88,7 +99,7 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
PermissionsManager permissionsManager = PermissionsManager.getInstance();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
permissionsManager.requestPermissionsIfNecessary(getActivity(), REQUIRED_PERMISSIONS);
permissionsManager.requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS, null);
}
}
@ -96,6 +107,9 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @@ -96,6 +107,9 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
public void onDestroy() {
super.onDestroy();
mActivity = null;
if (mImportTaskReference != null) {
mImportTaskReference.cancel(false);
}
}
private void initPrefs() {
@ -124,18 +138,37 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref @@ -124,18 +138,37 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
public boolean onPreferenceClick(Preference preference) {
switch (preference.getKey()) {
case SETTINGS_EXPORT:
if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) {
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS,
new PermissionsResultAction() {
@Override
public void onGranted() {
mBookmarkManager.exportBookmarks(getActivity());
}
@Override
public void onDenied(String permission) {
//TODO Show message
}
});
return true;
case SETTINGS_IMPORT:
if (PermissionsManager.checkPermissions(getActivity(), REQUIRED_PERMISSIONS)) {
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(getActivity(), REQUIRED_PERMISSIONS,
new PermissionsResultAction() {
@Override
public void onGranted() {
loadFileList(null);
createDialog();
}
@Override
public void onDenied(String permission) {
//TODO Show message
}
});
return true;
case SETTINGS_IMPORT_BROWSER:
new ImportBookmarksTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
mImportTaskReference = new ImportBookmarksTask(getActivity());
mImportTaskReference.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return true;
default:
return false;

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

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
package acr.browser.lightning.fragment;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.os.Bundle;
@ -36,23 +36,31 @@ import java.util.List; @@ -36,23 +36,31 @@ import java.util.List;
import javax.inject.Inject;
import acr.browser.lightning.R;
import acr.browser.lightning.activity.BrowserActivity;
import acr.browser.lightning.activity.ReadingActivity;
import acr.browser.lightning.activity.TabsManager;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.async.AsyncExecutor;
import acr.browser.lightning.bus.BookmarkEvents;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.dialog.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;
import acr.browser.lightning.utils.UrlUtils;
import acr.browser.lightning.view.LightningView;
/**
* Created by Stefano Pacifici on 25/08/15. Based on Anthony C. Restaino's code.
*/
public class BookmarksFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
private final static String TAG = BookmarksFragment.class.getSimpleName();
public final static String INCOGNITO_MODE = TAG + ".INCOGNITO_MODE";
// Managers
@Inject
BookmarkManager mBookmarkManager;
@ -63,7 +71,13 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -63,7 +71,13 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
// Dialog builder
@Inject
BookmarksDialogBuilder mBookmarksDialogBuilder;
LightningDialogBuilder mBookmarksDialogBuilder;
@Inject
PreferenceManager mPreferenceManager;
@Inject
TabsManager mTabsManager;
// Adapter
private BookmarkViewAdapter mBookmarkAdapter;
@ -96,6 +110,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -96,6 +110,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();
boolean isIncognito = arguments.getBoolean(INCOGNITO_MODE, false);
boolean darkTheme = mPreferenceManager.getUseTheme() != 0 || isIncognito;
mWebpageBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_webpage, darkTheme);
mFolderBitmap = ThemeUtils.getThemedBitmap(context, R.drawable.ic_folder, darkTheme);
mIconColor = darkTheme ? ThemeUtils.getIconDarkThemeColor(context) :
ThemeUtils.getIconLightThemeColor(context);
}
// Handle bookmark click
@ -107,7 +129,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -107,7 +129,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 +157,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -135,6 +157,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() {
@ -148,26 +171,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -148,26 +171,14 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
}
});
setupNavigationButton(view, R.id.action_add_bookmark, R.id.icon_star);
setupNavigationButton(view, R.id.action_reading, R.id.icon_reading);
setupNavigationButton(view, R.id.action_toggle_desktop, R.id.icon_desktop);
// Must be called here, only here we have a reference to the ListView
new Thread(mInitBookmarkManager).run();
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();
@ -183,6 +194,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -183,6 +194,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
@Subscribe
public void addBookmark(final BrowserEvents.AddBookmark event) {
final HistoryItem item = new HistoryItem(event.url, event.title);
if (!UrlUtils.isSpecialUrl(item.getUrl())) {
if (mBookmarkManager.addBookmark(item)) {
mBookmarks.add(item);
Collections.sort(mBookmarks, new BookmarkManager.SortIgnoreCase());
@ -191,6 +203,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -191,6 +203,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
updateBookmarkIndicator(event.url);
}
}
}
@Subscribe
public void currentPageInfo(final BrowserEvents.CurrentPageUrl event) {
@ -295,7 +308,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -295,7 +308,7 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
if (item.isFolder()) {
mBookmarksDialogBuilder.showBookmarkFolderLongPressedDialog(getContext(), item);
} else {
mBookmarksDialogBuilder.showLongPressedDialogForUrl(getContext(), item);
mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(getContext(), item);
}
}
@ -305,6 +318,22 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener, @@ -305,6 +318,22 @@ public class BookmarksFragment extends Fragment implements View.OnClickListener,
case R.id.action_add_bookmark:
mEventBus.post(new BookmarkEvents.WantToBookmarkCurrentPage());
break;
case R.id.action_reading:
LightningView currentTab = mTabsManager.getCurrentTab();
if (currentTab != null) {
Intent read = new Intent(getActivity(), ReadingActivity.class);
read.putExtra(Constants.LOAD_READING_URL, currentTab.getUrl());
startActivity(read);
}
break;
case R.id.action_toggle_desktop:
LightningView current = mTabsManager.getCurrentTab();
if (current != null) {
current.toggleDesktopUA(getActivity());
current.reload();
// TODO add back drawer closing
}
break;
default:
break;
}

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();
}
}

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

@ -5,11 +5,11 @@ package acr.browser.lightning.fragment; @@ -5,11 +5,11 @@ package acr.browser.lightning.fragment;
import android.app.Activity;
import android.content.DialogInterface;
import android.os.Build;
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;
@ -23,12 +23,11 @@ import android.widget.LinearLayout; @@ -23,12 +23,11 @@ import android.widget.LinearLayout;
import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
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);
if (API >= Build.VERSION_CODES.KITKAT) {
mPreferenceManager.setFlashSupport(0);
}
setSearchEngineSummary(mPreferences.getSearchChoice());
setSearchEngineSummary(mPreferenceManager.getSearchChoice());
downloadloc.setSummary(mDownloadLocation);
@ -139,28 +134,27 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -139,28 +134,27 @@ 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();
// proxy.setEnabled(Constants.FULL_VERSION);
cbAds.setEnabled(Constants.FULL_VERSION);
cbFlash.setEnabled(API < 19);
cbFlash.setEnabled(API < Build.VERSION_CODES.KITKAT);
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),
@ -168,7 +162,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -168,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);
}
@ -185,7 +179,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -185,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),
@ -193,13 +187,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -193,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);
}
});
@ -210,7 +204,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -210,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
@ -235,7 +229,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -235,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]);
}
@ -253,8 +247,8 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -253,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)
@ -269,10 +263,10 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -269,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();
@ -286,13 +280,13 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -286,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);
}
});
@ -303,7 +297,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -303,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;
@ -321,15 +315,15 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -321,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:
@ -346,11 +340,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -346,11 +340,12 @@ 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 {
getHome.setText("http://www.google.com");
String defaultUrl = "http://www.google.com";
getHome.setText(defaultUrl);
}
homePicker.setView(getHome);
homePicker.setPositiveButton(getResources().getString(R.string.action_ok),
@ -358,7 +353,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -358,7 +353,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);
}
});
@ -368,7 +363,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -368,7 +363,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;
@ -382,7 +377,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -382,7 +377,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:
@ -398,12 +393,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -398,12 +393,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));
@ -435,7 +430,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -435,7 +430,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));
}
});
@ -449,12 +444,12 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -449,12 +444,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);
@ -464,7 +459,7 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -464,7 +459,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);
}
});
@ -533,44 +528,41 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe @@ -533,44 +528,41 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// switch preferences
boolean checked = false;
if (newValue instanceof Boolean) {
checked = (Boolean) newValue;
}
switch (preference.getKey()) {
case SETTINGS_FLASH:
if (cbFlash.isChecked()) {
if (!Utils.isFlashInstalled(mActivity) && checked) {
Utils.createInformativeDialog(mActivity, R.string.title_warning, R.string.dialog_adobe_not_installed);
mPreferenceManager.setFlashSupport(0);
return false;
} else {
if (checked) {
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);
}
cbFlash.setChecked((Boolean) newValue);
return true;
case SETTINGS_ADS:
mPreferences.setAdBlockEnabled((Boolean) newValue);
cbAds.setChecked((Boolean) newValue);
mPreferenceManager.setAdBlockEnabled(checked);
return true;
case SETTINGS_IMAGES:
mPreferences.setBlockImagesEnabled((Boolean) newValue);
cbImages.setChecked((Boolean) newValue);
mPreferenceManager.setBlockImagesEnabled(checked);
return true;
case SETTINGS_JAVASCRIPT:
mPreferences.setJavaScriptEnabled((Boolean) newValue);
cbJsScript.setChecked((Boolean) newValue);
mPreferenceManager.setJavaScriptEnabled(checked);
return true;
case SETTINGS_COLORMODE:
mPreferences.setColorModeEnabled((Boolean) newValue);
cbColorMode.setChecked((Boolean) newValue);
mPreferenceManager.setColorModeEnabled(checked);
return true;
case SETTINGS_GOOGLESUGGESTIONS:
mPreferences.setGoogleSearchSuggestionsEnabled((Boolean) newValue);
cbgooglesuggest.setChecked((Boolean) newValue);
mPreferenceManager.setGoogleSearchSuggestionsEnabled(checked);
return true;
case SETTINGS_DRAWERTABS:
mPreferences.setShowTabsInDrawer((Boolean) newValue);
cbDrawerTabs.setChecked((Boolean) newValue);
mPreferenceManager.setShowTabsInDrawer(checked);
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);
}
}

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

@ -11,16 +11,15 @@ import android.os.Handler; @@ -11,16 +11,15 @@ 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;
import acr.browser.lightning.view.LightningView;
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";
@ -33,11 +32,10 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -33,11 +32,10 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
private static final String SETTINGS_CLEARCOOKIES = "clear_cookies";
private static final String SETTINGS_CLEARWEBSTORAGE = "clear_webstorage";
private static final String SETTINGS_WEBSTORAGEEXIT = "clear_webstorage_exit";
private static final String SETTINGS_DONOTTRACK = "do_not_track";
private static final String SETTINGS_IDENTIFYINGHEADERS = "remove_identifying_headers";
private Activity mActivity;
private PreferenceManager mPreferences;
private CheckBoxPreference cblocation, cb3cookies, cbsavepasswords, cbcacheexit, cbhistoryexit,
cbcookiesexit, cbwebstorageexit;
private Handler messageHandler;
@Override
@ -52,21 +50,20 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -52,21 +50,20 @@ 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);
Preference clearwebstorage = findPreference(SETTINGS_CLEARWEBSTORAGE);
cblocation = (CheckBoxPreference) findPreference(SETTINGS_LOCATION);
cb3cookies = (CheckBoxPreference) findPreference(SETTINGS_THIRDPCOOKIES);
cbsavepasswords = (CheckBoxPreference) findPreference(SETTINGS_SAVEPASSWORD);
cbcacheexit = (CheckBoxPreference) findPreference(SETTINGS_CACHEEXIT);
cbhistoryexit = (CheckBoxPreference) findPreference(SETTINGS_HISTORYEXIT);
cbcookiesexit = (CheckBoxPreference) findPreference(SETTINGS_COOKIEEXIT);
cbwebstorageexit = (CheckBoxPreference) findPreference(SETTINGS_WEBSTORAGEEXIT);
CheckBoxPreference cblocation = (CheckBoxPreference) findPreference(SETTINGS_LOCATION);
CheckBoxPreference cb3cookies = (CheckBoxPreference) findPreference(SETTINGS_THIRDPCOOKIES);
CheckBoxPreference cbsavepasswords = (CheckBoxPreference) findPreference(SETTINGS_SAVEPASSWORD);
CheckBoxPreference cbcacheexit = (CheckBoxPreference) findPreference(SETTINGS_CACHEEXIT);
CheckBoxPreference cbhistoryexit = (CheckBoxPreference) findPreference(SETTINGS_HISTORYEXIT);
CheckBoxPreference cbcookiesexit = (CheckBoxPreference) findPreference(SETTINGS_COOKIEEXIT);
CheckBoxPreference cbwebstorageexit = (CheckBoxPreference) findPreference(SETTINGS_WEBSTORAGEEXIT);
CheckBoxPreference cbDoNotTrack = (CheckBoxPreference) findPreference(SETTINGS_DONOTTRACK);
CheckBoxPreference cbIdentifyingHeaders = (CheckBoxPreference) findPreference(SETTINGS_IDENTIFYINGHEADERS);
clearcache.setOnPreferenceClickListener(this);
clearhistory.setOnPreferenceClickListener(this);
@ -80,14 +77,21 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -80,14 +77,21 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
cbhistoryexit.setOnPreferenceChangeListener(this);
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());
cbDoNotTrack.setOnPreferenceChangeListener(this);
cbIdentifyingHeaders.setOnPreferenceChangeListener(this);
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());
cbDoNotTrack.setChecked(mPreferenceManager.getDoNotTrackEnabled());
cbIdentifyingHeaders.setChecked(mPreferenceManager.getRemoveIdentifyingHeadersEnabled());
String identifyingHeadersSummary = LightningView.HEADER_REQUESTED_WITH + ", " + LightningView.HEADER_WAP_PROFILE;
cbIdentifyingHeaders.setSummary(identifyingHeadersSummary);
cb3cookies.setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
@ -200,35 +204,33 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe @@ -200,35 +204,33 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// switch preferences
switch (preference.getKey()) {
case SETTINGS_LOCATION:
mPreferences.setLocationEnabled((Boolean) newValue);
cblocation.setChecked((Boolean) newValue);
mPreferenceManager.setLocationEnabled((Boolean) newValue);
return true;
case SETTINGS_THIRDPCOOKIES:
mPreferences.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
cb3cookies.setChecked((Boolean) newValue);
mPreferenceManager.setBlockThirdPartyCookiesEnabled((Boolean) newValue);
return true;
case SETTINGS_SAVEPASSWORD:
mPreferences.setSavePasswordsEnabled((Boolean) newValue);
cbsavepasswords.setChecked((Boolean) newValue);
mPreferenceManager.setSavePasswordsEnabled((Boolean) newValue);
return true;
case SETTINGS_CACHEEXIT:
mPreferences.setClearCacheExit((Boolean) newValue);
cbcacheexit.setChecked((Boolean) newValue);
mPreferenceManager.setClearCacheExit((Boolean) newValue);
return true;
case SETTINGS_HISTORYEXIT:
mPreferences.setClearHistoryExitEnabled((Boolean) newValue);
cbhistoryexit.setChecked((Boolean) newValue);
mPreferenceManager.setClearHistoryExitEnabled((Boolean) newValue);
return true;
case SETTINGS_COOKIEEXIT:
mPreferences.setClearCookiesExitEnabled((Boolean) newValue);
cbcookiesexit.setChecked((Boolean) newValue);
mPreferenceManager.setClearCookiesExitEnabled((Boolean) newValue);
return true;
case SETTINGS_WEBSTORAGEEXIT:
mPreferences.setClearWebStorageExitEnabled((Boolean) newValue);
cbwebstorageexit.setChecked((Boolean) newValue);
mPreferenceManager.setClearWebStorageExitEnabled((Boolean) newValue);
return true;
case SETTINGS_DONOTTRACK:
mPreferenceManager.setDoNotTrackEnabled((Boolean) newValue);
return true;
case SETTINGS_IDENTIFYINGHEADERS:
mPreferenceManager.setRemoveIdentifyingHeadersEnabled((Boolean) newValue);
return true;
default:
return false;

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

@ -0,0 +1,359 @@ @@ -0,0 +1,359 @@
package acr.browser.lightning.fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.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.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import 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.controller.UIController;
import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ThemeUtils;
import acr.browser.lightning.utils.Utils;
import acr.browser.lightning.view.LightningView;
/**
* A fragment that holds and manages the tabs and interaction with the tabs.
* It is reliant on the BrowserController in order to get the current UI state
* of the browser. It also uses the BrowserController to signal that the UI needs
* to change. This class contains the adapter used by both the drawer tabs and
* the desktop tabs. It delegates touch events for the tab UI appropriately.
*/
public class TabsFragment extends Fragment implements View.OnClickListener, View.OnLongClickListener {
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 RecyclerView mRecyclerView;
private LightningViewAdapter mTabsAdapter;
private UIController mUiController;
@Inject
TabsManager tabsManager;
@Inject
Bus mBus;
@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();
mUiController = (UIController) getActivity();
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 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.tab_header_button, R.id.plusIcon);
setupFrameLayoutButton(view, R.id.new_tab_button, R.id.icon_plus);
setupFrameLayoutButton(view, R.id.action_back, R.id.icon_back);
setupFrameLayoutButton(view, R.id.action_forward, R.id.icon_forward);
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();
mBus.register(this);
}
@Override
public void onResume() {
super.onResume();
// Force adapter refresh
mTabsAdapter.notifyDataSetChanged();
}
@Override
public void onStop() {
super.onStop();
mBus.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:
mBus.post(new TabEvents.NewTab());
break;
case R.id.action_back:
mBus.post(new NavigationEvents.GoBack());
break;
case R.id.action_forward:
mBus.post(new NavigationEvents.GoForward());
break;
case R.id.action_home:
mBus.post(new NavigationEvents.GoHome());
default:
break;
}
}
@Override
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.action_new_tab:
mBus.post(new TabEvents.NewTabLongPress());
break;
default:
break;
}
return true;
}
public class LightningViewAdapter extends RecyclerView.Adapter<LightningViewAdapter.LightningViewHolder> {
private final int mLayoutResourceId;
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 mDrawerTabs;
public LightningViewAdapter(final boolean vertical) {
this.mLayoutResourceId = vertical ? R.layout.tab_list_item : R.layout.tab_list_item_horizontal;
this.mDrawerTabs = 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(mLayoutResourceId, 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);
if (web == null) {
return;
}
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 (!mDrawerTabs) {
foregroundDrawable = new BitmapDrawable(getResources(), mForegroundTabBitmap);
if (!mIsIncognito && mColorMode) {
foregroundDrawable.setColorFilter(mUiController.getUiColor(), 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) {
mUiController.changeToolbarBackground(favicon, foregroundDrawable);
}
holder.favicon.setImageBitmap(favicon);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
holder.txtTitle.setTextAppearance(R.style.normalText);
} else {
holder.txtTitle.setTextAppearance(getContext(), R.style.normalText);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.layout.setBackground(mBackgroundTabDrawable);
} else {
holder.layout.setBackgroundDrawable(mBackgroundTabDrawable);
}
holder.favicon.setImageBitmap(getDesaturatedBitmap(favicon));
}
}
@Override
public int getItemCount() {
return tabsManager.size();
}
public Bitmap getDesaturatedBitmap(Bitmap favicon) {
Bitmap grayscaleBitmap = Bitmap.createBitmap(favicon.getWidth(),
favicon.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(grayscaleBitmap);
if (mColorMatrix == null || mFilter == null || mPaint == null) {
mPaint = new Paint();
mColorMatrix = new ColorMatrix();
mColorMatrix.setSaturation(DESATURATED);
mFilter = new ColorMatrixColorFilter(mColorMatrix);
mPaint.setColorFilter(mFilter);
}
c.drawBitmap(favicon, 0, 0, mPaint);
return grayscaleBitmap;
}
public class LightningViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
public LightningViewHolder(View view) {
super(view);
txtTitle = (TextView) view.findViewById(R.id.textTab);
favicon = (ImageView) view.findViewById(R.id.faviconTab);
exit = (ImageView) view.findViewById(R.id.deleteButton);
layout = (LinearLayout) view.findViewById(R.id.tab_item_background);
exitButton = (FrameLayout) view.findViewById(R.id.deleteAction);
exit.setColorFilter(mIconColor, PorterDuff.Mode.SRC_IN);
exitButton.setOnClickListener(this);
layout.setOnClickListener(this);
layout.setOnLongClickListener(this);
}
final TextView txtTitle;
final ImageView favicon;
final ImageView exit;
final FrameLayout exitButton;
final LinearLayout layout;
@Override
public void onClick(View v) {
if (v == exitButton) {
// Close tab
mBus.post(new TabEvents.CloseTab(getAdapterPosition()));
}
if (v == layout) {
mBus.post(new TabEvents.ShowTab(getAdapterPosition()));
}
}
@Override
public boolean onLongClick(View v) {
// Show close dialog
mBus.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);
}
}

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

@ -56,16 +56,14 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -56,16 +56,14 @@ 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 String DEFAULT_LANGUAGE = "en";
private static final long INTERVAL_DAY = 86400000;
private static final int MAX_SUGGESTIONS = 5;
private static final SuggestionsComparator mComparator = new SuggestionsComparator();
@ -75,11 +73,19 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -75,11 +73,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 +120,12 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -114,13 +120,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 +249,10 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -244,13 +249,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();
@ -373,9 +375,13 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -373,9 +375,13 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
}
InputStream in = null;
FileOutputStream fos = null;
String language = Locale.getDefault().getLanguage();
if (language.isEmpty()) {
language = DEFAULT_LANGUAGE;
}
try {
URL url = new URL("http://google.com/complete/search?q=" + query
+ "&output=toolbar&hl=en");
+ "&output=toolbar&hl=" + language);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
@ -413,7 +419,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable { @@ -413,7 +419,7 @@ public class SearchAdapter extends BaseAdapter implements Filterable {
return connectivity.getActiveNetworkInfo();
}
private List<HistoryItem> getFilteredList() {
private synchronized List<HistoryItem> getFilteredList() {
List<HistoryItem> list = new ArrayList<>(5);
synchronized (mBookmarks) {
synchronized (mHistory) {

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

@ -1,11 +1,15 @@ @@ -1,11 +1,15 @@
package acr.browser.lightning.preference;
import android.content.Context;
import android.content.SharedPreferences;
import acr.browser.lightning.app.BrowserApp;
import javax.inject.Inject;
import javax.inject.Singleton;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
@Singleton
public class PreferenceManager {
private static class Name {
@ -47,6 +51,8 @@ public class PreferenceManager { @@ -47,6 +51,8 @@ public class PreferenceManager {
public static final String TEXT_ENCODING = "textEncoding";
public static final String CLEAR_WEBSTORAGE_EXIT = "clearWebStorageExit";
public static final String SHOW_TABS_IN_DRAWER = "showTabsInDrawer";
public static final String DO_NOT_TRACK = "doNotTrack";
public static final String IDENTIFYING_HEADERS = "removeIdentifyingHeaders";
public static final String USE_PROXY = "useProxy";
public static final String PROXY_CHOICE = "proxyChoice";
@ -56,20 +62,13 @@ public class PreferenceManager { @@ -56,20 +62,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() {
@ -248,6 +247,14 @@ public class PreferenceManager { @@ -248,6 +247,14 @@ public class PreferenceManager {
return mPrefs.getBoolean(Name.SHOW_TABS_IN_DRAWER, defaultValue);
}
public boolean getDoNotTrackEnabled() {
return mPrefs.getBoolean(Name.DO_NOT_TRACK, false);
}
public boolean getRemoveIdentifyingHeadersEnabled(){
return mPrefs.getBoolean(Name.IDENTIFYING_HEADERS, false);
}
private void putBoolean(String name, boolean value) {
mPrefs.edit().putBoolean(name, value).apply();
}
@ -260,6 +267,14 @@ public class PreferenceManager { @@ -260,6 +267,14 @@ public class PreferenceManager {
mPrefs.edit().putString(name, value).apply();
}
public void setRemoveIdentifyingHeadersEnabled(boolean enabled){
putBoolean(Name.IDENTIFYING_HEADERS, enabled);
}
public void setDoNotTrackEnabled(boolean doNotTrack) {
putBoolean(Name.DO_NOT_TRACK, doNotTrack);
}
public void setShowTabsInDrawer(boolean show) {
putBoolean(Name.SHOW_TABS_IN_DRAWER, show);
}

3
app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java

@ -491,8 +491,7 @@ public class ArticleTextExtractor { @@ -491,8 +491,7 @@ public class ArticleTextExtractor {
Element el = elems.get(0);
if (el.hasAttr("content")) {
dateStr = el.attr("content");
Date parsedDate = parseDate(dateStr);
return parsedDate;
return parseDate(dateStr);
}
}

16
app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java

@ -33,6 +33,8 @@ import java.util.zip.GZIPInputStream; @@ -33,6 +33,8 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import acr.browser.lightning.utils.Utils;
/**
* Class to fetch articles. This class is thread safe.
*
@ -49,7 +51,11 @@ public class HtmlFetcher { @@ -49,7 +51,11 @@ public class HtmlFetcher {
}
public static void main(String[] args) throws Exception {
BufferedReader reader = new BufferedReader(new FileReader("urls.txt"));
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader("urls.txt"));
String line;
Set<String> existing = new LinkedHashSet<>();
while ((line = reader.readLine()) != null) {
@ -66,11 +72,13 @@ public class HtmlFetcher { @@ -66,11 +72,13 @@ public class HtmlFetcher {
String html = new HtmlFetcher().fetchAsString(url, 2000);
String outFile = domainStr + counterStr + ".html";
BufferedWriter writer = new BufferedWriter(new FileWriter(outFile));
writer = new BufferedWriter(new FileWriter(outFile));
writer.write(html);
writer.close();
}
reader.close();
} finally {
Utils.close(reader);
Utils.close(writer);
}
}
private String referrer = "http://jetsli.de/crawler";

2
app/src/main/java/acr/browser/lightning/reading/OutputFormatter.java

@ -23,7 +23,7 @@ public class OutputFormatter { @@ -23,7 +23,7 @@ public class OutputFormatter {
private static final int MIN_FIRST_PARAGRAPH_TEXT = 50; // Min size of first paragraph
private static final int MIN_PARAGRAPH_TEXT = 30; // Min size of any other paragraphs
private static final List<String> NODES_TO_REPLACE = Arrays.asList("strong", "b", "i");
private Pattern unlikelyPattern = Pattern.compile("display\\:none|visibility\\:hidden");
private Pattern unlikelyPattern = Pattern.compile("display:none|visibility:hidden");
private final int minFirstParagraphText;
private final int minParagraphText;
private final List<String> nodesToReplace;

2
app/src/main/java/acr/browser/lightning/reading/SHelper.java

@ -253,7 +253,7 @@ class SHelper { @@ -253,7 +253,7 @@ class SHelper {
public static String getUrlFromUglyGoogleRedirect(String url) {
if (url.startsWith("http://www.google.com/url?")) {
url = url.substring("http://www.google.com/url?".length());
String arr[] = urlDecode(url).split("\\&");
String arr[] = urlDecode(url).split("&");
for (String str : arr) {
if (str.startsWith("q="))
return str.substring("q=".length());

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

@ -13,8 +13,8 @@ import java.util.HashSet; @@ -13,8 +13,8 @@ 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;
public class AdBlock {
@ -44,11 +44,11 @@ public class AdBlock { @@ -44,11 +44,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) {

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

@ -7,6 +7,7 @@ import android.content.IntentFilter; @@ -7,6 +7,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.webkit.WebView;
@ -23,7 +24,7 @@ public class IntentUtils { @@ -23,7 +24,7 @@ public class IntentUtils {
+ // switch on case insensitive matching
'('
+ // begin group for schema
"(?:http|https|file):\\/\\/" + "|(?:inline|data|about|javascript):" + "|(?:.*:.*@)"
"(?:http|https|file)://" + "|(?:inline|data|about|javascript):" + "|(?:.*:.*@)"
+ ')' + "(.*)");
public IntentUtils(Activity activity) {
@ -39,6 +40,12 @@ public class IntentUtils { @@ -39,6 +40,12 @@ public class IntentUtils {
return false;
}
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setComponent(null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
intent.setSelector(null);
}
if (mActivity.getPackageManager().resolveActivity(intent, 0) == null) {
String packagename = intent.getPackage();
if (packagename != null) {
@ -51,8 +58,6 @@ public class IntentUtils { @@ -51,8 +58,6 @@ public class IntentUtils {
return false;
}
}
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setComponent(null);
if (tab != null) {
intent.putExtra(mActivity.getPackageName() + ".Origin", 1);
}

75
app/src/main/java/acr/browser/lightning/utils/PermissionsManager.java

@ -1,75 +0,0 @@ @@ -1,75 +0,0 @@
package acr.browser.lightning.utils;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Copyright 8/22/2015 Anthony Restaino
*/
public class PermissionsManager {
private static PermissionsManager mInstance;
private final Set<String> mPendingRequests = new HashSet<>();
public static PermissionsManager getInstance() {
if (mInstance == null) {
mInstance = new PermissionsManager();
}
return mInstance;
}
public void requestPermissionsIfNecessary(Activity activity, @NonNull String[] permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || activity == null) {
return;
}
List<String> permList = new ArrayList<>();
for (String perm : permissions) {
if (activity.checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED
&& !mPendingRequests.contains(perm)) {
permList.add(perm);
}
}
if (!permList.isEmpty()) {
String[] permsToRequest = permList.toArray(new String[permList.size()]);
mPendingRequests.addAll(permList);
activity.requestPermissions(permsToRequest, 1);
}
}
public static boolean checkPermission(Activity activity, @NonNull String permission) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
} else if (activity == null) {
return false;
}
return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
}
public static boolean checkPermissions(Activity activity, @NonNull String[] permissions) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
} else if (activity == null) {
return false;
}
boolean permissionsNecessary = true;
for (String perm : permissions) {
permissionsNecessary &= activity.checkSelfPermission(perm) == PackageManager.PERMISSION_GRANTED;
}
return permissionsNecessary;
}
public void notifyPermissionsChange(String[] permissions) {
for (String perm : permissions) {
mPendingRequests.remove(perm);
}
}
}

17
app/src/main/java/acr/browser/lightning/utils/UrlUtils.java

@ -21,6 +21,11 @@ import android.webkit.URLUtil; @@ -21,6 +21,11 @@ import android.webkit.URLUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import acr.browser.lightning.constant.BookmarkPage;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.constant.HistoryPage;
import acr.browser.lightning.constant.StartPage;
/**
* Utility methods for Url manipulation
*/
@ -28,7 +33,7 @@ public class UrlUtils { @@ -28,7 +33,7 @@ public class UrlUtils {
private static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile(
"(?i)" + // switch on case insensitive matching
'(' + // begin group for schema
"(?:http|https|file):\\/\\/" +
"(?:http|https|file)://" +
"|(?:inline|data|about|javascript):" +
"|(?:.*:.*@)" +
')' +
@ -145,4 +150,14 @@ public class UrlUtils { @@ -145,4 +150,14 @@ public class UrlUtils {
}
return inUrl;
}
/**
* Returns whether the given url is the bookmarks/history page or a normal website
*/
public static boolean isSpecialUrl(String url) {
return url != null && url.startsWith(Constants.FILE) &&
(url.endsWith(BookmarkPage.FILENAME) ||
url.endsWith(HistoryPage.FILENAME) ||
url.endsWith(StartPage.FILENAME));
}
}

15
app/src/main/java/acr/browser/lightning/utils/Utils.java

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
*/
package acr.browser.lightning.utils;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
@ -39,17 +40,31 @@ import java.util.Date; @@ -39,17 +40,31 @@ import java.util.Date;
import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
import com.anthonycr.grant.PermissionsManager;
import com.anthonycr.grant.PermissionsResultAction;
public final class Utils {
public static void downloadFile(final Activity activity, final String url,
final String userAgent, final String contentDisposition) {
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, new PermissionsResultAction() {
@Override
public void onGranted() {
String fileName = URLUtil.guessFileName(url, null, null);
DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null
);
Log.i(Constants.TAG, "Downloading" + fileName);
}
@Override
public void onDenied(String permission) {
// TODO Show Message
}
});
}
public static Intent newEmailIntent(String address, String subject,
String body, String cc) {
Intent intent = new Intent(Intent.ACTION_SEND);

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

@ -10,7 +10,7 @@ import android.webkit.WebStorage; @@ -10,7 +10,7 @@ import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
import acr.browser.lightning.database.HistoryDatabase;
import acr.browser.lightning.app.BrowserApp;
/**
* Copyright 8/4/2015 Anthony Restaino
@ -34,7 +34,7 @@ public class WebUtils { @@ -34,7 +34,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);
}
}
}

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

@ -0,0 +1,233 @@ @@ -0,0 +1,233 @@
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.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.controller.UIController;
import com.anthonycr.grant.PermissionsManager;
import com.anthonycr.grant.PermissionsResultAction;
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 Activity mActivity;
private final LightningView mLightningView;
private final UIController mUIController;
private final Bus eventBus;
LightningChromeClient(Activity activity, LightningView lightningView) {
mActivity = activity;
mUIController = (UIController) activity;
mLightningView = lightningView;
eventBus = BrowserApp.getAppComponent().getBus();
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (mLightningView.isShown()) {
mUIController.updateProgress(newProgress);
}
}
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
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 static 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) {
mUIController.updateHistory(title, view.getUrl());
}
}
@Override
public void onGeolocationPermissionsShowPrompt(final String origin,
final GeolocationPermissions.Callback callback) {
PermissionsManager.getInstance().requestPermissionsIfNecessaryForResult(mActivity, PERMISSIONS, new PermissionsResultAction() {
@Override
public void onGranted() {
final boolean remember = true;
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(mActivity.getString(R.string.location));
String org;
if (origin.length() > 50) {
org = origin.subSequence(0, 50) + "...";
} else {
org = origin;
}
builder.setMessage(org + mActivity.getString(R.string.message_location))
.setCancelable(true)
.setPositiveButton(mActivity.getString(R.string.action_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, true, remember);
}
})
.setNegativeButton(mActivity.getString(R.string.action_dont_allow),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
callback.invoke(origin, false, remember);
}
});
AlertDialog alert = builder.create();
alert.show();
}
@Override
public void onDenied(String permission) {
//TODO show message and/or turn off setting
}
});
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture,
Message resultMsg) {
mUIController.onCreateWindow(resultMsg);
return true;
}
@Override
public void onCloseWindow(WebView window) {
mUIController.onCloseWindow(mLightningView);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUIController.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUIController.openFileChooser(uploadMsg);
}
@SuppressWarnings("unused")
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUIController.openFileChooser(uploadMsg);
}
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
mUIController.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() {
if (mActivity == null) {
return null;
}
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() {
mUIController.onHideCustomView();
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
mUIController.onShowCustomView(view, callback);
}
@SuppressWarnings("deprecation")
@Override
public void onShowCustomView(View view, int requestedOrientation,
CustomViewCallback callback) {
mUIController.onShowCustomView(view, callback, requestedOrientation);
}
}

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

@ -4,28 +4,21 @@ @@ -4,28 +4,21 @@
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.support.v4.util.ArrayMap;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
@ -34,58 +27,53 @@ import android.view.View; @@ -34,58 +27,53 @@ 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 java.lang.ref.WeakReference;
import java.util.Map;
import javax.inject.Inject;
import acr.browser.lightning.R;
import acr.browser.lightning.app.BrowserApp;
import acr.browser.lightning.bus.BrowserEvents;
import acr.browser.lightning.constant.BookmarkPage;
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.controller.UIController;
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.UrlUtils;
import acr.browser.lightning.utils.Utils;
public class LightningView {
private final Title mTitle;
public static final String HEADER_REQUESTED_WITH = "X-Requested-With";
public static final String HEADER_WAP_PROFILE = "X-Wap-Profile";
public static final String HEADER_DNT = "DNT";
final LightningViewTitle mTitle;
private WebView mWebView;
private final boolean mIsIncognitoTab;
private final BrowserController mBrowserController;
final boolean mIsIncognitoTab;
private final UIController mUIController;
private final GestureDetector mGestureDetector;
private final Activity mActivity;
private static String mHomepage;
private static String mDefaultUserAgent;
// TODO fix so that mWebpageBitmap can be static - static changes the icon when switching from light to dark and then back to light
private final Bitmap mWebpageBitmap;
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;
@ -97,26 +85,29 @@ public class LightningView { @@ -97,26 +85,29 @@ public class LightningView {
0, 0, -1.0f, 0, 255, // blue
0, 0, 0, 1.0f, 0 // alpha
};
private final PermissionsManager mPermissionsManager;
private static final String[] PERMISSIONS = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
private final WebViewHandler mWebViewHandler = new WebViewHandler(this);
private final Map<String, String> mRequestHeaders = new ArrayMap<>();
@SuppressLint("NewApi")
public LightningView(Activity activity, String url, boolean darkTheme, boolean isIncognito, BrowserController controller) {
@Inject
Bus mEventBus;
@Inject
PreferenceManager mPreferences;
@Inject
LightningDialogBuilder mBookmarksDialogBuilder;
@SuppressLint("NewApi")
public LightningView(Activity activity, String url, boolean isIncognito) {
BrowserApp.getAppComponent().inject(this);
mActivity = activity;
mUIController = (UIController) activity;
mWebView = new WebView(activity);
mIsIncognitoTab = isIncognito;
mTitle = new Title(activity, darkTheme);
mAdBlock = AdBlock.getInstance(activity.getApplicationContext());
mPermissionsManager = PermissionsManager.getInstance();
mWebpageBitmap = mTitle.mDefaultIcon;
mTitle = new LightningViewTitle(activity, mUIController.getUseDarkTheme());
mMaxFling = ViewConfiguration.get(activity).getScaledMaximumFlingVelocity();
mBrowserController = controller;
mIntentUtils = new IntentUtils(mActivity);
mWebView.setDrawingCacheBackgroundColor(Color.WHITE);
mWebView.setFocusableInTouchMode(true);
mWebView.setFocusable(true);
@ -133,8 +124,8 @@ public class LightningView { @@ -133,8 +124,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());
@ -144,7 +135,7 @@ public class LightningView { @@ -144,7 +135,7 @@ public class LightningView {
if (url != null) {
if (!url.trim().isEmpty()) {
mWebView.loadUrl(url);
mWebView.loadUrl(url, mRequestHeaders);
} else {
// don't load anything, the user is looking for a blank tab
}
@ -158,12 +149,37 @@ public class LightningView { @@ -158,12 +149,37 @@ public class LightningView {
return;
}
if (mHomepage.startsWith("about:home")) {
mWebView.loadUrl(StartPage.getHomepage(mActivity));
mWebView.loadUrl(StartPage.getHomepage(mActivity), mRequestHeaders);
} else if (mHomepage.startsWith("about:bookmarks")) {
mBrowserController.openBookmarkPage(mWebView);
loadBookmarkpage();
} else {
mWebView.loadUrl(mHomepage);
mWebView.loadUrl(mHomepage, mRequestHeaders);
}
}
/**
* 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(), BookmarkPage.FILENAME);
BrowserApp.getAppComponent().getBookmarkPage().buildBookmarkPage(null);
mWebView.loadUrl(Constants.FILE + bookmarkWebPage, mRequestHeaders);
}
/**
@ -173,26 +189,34 @@ public class LightningView { @@ -173,26 +189,34 @@ public class LightningView {
* if you don't have a reference to them
* @param context the context in which the WebView was created
*/
@SuppressLint("NewApi")
@SuppressLint({"NewApi", "SetJavaScriptEnabled"})
public synchronized void initializePreferences(@Nullable WebSettings settings, Context context) {
if (settings == null && mWebView == null) {
return;
} else if (settings == null) {
settings = mWebView.getSettings();
}
mPreferences = PreferenceManager.getInstance();
if (mPreferences.getDoNotTrackEnabled()) {
mRequestHeaders.put(HEADER_DNT, "1");
} else {
mRequestHeaders.remove(HEADER_DNT);
}
if (mPreferences.getRemoveIdentifyingHeadersEnabled()) {
mRequestHeaders.put(HEADER_REQUESTED_WITH, "");
mRequestHeaders.put(HEADER_WAP_PROFILE, "");
} else {
mRequestHeaders.remove(HEADER_REQUESTED_WITH);
mRequestHeaders.remove(HEADER_WAP_PROFILE);
}
settings.setDefaultTextEncodingName(mPreferences.getTextEncoding());
mHomepage = mPreferences.getHomepage();
mAdBlock.updatePreference();
setColorMode(mPreferences.getRenderingMode());
if (!mIsIncognitoTab) {
settings.setGeolocationEnabled(mPreferences.getLocationEnabled());
if (mPreferences.getLocationEnabled() && !PermissionsManager.checkPermissions(mActivity, PERMISSIONS)) {
mPermissionsManager.requestPermissionsIfNecessary(mActivity, PERMISSIONS);
}
} else {
settings.setGeolocationEnabled(false);
}
@ -240,7 +264,6 @@ public class LightningView { @@ -240,7 +264,6 @@ public class LightningView {
}
if (mPreferences.getTextReflowEnabled()) {
mTextReflow = true;
settings.setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
if (API >= android.os.Build.VERSION_CODES.KITKAT) {
try {
@ -252,7 +275,6 @@ public class LightningView { @@ -252,7 +275,6 @@ public class LightningView {
}
}
} else {
mTextReflow = false;
settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
}
@ -383,6 +405,11 @@ public class LightningView { @@ -383,6 +405,11 @@ public class LightningView {
}
}
@NonNull
protected Map<String, String> getRequestHeaders() {
return mRequestHeaders;
}
public boolean isShown() {
return mWebView != null && mWebView.isShown();
}
@ -406,7 +433,7 @@ public class LightningView { @@ -406,7 +433,7 @@ public class LightningView {
public void setForegroundTab(boolean isForeground) {
isForegroundTab = isForeground;
mBrowserController.updateTabs();
mEventBus.post(new BrowserEvents.TabsChanged());
}
public boolean isForegroundTab() {
@ -509,7 +536,7 @@ public class LightningView { @@ -509,7 +536,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;
}
@ -521,6 +548,7 @@ public class LightningView { @@ -521,6 +548,7 @@ public class LightningView {
/**
* Naive caching of the favicon according to the domain name of the URL
*
* @param icon the icon to cache
*/
private void cacheFavicon(final Bitmap icon) {
@ -552,7 +580,10 @@ public class LightningView { @@ -552,7 +580,10 @@ public class LightningView {
mWebView.setVisibility(View.GONE);
mWebView.removeAllViews();
mWebView.destroyDrawingCache();
// mWebView.destroy(); //this is causing the segfault
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
//this is causing the segfault occasionally below 4.2
mWebView.destroy();
}
mWebView = null;
}
}
@ -563,7 +594,7 @@ public class LightningView { @@ -563,7 +594,7 @@ public class LightningView {
}
}
public String getUserAgent() {
private String getUserAgent() {
if (mWebView != null) {
return mWebView.getSettings().getUserAgentString();
} else {
@ -577,510 +608,118 @@ public class LightningView { @@ -577,510 +608,118 @@ public class LightningView {
}
}
public boolean canGoBack() {
return mWebView != null && mWebView.canGoBack();
}
public boolean canGoForward() {
return mWebView != null && mWebView.canGoForward();
}
@Nullable
public WebView getWebView() {
return mWebView;
}
public Bitmap getFavicon() {
return mTitle.getFavicon();
}
public synchronized void loadUrl(String url) {
// Check if configured proxy is available
if (mBrowserController.proxyIsNotReady()) {
// User has been notified
return;
}
public synchronized void findNext() {
if (mWebView != null) {
mWebView.loadUrl(url);
mWebView.findNext(true);
}
}
public String getTitle() {
return mTitle.getTitle();
}
@NonNull
public String getUrl() {
if (mWebView != null && mWebView.getUrl() != null) {
return mWebView.getUrl();
} else {
return "";
}
public synchronized void findPrevious() {
if (mWebView != null) {
mWebView.findNext(false);
}
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 synchronized void clearFindMatches() {
if (mWebView != null) {
mWebView.clearMatches();
}
}
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);
/**
* Used by {@link LightningWebClient}
*
* @return true if the page is in inverted mode, false otherwise
*/
public boolean getInvertePage() {
return mInvertPage;
}
@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);
/**
* 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 && UrlUtils.isSpecialUrl(currentUrl)) {
if (currentUrl.endsWith(HistoryPage.FILENAME)) {
if (url != null) {
mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, url);
} else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra();
mBookmarksDialogBuilder.showLongPressedHistoryLinkDialog(mActivity, newUrl);
}
return null;
} else if (currentUrl.endsWith(BookmarkPage.FILENAME)) {
if (url != null) {
mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, url);
} else if (result != null && result.getExtra() != null) {
final String newUrl = result.getExtra();
mBookmarksDialogBuilder.showLongPressedDialogForBookmarkUrl(mActivity, newUrl);
}
@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);
}
}
}
@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();
if (url != null) {
if (result != null) {
if (result.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE || result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, url, getUserAgent());
} 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 (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;
mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
}
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());
mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, url);
}
@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 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) {
mBookmarksDialogBuilder.showLongPressImageDialog(mActivity, newUrl, getUserAgent());
} 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);
mBookmarksDialogBuilder.showLongPressLinkDialog(mActivity, newUrl);
}
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();
public boolean canGoBack() {
return mWebView != null && mWebView.canGoBack();
}
@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 boolean canGoForward() {
return mWebView != null && mWebView.canGoForward();
}
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);
@Nullable
public synchronized WebView getWebView() {
return mWebView;
}
public void setFavicon(Bitmap favicon) {
if (favicon == null) {
mFavicon = mDefaultIcon;
} else {
mFavicon = Utils.padFavicon(favicon);
}
public Bitmap getFavicon() {
return mTitle.getFavicon();
}
public void setTitle(String title) {
if (title == null) {
mTitle = "";
} else {
mTitle = title;
}
public synchronized void loadUrl(String url) {
// Check if configured proxy is available
if (!ProxyUtils.getInstance().isProxyReady()) {
return;
}
public void setTitleAndFavicon(String title, Bitmap favicon) {
mTitle = title;
if (favicon == null) {
mFavicon = mDefaultIcon;
} else {
mFavicon = Utils.padFavicon(favicon);
if (mWebView != null) {
mWebView.loadUrl(url, mRequestHeaders);
}
}
public String getTitle() {
return mTitle;
return mTitle.getTitle();
}
public Bitmap getFavicon() {
return mFavicon;
@NonNull
public String getUrl() {
if (mWebView != null && mWebView.getUrl() != null) {
return mWebView.getUrl();
} else {
return "";
}
}
private class TouchListener implements OnTouchListener {
@ -1105,9 +744,9 @@ public class LightningView { @@ -1105,9 +744,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();
mUIController.showActionBar();
} else if (distance < -SCROLL_UP_THRESHOLD) {
mBrowserController.hideActionBar();
mUIController.hideActionBar();
}
mLocation = 0;
}
@ -1122,9 +761,9 @@ public class LightningView { @@ -1122,9 +761,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();
mUIController.hideActionBar();
} else if (power > 15) {
mBrowserController.showActionBar();
mUIController.showActionBar();
}
return super.onFling(e1, e2, velocityX, velocityY);
}
@ -1140,8 +779,13 @@ public class LightningView { @@ -1140,8 +779,13 @@ public class LightningView {
@Override
public void onLongPress(MotionEvent e) {
if (mCanTriggerLongPress)
mBrowserController.onLongPress();
if (mCanTriggerLongPress) {
Message msg = mWebViewHandler.obtainMessage();
if (msg != null) {
msg.setTarget(mWebViewHandler);
mWebView.requestFocusNodeHref(msg);
}
}
}
/**
@ -1163,4 +807,23 @@ public class LightningView { @@ -1163,4 +807,23 @@ public class LightningView {
mCanTriggerLongPress = true;
}
}
private static class WebViewHandler extends Handler {
private final WeakReference<LightningView> mReference;
public WebViewHandler(LightningView view) {
mReference = new WeakReference<>(view);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
final String url = msg.getData().getString("url");
LightningView view = mReference.get();
if (view != null) {
view.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 static Bitmap getDefaultIcon() {
return DEFAULT_ICON;
}
}

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

@ -0,0 +1,319 @@ @@ -0,0 +1,319 @@
package acr.browser.lightning.view;
import android.annotation.TargetApi;
import android.app.Activity;
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
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.controller.UIController;
import acr.browser.lightning.utils.AdBlock;
import acr.browser.lightning.utils.IntentUtils;
import acr.browser.lightning.utils.ProxyUtils;
import acr.browser.lightning.utils.Utils;
class LightningWebClient extends WebViewClient {
private final Activity mActivity;
private final LightningView mLightningView;
private final UIController mUIController;
private final AdBlock mAdBlock;
private final Bus mEventBus;
private final IntentUtils mIntentUtils;
LightningWebClient(Activity activity, LightningView lightningView) {
mActivity = activity;
mUIController = (UIController) activity;
mLightningView = lightningView;
mAdBlock = AdBlock.getInstance(activity);
mAdBlock.updatePreference();
mEventBus = BrowserApp.getAppComponent().getBus();
mIntentUtils = new IntentUtils(activity);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
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")
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@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;
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@Override
public void onPageFinished(WebView view, String url) {
if (view.isShown()) {
mUIController.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) {
mLightningView.mTitle.setFavicon(null);
if (mLightningView.isShown()) {
mUIController.updateUrl(url, false);
mUIController.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;
@TargetApi(Build.VERSION_CODES.KITKAT)
@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);
}
}
}
private static 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 (!ProxyUtils.getInstance().isProxyReady()) {
// User has been notified
return true;
}
Map<String, String> headers = mLightningView.getRequestHeaders();
if (mLightningView.mIsIncognitoTab) {
view.loadUrl(url, headers);
return true;
}
if (url.startsWith("about:")) {
view.loadUrl(url, headers);
return true;
}
if (url.startsWith("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 ignored) {
intent = null;
}
if (intent != null) {
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setComponent(null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
intent.setSelector(null);
}
try {
mActivity.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.e(Constants.TAG, "ActivityNotFoundException");
}
return true;
}
}
if (!mIntentUtils.startActivityForUrl(view, url)) {
view.loadUrl(url, headers);
}
return true;
}
}

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>

29
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"
@ -58,7 +56,7 @@ @@ -58,7 +56,7 @@
android:background="?attr/dividerColor"
android:baselineAligned="false"
android:orientation="horizontal"
android:weightSum="3">
android:weightSum="4">
<FrameLayout
android:id="@+id/action_back"
@ -94,6 +92,23 @@ @@ -94,6 +92,23 @@
android:src="@drawable/ic_action_plus" />
</FrameLayout>
<FrameLayout
android:id="@+id/action_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?attr/actionBarItemBackground"
android:clickable="true">
<ImageView
android:id="@+id/icon_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/action_homepage"
android:src="@drawable/ic_action_home" />
</FrameLayout>
<FrameLayout
android:id="@+id/action_forward"
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"

33
app/src/main/res/values-de/strings.xml

@ -123,7 +123,6 @@ @@ -123,7 +123,6 @@
<string name="licenses">Open Source-Lizenzen</string>
<string name="suggestion">Suche nach</string>
<string name="block_ads">Werbung blockieren</string>
<string name="message_untrusted_certificate">Das Zertifikat dieser Webseite ist nicht vertrauenswürdig. Trotzdem fortsetzen?</string>
<string name="title_form_resubmission">Formularneuzustellung</string>
<string name="message_form_resubmission">Daten erneut senden?</string>
<string name="message_location">\nMeine Position verwenden?</string>
@ -184,4 +183,36 @@ @@ -184,4 +183,36 @@
<item >URL</item>
<item >Titel</item>
</string-array>
<string name="action_folder">Ordner</string>
<string name="action_rename">Umbenennen</string>
<string name="black_theme">Schwarzes Design (AMOLED)</string>
<string name="clear_web_storage">Webinhalte leeren</string>
<string name="clear_web_storage_exit">Webinhalte beim Beenden leeren</string>
<string name="dark_theme">Dunkles Design</string>
<string name="dialog_folder">Was möchten Sie mit diesem Ordner tun?</string>
<string name="dialog_history_long_press">Was möchten Sie mit diesem Verlaufs-Eintrag tun?</string>
<string name="folder">Ordnername</string>
<string name="invert_color">Farben invertieren</string>
<string name="light_theme">Helles Design</string>
<string name="manual_proxy">Manueller Proxy</string>
<string name="message_insecure_connection">Die Verbindung zu dieser Seite ist nicht sicher:\n%1$s\nTrotzdem fortfahren?</string>
<string name="message_web_storage_cleared">Webinhalte geleert</string>
<string name="port">Port:</string>
<string name="tabs">Tabs</string>
<string name="theme">App-Design</string>
<string name="title_rename_folder">Ordner umbenennen</string>
<string name="http_proxy">HTTP-Proxy</string>
<string name="i2p_not_running">I2P läuft nicht.</string>
<string name="i2p_tunnels_not_ready">I2P Tunnel sind noch nicht bereit.</string>
<string name="message_certificate_date_invalid">Zertifikats-Datum ungültig</string>
<string name="message_certificate_domain_mismatch">Domain in Zertifikat stimmt nicht mit aktueller Domain überein</string>
<string name="message_certificate_expired">Zertifikat abgelaufen</string>
<string name="message_certificate_invalid">Zertifikat ungültig</string>
<string name="message_certificate_not_yet_valid">Zertifikat noch nicht gültig</string>
<string name="message_certificate_untrusted">Zertifikat wird nicht vertraut</string>
<string name="problem_download">Ungültige Adresse gefunden. Kann nicht herunterladen</string>
<string name="problem_location_download">Kann nicht an den eingestellten Ort herunterladen</string>
<string name="use_i2p_prompt">Es sieht aus, als ob I2P installiert wäre. Möchten Sie es verwenden?</string>
<string name="text_encoding">Textcodierung</string>
<string name="tabs_in_drawer">Tabs in Drawer anzeigen</string>
</resources>

1
app/src/main/res/values-es/strings.xml

@ -106,7 +106,6 @@ @@ -106,7 +106,6 @@
<string name="licenses">Licencias de código abierto (open source)</string>
<string name="suggestion">Buscar</string>
<string name="block_ads">Bloquear anuncios</string>
<string name="message_untrusted_certificate">El certificado del sitio no es de fiar. ¿Continuar de todas maneras?</string>
<string name="title_form_resubmission">Resubir el formulario</string>
<string name="message_form_resubmission">¿Quieres mandar los datos de nuevo?</string>
<string name="message_location">\n¿Quieres usar tu geolocalización?</string>

1
app/src/main/res/values-gr/strings.xml

@ -107,7 +107,6 @@ @@ -107,7 +107,6 @@
<string name="licenses">Άδειες ανοιχτού κώδικα</string>
<string name="suggestion">Αναζήτηση για</string>
<string name="block_ads">Μπλοκάρισμα διαφημίσεων</string>
<string name="message_untrusted_certificate">Το πιστοποιητικό δεν είναι αξιόπιστο. Συνέχεια παρ\'όλα αυτά;</string>
<string name="title_form_resubmission">Επαναυποβολή φόρμας</string>
<string name="message_form_resubmission">Θα θέλατε να ξαναστείλετε τα στοιχεία;</string>
<string name="message_location">\nΘα θέλατε να χρησιμοποιήσετε την τοποθεσία σας;</string>

1
app/src/main/res/values-hu/strings.xml

@ -123,7 +123,6 @@ @@ -123,7 +123,6 @@
<string name="licenses">Nyílt forráskódú licencek</string>
<string name="suggestion">Keresés</string>
<string name="block_ads">Reklámok blokkolása</string>
<string name="message_untrusted_certificate">Az oldal tanusítványa nem megfelelő.Folytatja mindenképpen?</string>
<string name="title_form_resubmission">Űrlap újraküldése</string>
<string name="message_form_resubmission">Szeretnél újból elküldi az adatokat?</string>
<string name="message_location">\nSzeretné használni a saját helyét?</string>

229
app/src/main/res/values-it/strings.xml

@ -22,190 +22,193 @@ @@ -22,190 +22,193 @@
<string name="action_history">Cronologia</string>
<string name="action_bookmarks">Segnalibri</string>
<string name="action_add_bookmark">Aggiungi segnalibro</string>
<string name="action_copy">Copia link</string>
<string name="action_copy">Copia Link</string>
<string name="action_forward">Avanti</string>
<string name="settings">Impostazioni del browser</string>
<string name="location">Accesso alla posizione</string>
<string name="password">Salva Password</string>
<string name="settings">Impostazioni</string>
<string name="location">Localizzazione</string>
<string name="password">Salva password</string>
<string name="agent">User Agent</string>
<string name="flash">Abilita Adobe Flash</string>
<string name="home">Homepage</string>
<string name="fullscreen">Mod. Schermo intero</string>
<string name="home">Home</string>
<string name="fullscreen">Schermo Intero</string>
<string name="java">Abilita JavaScript</string>
<string name="download">Percorso download</string>
<string name="settings_advanced">Impostazioni avanzate</string>
<string name="apache">Licenza Apache 2.0</string>
<string name="version">Versione Applicazione</string>
<string name="cache">Pulisci la cache alla chiusura</string>
<string name="reflow">Abilità reflow del testo</string>
<string name="block">Blocca immagini</string>
<string name="window">Consenti l\'apertura di nuove finestre</string>
<string name="download">Scegli un percorso</string>
<string name="settings_advanced">Avanzate</string>
<string name="apache">Apache License 2.0</string>
<string name="version">Versione App</string>
<string name="cache">Cancella la cache in chiusura</string>
<string name="reflow">Abilità il reflow del testo</string>
<string name="block">Blocca Immagini</string>
<string name="window">Consenti a siti di aprire nuove finestre</string>
<string name="cookies">Abilita Cookies</string>
<string name="importbookmarks">Importa Segnalibri</string>
<string name="size">Dimensione testo</string>
<string name="importbookmarks">Importa preferiti da browser</string>
<string name="size">Dimensioni carattere</string>
<string name="recommended">Consigliato</string>
<string name="search">Motore di ricerca</string>
<string name="search_hint">Cerca</string>
<string name="wideViewPort">Use wide viewport</string>
<string name="overViewMode">Carica le pagine in modalità overview</string>
<string name="restore">Ricarica le schede perse all\'avvio</string>
<string name="wideViewPort">Utilizza ampia finestra</string>
<string name="overViewMode">Carica le pagine in modalità panoramica</string>
<string name="restore">Restore lost tabs on start</string>
<string name="stock_browser_unavailable">Nessun browser stock trovato</string>
<string name="stock_browser_available">Browser stock supportato trovato</string>
<string name="fullScreenOption">Nascondi la barra di stato durante la navigazione</string>
<string name="fullScreenOption">Nascondi la barra di stato mentre navighi</string>
<string name="clear_cookies">Cancella i cookies</string>
<string name="dialog_image">Cosa vorresti fare con questa immagine?</string>
<string name="dialog_image">Cosa vuoi fare con questa immagine?</string>
<string name="action_download">Scarica</string>
<string name="action_open">Apri</string>
<string name="dialog_link">Cosa vorresti fare con questo link?</string>
<string name="dialog_link">Cosa vuoi fare con questo link?</string>
<string name="dialog_title_share">Condividi questa pagina</string>
<string name="dialog_bookmark">Cosa vorresti fare con questo segnalibro?</string>
<string name="action_delete">Cancella</string>
<string name="dialog_history_long_press">Cosa vuoi fare con questo elemento di cronologia?</string>
<string name="dialog_bookmark">Cosa vorresti fare con questo preferito?</string>
<string name="action_delete">Elimina</string>
<string name="action_blank">Pagina vuota</string>
<string name="agent_default">Default</string>
<string name="agent_desktop">Desktop</string>
<string name="agent_mobile">Mobile</string>
<string name="agent_custom">Personalizzato</string>
<string name="title_search_engine">Motore di ricerca</string>
<string name="agent_custom">Custom</string>
<string name="title_search_engine">Motore di Ricerca</string>
<string name="action_ok">OK</string>
<string name="dialog_download">Vuoi scaricare questo file?</string>
<string name="dialog_download">Vuoi scaricarlo?</string>
<string name="action_cancel">Annulla</string>
<string name="title_warning">Attenzione</string>
<string name="dialog_adobe_not_installed">Adobe Flash Player non rilevato.\nSi prega di installare Flash Player.</string>
<string name="dialog_adobe_not_installed">Adobe Flash Player non è stato trovato.\nSi prega di installare Flash Player.</string>
<string name="title_user_agent">User Agent</string>
<string name="title_download_location">Percorso download</string>
<string name="title_custom_homepage">Homepage personale</string>
<string name="title_clear_history">Cancella cronologia</string>
<string name="title_clear_cookies">Cancella i cookie</string>
<string name="dialog_history">Vorresti eliminare tutta la cronologia del browser?</string>
<string name="dialog_cookies">Vorresti eliminare tutti i cookie del browser?</string>
<string name="title_download_location">Percorso Download</string>
<string name="title_custom_homepage">Pagina iniziale</string>
<string name="action_webpage">Pagina Web</string>
<string name="title_clear_history">Cancella la cronologia</string>
<string name="title_clear_cookies">Cancella i cookies</string>
<string name="dialog_history">Vorresti cancellare tutta la cronologia?</string>
<string name="dialog_cookies">Vorresti cancellare tutti i cookies?</string>
<string name="action_yes">Si</string>
<string name="action_no">No</string>
<string name="title_text_size">Dimensione testo</string>
<string name="size_largest">Più Grande</string>
<string name="title_text_size">Dimensioni carattere</string>
<string name="size_largest">Più grande</string>
<string name="size_large">Grande</string>
<string name="size_normal">Normale</string>
<string name="size_small">Piccolo</string>
<string name="size_smallest">Più Piccolo</string>
<string name="size_smallest">Più piccolo</string>
<string name="title_error">Errore</string>
<string name="dialog_import_error">Nessun browser rilevato da cui importare segnalibri.</string>
<string name="dialog_import_error">Nessun browser è stato trovato.</string>
<string name="hint_title">Titolo</string>
<string name="hint_url">URL</string>
<string name="title_edit_bookmark">Modifica Segnalibro</string>
<string name="action_edit">Modifica</string>
<string name="action_incognito">Nuova scheda anonima</string>
<string name="title_edit_bookmark">Edita</string>
<string name="action_edit">Edita</string>
<string name="action_incognito">Nuova scheda in incognito</string>
<string name="action_homepage">Default</string>
<string name="action_back">Indietro</string>
<string name="action_find">Trova nella pagina</string>
<string name="download_pending">Avvio scaricamento\u2026</string>
<string name="cannot_download">Possibile scaricare solo da URL \"http\" o \"https\".</string>
<string name="download_no_sdcard_dlg_title">Nessuna scheda SD</string>
<string name="download_no_sdcard_dlg_msg">Una memoria USB è necessaria per scaricare il file.</string>
<string name="download_sdcard_busy_dlg_title">Memoria USB non disponibile</string>
<string name="download_sdcard_busy_dlg_msg">La memoria di archiviazione è occupata. Per permettere i download, tocca Disattiva Memoria USB nella notifica.</string>
<string name="incognito_cookies">Abilita Cookies in modalità incognito</string>
<string name="download_pending">Inizio download\u2026</string>
<string name="cannot_download">Può solo scaricare \"http\" or \"https\" URLs.</string>
<string name="download_no_sdcard_dlg_title" >Nessuna SD Card trovata.</string>
<string name="download_no_sdcard_dlg_msg" >USB storage is required to download the file.</string>
<string name="download_sdcard_busy_dlg_title">USB storage unavailable</string>
<string name="download_sdcard_busy_dlg_msg" >The storage is busy. To allow downloads, touch Turn Off USB Storage in the notification.</string>
<string name="incognito_cookies">Enable Cookies in Incognito Mode</string>
<string name="title_flash">Adobe Flash</string>
<string name="action_manual">Manuale</string>
<string name="action_auto">Auto</string>
<string name="action_auto">Automatica</string>
<string name="action_follow_me">Contattami</string>
<string name="url_twitter">twitter.com/ACRDevelopment</string>
<string name="clear_cache">Pulisci la Cache</string>
<string name="message_cache_cleared">Cache Cancellata</string>
<string name="message_import">Segnalibri importati!</string>
<string name="message_clear_history">Cronologia Cancellata</string>
<string name="message_cookies_cleared">Cookies Cancellati</string>
<string name="max_tabs">Numero massimo di pagine raggiunto</string>
<string name="url_twitter">twitter.com/RestainoAnthony</string>
<string name="clear_cache">Cancella la cache</string>
<string name="message_cache_cleared">Cache cancellata</string>
<string name="message_import">Segnalibri importati</string>
<string name="message_clear_history">Cronologia cancellata</string>
<string name="message_cookies_cleared">Cookies cancellati</string>
<string name="max_tabs">Massimo numero di schede raggiunto!</string>
<string name="message_text_copied">Testo copiato negli appunti</string>
<string name="message_link_copied">Link copiato negli appunti</string>
<string name="block_ads">Blocca Annunci</string>
<string name="custom_url">URL personale</string>
<string name="message_blocked_local">Il caricamento del file locale è stato bloccato</string>
<string name="custom_url">URL Personalizzato</string>
<string name="message_blocked_local">Local file has been blocked from loading</string>
<string name="licenses">Licenze Open Source</string>
<string name="suggestion">Cerca</string>
<string name="message_untrusted_certificate">Il certificato del sito non è fidato. Procedere comunque?</string>
<string name="title_form_resubmission">Reinvio form</string>
<string name="message_form_resubmission">Vuoi reinviare i dati?</string>
<string name="block_ads">Blocca Annunci</string>
<string name="title_form_resubmission">Reinvio Modulo</string>
<string name="message_form_resubmission">Vuoi inviare nuovamente i dati?</string>
<string name="message_location">\nVorrebbe usare la tua posizione</string>
<string name="action_allow">Permetti</string>
<string name="action_dont_allow">Nega</string>
<string name="title_sign_in">Accedi</string>
<string name="hint_username">Nome utente</string>
<string name="action_allow">Consenti</string>
<string name="action_dont_allow">Non consentire</string>
<string name="title_sign_in">Registrati</string>
<string name="hint_username">Username</string>
<string name="hint_password">Password</string>
<string name="google_suggestions">Suggerimenti di ricerca</string>
<string name="powered_by_google">In collaborazione con Google</string>
<string name="powered_by_google">Powered by Google</string>
<string name="http_proxy">HTTP Proxy</string>
<string-array name="proxy_choices_array">
<item>Nessuno</item>
<item>Orbot</item>
<item>I2P</item>
<item>Manuale</item>
</string-array>
<string name="manual_proxy">Proxy manuale</string>
<string name="host">Host:</string>
<string name="port">Porta:</string>
<string name="use_tor_prompt">Sembra che tu abbia Orbot installato. Vuoi usare Tor?</string>
<string name="use_i2p_prompt">Sembra che tu abbia I2P installato. Vuoi usare I2P?</string>
<string name="install_orbot">Devi installare Orbot per navigare con Tor.</string>
<string name="i2p_not_running">I2P non è attivo.</string>
<string name="i2p_tunnels_not_ready">I tunnel I2P non sono ancora pronti.</string>
<string name="yes">Sì</string>
<string name="use_tor_prompt">Sembra che tu abbia Orbot installato. Vorresti usare Tor?</string>
<string name="use_i2p_prompt">Sembra che tu abbia I2P installato. Vorresti usare I2P?</string>
<string name="install_orbot">Si prega di installare Orbot per creare un proxy con Tor.</string>
<string name="i2p_not_running">I2P non è in esecuzione.</string>
<string name="i2p_tunnels_not_ready">I tunnel I2P non sono pronti al momento.</string>
<string name="yes">Si</string>
<string name="no">No</string>
<string name="clear_cookies_exit">Elimina i cookie all\'uscita</string>
<string name="clear_history_exit">Elimina la cronologia all\'uscita</string>
<string name="folder_default">Predefinito</string>
<string name="folder_custom">Personale</string>
<string name="clear_cookies_exit">Cancella i cookies in chiusura</string>
<string name="clear_history_exit">Cancella la cronologia in chiusura</string>
<string name="folder_default">Default</string>
<string name="folder_custom">Custom</string>
<string name="untitled">Senza titolo</string>
<string name="mpl_license">Mozilla Public License v. 2.0</string>
<string name="freeware">Freeware</string>
<string name="android_open_source_project">Android Open Source Project</string>
<string name="hphosts_ad_server_list">hpHosts Ad Server List</string>
<string name="deleted_tab">Vecchia scheda riaperta</string>
<string name="rendering_mode">Modalità rendering</string>
<string name="sync_history">Sincronizza cronologia con Google</string>
<string name="title_file_chooser">Selezione file</string>
<string name="deleted_tab">Reopened old tab</string>
<string name="rendering_mode">Rendering Mode</string>
<string name="name_inverted">Inverso</string>
<string name="name_grayscale">Scala di grigi</string>
<string name="name_inverted_grayscale">Scala di grigi invertita</string>
<string name="name_normal">Normale</string>
<string name="sync_history">Sincronizza la cronologia con l\'account Google</string>
<string name="title_file_chooser">Seleziona file</string>
<string name="library_netcipher">NetCipher</string>
<string name="license_gnu">GNU Lesser General Public License</string>
<string name="export_bookmarks">Esporta segnalibri</string>
<string name="import_backup">Importa segnalibri da backup</string>
<string name="export_bookmarks">Esporta i segnalibri per il backup</string>
<string name="import_backup">Importa i segnalibri da un backup</string>
<string name="bookmark_export_path">Segnalibri esportati</string>
<string name="bookmark_settings">Segnalibri</string>
<string name="import_bookmark_error">Impossibile importare i segnalibri dal file</string>
<string name="title_chooser">Seleziona un file</string>
<string name="import_bookmark_error">Impossibile importare i segnalibri da file</string>
<string name="title_chooser">Scegli un file</string>
<string name="settings_general">Generali</string>
<string name="settings_display">Display</string>
<string name="settings_privacy">Privacy</string>
<string name="settings_about">Informazioni</string>
<string name="settings_about_explain">Informazioni sull\'autore, versione e license.</string>
<string name="name_inverted">Inverso</string>
<string name="name_grayscale">Scala di grigi</string>
<string name="name_inverted_grayscale">Scala di grigi inversa</string>
<string name="name_normal">Normale</string>
<string name="licenses">Licenze Open Source</string>
<string name="action_webpage">Pagina Web</string>
<string name="settings_about_explain">Informazioni sulla versione, l\'autore e licenze.</string>
<string name="close_tab">Chiudi scheda</string>
<string name="close_all_tabs">Chiudi tutte le schede</string>
<string name="third_party">Blocca i cookie di terze parti</string>
<string name="third_party">Blocca cookies di terze parti.</string>
<string name="color_mode">Attiva modalità colore</string>
<string name="reading_mode">Modalità lettura</string>
<string name="loading">Caricamento&#8230;</string>
<string name="loading_failed">Impossibile caricare la pagina.</string>
<string name="loading_failed">Impossibile caricare nulla dalla pagina.</string>
<string name="snacktory">Snacktory</string>
<string name="jsoup">jsoup: Java HTML Parser</string>
<string name="mit_license">Licenza MIT</string>
<string name="url_contents">Contenuti campo URL</string>
<string name="mit_license">MIT License</string>
<string name="url_contents">URL Box Contents</string>
<string name="text_encoding">Text Encoding</string>
<string-array name="url_content_array">
<item>Dominio (predefinito)</item>
<item>URL</item>
<item>Titolo</item>
<item >Dominio (default)</item>
<item >URL</item>
<item >Titolo</item>
</string-array>
<string name="invert_color">Inverti colori</string>
<string name="dark_theme">Tema Scuro</string>
<string name="dark_theme">Scuro</string>
<string name="tabs">Schede</string>
<string name="theme">Temi</string>
<string name="light_theme">Tema Chiaro</string>
<string name="black_theme">Tema Nero (AMOLED)</string>
<string name="folder">Nomne Cartella</string>
<string name="theme">Tema App</string>
<string name="light_theme">Chiaro</string>
<string name="black_theme">Nero (AMOLED)</string>
<string name="folder">Nome cartella</string>
<string name="action_folder">Cartella</string>
<string name="action_rename">Rinomina</string>
<string name="title_rename_folder">Rinomina Cartellar</string>
<string name="dialog_folder">Cosa vorresti fare con questa cartella?</string>
<string name="title_rename_folder">Rinomina cartella</string>
<string name="dialog_folder">Cosa vuoi fare con questa cartella?</string>
<string name="clear_web_storage">Clear Web Storage</string>
<string name="http_proxy">Proxy HTTP</string>
<string-array name="proxy_choices_array">
<item>Nessuno</item>
<item>Orbot</item>
<item>I2P</item>
<item>Manuale</item>
</string-array>
<string name="clear_web_storage_exit">Clear web storage on exit</string>
<string name="message_web_storage_cleared">Web Storage Cleared</string>
</resources>

1
app/src/main/res/values-ja/strings.xml

@ -120,7 +120,6 @@ @@ -120,7 +120,6 @@
<string name="licenses">オープンソースライセンス</string>
<string name="suggestion">Search for</string>
<string name="block_ads">広告ブロック</string>
<string name="message_untrusted_certificate">このページに信用性の証明書がありません。読み込みを続けますか?</string>
<string name="title_form_resubmission">フォームの再送</string>
<string name="message_form_resubmission">データを再送しますか?</string>
<string name="message_location">\n位置情報の提供を許可しますか?</string>

1
app/src/main/res/values-ko/strings.xml

@ -106,7 +106,6 @@ @@ -106,7 +106,6 @@
<string name="licenses">오픈 소스 라이센스</string>
<string name="suggestion">다음을 검색</string>
<string name="block_ads">광고 차단</string>
<string name="message_untrusted_certificate">이 웹사이트의 인증서는 신뢰할 수 없습니다. 계속할까요?</string>
<string name="title_form_resubmission">양식 다시 제출</string>
<string name="message_form_resubmission">다시 전송할까요?</string>
<string name="message_location">\n 이(가) 위치를 사용하고자 합니다</string>

78
app/src/main/res/values-pl/strings.xml

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
<string name="action_share">Udostępnij</string>
<string name="action_history">Historia</string>
<string name="action_bookmarks">Zakładki</string>
<string name="action_add_bookmark">Dodaj do zakładek</string>
<string name="action_add_bookmark">Dodaj zakładkę</string>
<string name="action_copy">Kopiuj link</string>
<string name="action_forward">Dalej</string>
<string name="settings">Ustawienia</string>
@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
<string name="java">Włącz Javascript</string>
<string name="download">Miejsce zapisu pobieranych plików</string>
<string name="settings_advanced">Zaawansowane</string>
<string name="apache">Apache License 2.0</string>
<string name="apache">Licencja Apache 2.0</string>
<string name="version">Wersja aplikacji</string>
<string name="cache">Wyczyść pamięć podręczną po zamknięciu</string>
<string name="reflow">Zawijaj tekst do rozmiaru ekranu</string>
@ -42,6 +42,7 @@ @@ -42,6 +42,7 @@
<string name="action_open">Otwórz</string>
<string name="dialog_link">Co chciałbyś zrobić z tym linkiem?</string>
<string name="dialog_title_share">Udostępnij tę stronę</string>
<string name="dialog_history_long_press">Co chciałbyś zrobić z tym wpisem historii przeglądania?</string>
<string name="dialog_bookmark">Co chciałbyś zrobić z tą zakładką?</string>
<string name="action_delete">Usuń</string>
<string name="action_blank">Pusta</string>
@ -83,6 +84,8 @@ @@ -83,6 +84,8 @@
<string name="action_find">Znajdź na stronie</string>
<string name="download_pending">Rozpoczynanie pobierania\u2026</string>
<string name="cannot_download">Pliki mogą być pobierane tylko z linków zaczynających się od \"http\" lub \"https\".</string>
<string name="problem_download">Nie można pobrać - nieprawidłowy URL</string>
<string name="problem_location_download">Nie można pobrać pliku do wskazanej lokalizacji</string>
<string name="download_no_sdcard_dlg_title" >Brak karty SD</string>
<string name="download_no_sdcard_dlg_msg" >Pamięć USB jest wymagana do pobrania tego pliku.</string>
<string name="download_sdcard_busy_dlg_title">Pamięć USB niedostępna</string>
@ -106,7 +109,13 @@ @@ -106,7 +109,13 @@
<string name="licenses">Licencje Open Source</string>
<string name="suggestion">Wyszukaj</string>
<string name="block_ads">Blokuj reklamy</string>
<string name="message_untrusted_certificate">Certyfikat używany przez tę stronę nie jest zaufany. Kontynuować mimo wszystko?</string>
<string name="message_insecure_connection">Połączenie z tą stroną jest niezaufane:\n%1$s\nKontynuuować mimo wszystko?</string>
<string name="message_certificate_date_invalid">data ważności certyfikatu jest nieprawidłowa</string>
<string name="message_certificate_domain_mismatch">domena dla której wystawiono certyfikat jest różna od domeny odwiedzanej strony</string>
<string name="message_certificate_expired">data ważności certyfikatu już upłynęła</string>
<string name="message_certificate_invalid">ceryfikat jest nieprawidłowy</string>
<string name="message_certificate_not_yet_valid">certyfikat nie jest jeszcze ważny</string>
<string name="message_certificate_untrusted">certyfikat jest niezaufany</string>
<string name="title_form_resubmission">Ponowne wysyłanie formularza</string>
<string name="message_form_resubmission">Czy chciałbyś ponownie wysłać dane wprowadzone do formularza?</string>
<string name="message_location">\nTa strona prosi o dostęp do twojej geolokalizacji</string>
@ -117,8 +126,21 @@ @@ -117,8 +126,21 @@
<string name="hint_password">Hasło</string>
<string name="google_suggestions">Podpowiedzi wyszukiwania</string>
<string name="powered_by_google">Dostarczane przez Google</string>
<string name="use_tor_prompt">Wygląda na to że Orbot jest zainstalowany. Chciałbyś go włączyć i użyć sieci Tor do łączenia się z internetem?</string>
<string name="install_orbot">Zanistaluj Orbota by móc używać sieci Tor do łączenia się z internetem.</string>
<string name="http_proxy">Konfiguracja serwera proxy</string>
<string-array name="proxy_choices_array">
<item>Bez proxy</item>
<item>Orbot</item>
<item>I2P</item>
<item>Ręczne ustawienia</item>
</string-array>
<string name="manual_proxy">Ręczne ustawienia proxy</string>
<string name="host">Host:</string>
<string name="port">Port:</string>
<string name="use_tor_prompt">Wygląda na to że Orbot jest zainstalowany. Chciałbyś go włączyć i użyć sieci TOR do łączenia się z internetem?</string>
<string name="use_i2p_prompt">Wygląda na to że I2P jest zainstalowany. Chciałbyś go użyć do łączenia się z internetem?</string>
<string name="install_orbot">Zainstaluj Orbota by móc używać sieci TOR do łączenia się z internetem.</string>
<string name="i2p_not_running">I2P nie jest uruchomiony.</string>
<string name="i2p_tunnels_not_ready">Tunele I2P nie są jeszcze gotowe.</string>
<string name="yes">Tak</string>
<string name="no">Nie</string>
<string name="clear_cookies_exit">Wyczyść ciasteczka po zamknięciu</string>
@ -129,19 +151,19 @@ @@ -129,19 +151,19 @@
<string name="mpl_license">Mozilla Public License v. 2.0</string>
<string name="freeware">Freeware</string>
<string name="android_open_source_project">Android Open Source Project</string>
<string name="hphosts_ad_server_list">hpHosts Ad Server List</string>
<string name="hphosts_ad_server_list">Lista filtrów hpHosts</string>
<string name="deleted_tab">Przywrócono kartę</string>
<string name="rendering_mode">Tryb Renderowania</string>
<string name="rendering_mode">Tryb renderowania</string>
<string name="name_inverted">Odwrócony</string>
<string name="name_grayscale">Odcienie Szarości</string>
<string name="name_inverted_grayscale">Odwrócone Odcienie Szarości</string>
<string name="name_grayscale">Odcienie szarości</string>
<string name="name_inverted_grayscale">Odwrócone odcienie szarości</string>
<string name="name_normal">Normalny</string>
<string name="sync_history">Synchronizuj historię z Google</string>
<string name="title_file_chooser">Wybierz plik</string>
<string name="library_netcipher">NetCipher</string>
<string name="license_gnu">GNU Lesser General Public License</string>
<string name="export_bookmarks">Eksportuj zakładki do backupu</string>
<string name="import_backup">Importuj zakładki z backupu</string>
<string name="export_bookmarks">Eksportuj zakładki</string>
<string name="import_backup">Importuj zakładki</string>
<string name="bookmark_export_path">Zakładki wyeksportowane do</string>
<string name="bookmark_settings">Zakładki</string>
<string name="import_bookmark_error">Nie udało się zaimportować zakładek z</string>
@ -149,10 +171,40 @@ @@ -149,10 +171,40 @@
<string name="settings_general">Ogólne</string>
<string name="settings_display">Wyświetlanie</string>
<string name="settings_privacy">Prywatność</string>
<string name="settings_about">O Przeglądarce</string>
<string name="settings_about">O przeglądarce</string>
<string name="settings_about_explain">Szczegóły o wersji, autorze i licencji.</string>
<string name="close_tab">Zamknij kartę</string>
<string name="close_all_tabs">Zamknij wszystkie karty</string>
<string name="third_party">Blokuj ciasteczka z innych witryn</string>
<string name="color_mode">Włącz Tryb zmieniania koloru</string>
<string name="color_mode">Włącz tryb zmieniania koloru</string>
<string name="reading_mode">Tryb czytania</string>
<string name="loading">Ładowanie&#8230;</string>
<string name="loading_failed">Nie udało się wczytać tekstu ze strony.</string>
<string name="snacktory">Snacktory</string>
<string name="jsoup">jsoup: Java HTML Parser</string>
<string name="mit_license">Licencja MIT</string>
<string name="url_contents">Zawartość paska adresu</string>
<string name="text_encoding">Kodowanie tekstu</string>
<string-array name="url_content_array">
<item >Tylko domena (domyślne)</item>
<item >Pełny URL</item>
<item >Tytuł strony</item>
</string-array>
<string name="invert_color">Odwróć kolory</string>
<string name="dark_theme">Ciemny motyw</string>
<string name="tabs">Karty</string>
<string name="theme">Wygląd aplikacji</string>
<string name="light_theme">Jasny motyw</string>
<string name="black_theme">Czarny motyw (AMOLED)</string>
<string name="folder">Nazwa folderu</string>
<string name="action_folder">Folder</string>
<string name="action_rename">Zmień nazwę</string>
<string name="title_rename_folder">Zmień nazwę folderu</string>
<string name="dialog_folder">Co chciałbyś zrobić z tym folderem?</string>
<string name="clear_web_storage">Wyczyść dane i ustawienia witryn</string>
<string name="clear_web_storage_exit">Wyczyść dane i ustawienia witryn po zamknięciu</string>
<string name="message_web_storage_cleared">Dane i ustawienia witryn zostały wyczyszczone</string>
<string name="hosts_source">Źródło filtrów blokujących reklamy</string>
<string name="settings_adblock">Ustawienia blokowania reklam</string>
<string name="tabs_in_drawer">Pokazuj karty w bocznym menu</string>
</resources>

1
app/src/main/res/values-pt/strings.xml

@ -122,7 +122,6 @@ @@ -122,7 +122,6 @@
<string name="licenses">Licenças Open Source</string>
<string name="suggestion">Pesquisar por</string>
<string name="block_ads">Bloquear anúncios</string>
<string name="message_untrusted_certificate">O certificado deste sítio web não é fiável. Continuar?</string>
<string name="title_form_resubmission">Submissão de formulário</string>
<string name="message_form_resubmission">Gostaria de reenviar os dados?</string>
<string name="message_location">\nGostaria de utilizar a sua localização</string>

1
app/src/main/res/values-ru/strings.xml

@ -106,7 +106,6 @@ @@ -106,7 +106,6 @@
<string name="licenses">Open Source Licenses</string>
<string name="suggestion">Искать</string>
<string name="block_ads">Блокировать рекламу</string>
<string name="message_untrusted_certificate">Сертификат сайта не является доверенным. Все равно продолжить?</string>
<string name="title_form_resubmission">Повторная форма</string>
<string name="message_form_resubmission">Вы действительно хотите отправить данные?</string>
<string name="message_location">\Хотите использовать своё местоположение?</string>

50
app/src/main/res/values-sr/strings.xml

@ -1,10 +1,13 @@ @@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -12,7 +15,7 @@ @@ -12,7 +15,7 @@
limitations under the License.
-->
<resources>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_name">Муња</string>
<string name="action_new_tab">Нови језичак</string>
@ -56,6 +59,7 @@ @@ -56,6 +59,7 @@
<string name="action_open">Отвори</string>
<string name="dialog_link">Шта желите да урадите са овом везом?</string>
<string name="dialog_title_share">Подели ову страницу</string>
<string name="dialog_history_long_press">Шта желите да урадите са овом ставком историјата?</string>
<string name="dialog_bookmark">Шта желите да урадите са овим обележивачем?</string>
<string name="action_delete">Обриши</string>
<string name="action_blank">Празна страница</string>
@ -96,7 +100,9 @@ @@ -96,7 +100,9 @@
<string name="action_back">Назад</string>
<string name="action_find">Нађи на страници</string>
<string name="download_pending">Покрећем преузимање\u2026</string>
<string name="cannot_download">Преузимање је могуће само са „http“ или „https“ адреса.</string>
<string name="cannot_download">Могу да преузмем само са „http“ или „https“ адреса.</string>
<string name="problem_download">Неисправан УРЛ, не могу да преузмем</string>
<string name="problem_location_download">Не могу да преузмем у наведену локацију</string>
<string name="download_no_sdcard_dlg_title">Нема СД картице</string>
<string name="download_no_sdcard_dlg_msg">УСБ складиште је потребно за преузимање фајла.</string>
<string name="download_sdcard_busy_dlg_title">УСБ складиште није доступно</string>
@ -120,7 +126,13 @@ @@ -120,7 +126,13 @@
<string name="licenses">Лиценце отвореног кôда</string>
<string name="suggestion">Тражи</string>
<string name="block_ads">Блокирај рекламе</string>
<string name="message_untrusted_certificate">Сертификат овог сајта није поуздан. Да наставим свеједно?</string>
<string name="message_insecure_connection">Веза са овим сајтом није безбедна:\n%1$s\nДа наставим свеједно?</string>
<string name="message_certificate_date_invalid">датум сертификата је неважећи</string>
<string name="message_certificate_expired">сертификат је истекао</string>
<string name="message_certificate_domain_mismatch">домен на сертификату се не поклапа са доменом сајта</string>
<string name="message_certificate_invalid">сертификат је неважећи</string>
<string name="message_certificate_not_yet_valid">сертификат још није важећи</string>
<string name="message_certificate_untrusted">сертификат није поуздан</string>
<string name="title_form_resubmission">Поновно слање формулара</string>
<string name="message_form_resubmission">Желите ли да поново пошаљете податке?</string>
<string name="message_location">\nЖелите ли да користите вашу локацију</string>
@ -131,8 +143,21 @@ @@ -131,8 +143,21 @@
<string name="hint_password">Лозинка</string>
<string name="google_suggestions">Предлози претраге</string>
<string name="powered_by_google">Погоњено Гуглом</string>
<string name="http_proxy">ХТТП прокси</string>
<string-array name="proxy_choices_array">
<item>Ништа</item>
<item>Орбот</item>
<item>I2P</item>
<item>Ручно</item>
</string-array>
<string name="manual_proxy">Ручне поставке проксија</string>
<string name="host">Домаћин:</string>
<string name="port">Порт:</string>
<string name="use_tor_prompt">Изгледа да имате Орбот инсталиран. Желите ли да користите Тор?</string>
<string name="use_i2p_prompt">Изгледа да имате I2P инсталиран. Желите ли да користите I2P?</string>
<string name="install_orbot">Инсталирајте Орбот да бисте користили Тор.</string>
<string name="i2p_not_running">I2P није покренут.</string>
<string name="i2p_tunnels_not_ready">I2P тунели још нису спремни.</string>
<string name="yes">Да</string>
<string name="no">Не</string>
<string name="clear_cookies_exit">Очисти колачиће по затварању</string>
@ -169,13 +194,14 @@ @@ -169,13 +194,14 @@
<string name="close_all_tabs">Затвори све језичке</string>
<string name="third_party">Блокирај колачиће треће стране</string>
<string name="color_mode">Режим боје</string>
<string name="reading_mode">Режим исцртавања</string>
<string name="reading_mode">Режим за читање</string>
<string name="loading">Учитавам&#8230;</string>
<string name="loading_failed">Нисам могао ништа да учитам са странице.</string>
<string name="snacktory">Snacktory</string>
<string name="jsoup">jsoup: Јава ХТМЛ рашчлањивач</string>
<string name="mit_license">МИТ лиценца</string>
<string name="url_contents">Садржај УРЛ бокса</string>
<string name="text_encoding">Кодирање текста</string>
<string-array name="url_content_array">
<item >Домен (подраз.)</item>
<item >УРЛ</item>
@ -183,5 +209,19 @@ @@ -183,5 +209,19 @@
</string-array>
<string name="invert_color">Обрнута боја</string>
<string name="tabs">Језичци</string>
<string name="dark_theme">Тамна тема</string>
<string name="theme">Тема</string>
<string name="light_theme">Светла</string>
<string name="dark_theme">Тамна</string>
<string name="black_theme">Црна (АМОЛЕД)</string>
<string name="folder">Назив фасцикле</string>
<string name="action_folder">Фасцикла</string>
<string name="action_rename">Преименуј</string>
<string name="title_rename_folder">Преименуј фасциклу</string>
<string name="dialog_folder">Шта желите да урадите са овом фасциклом?</string>
<string name="clear_web_storage">Очисти веб складиште</string>
<string name="clear_web_storage_exit">Очисти веб складиште по затварању</string>
<string name="message_web_storage_cleared">Веб складиште је очишћено</string>
<string name="hosts_source">Извор hosts фајла за блокирање реклама</string>
<string name="settings_adblock">Поставке Адблока</string>
<string name="tabs_in_drawer">Језичци у фиоци навигације</string>
</resources>

1
app/src/main/res/values-tr/strings.xml

@ -107,7 +107,6 @@ @@ -107,7 +107,6 @@
<string name="licenses">Open Source Licenses</string>
<string name="suggestion">Ara</string>
<string name="block_ads">Reklamları Engelle</string>
<string name="message_untrusted_certificate">Sitenin sertifikası güvenilir değil. Yine de devam edilsin mi?</string>
<string name="title_form_resubmission">Formu yeniden gönder</string>
<string name="message_form_resubmission">Veriyi yeniden göndermek istiyor musun?</string>
<string name="message_location">\nKonum bilgisi isteniyor</string>

8
app/src/main/res/values-v16/styles.xml

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="normalText">
<item name="android:textStyle">normal</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
</resources>

1
app/src/main/res/values-zh-rCN/strings.xml

@ -107,7 +107,6 @@ @@ -107,7 +107,6 @@
<string name="licenses">开源许可</string>
<string name="suggestion">搜索目标</string>
<string name="block_ads">拦截广告</string>
<string name="message_untrusted_certificate">该网站的证书不被信任。是否仍要继续?</string>
<string name="title_form_resubmission">重新提交表单</string>
<string name="message_form_resubmission">你想重新发送数据吗?</string>
<string name="message_location">\n你想使用你的位置吗?</string>

10
app/src/main/res/values/strings.xml

@ -126,7 +126,13 @@ @@ -126,7 +126,13 @@
<string name="licenses">Open Source Licenses</string>
<string name="suggestion">Search for</string>
<string name="block_ads">Block Ads</string>
<string name="message_untrusted_certificate">The certificate of the site is not trusted. Proceed anyway?</string>
<string name="message_insecure_connection">Connection to this site is not secure:\n%1$s\nProceed anyway?</string>
<string name="message_certificate_date_invalid">date of certificate is invalid</string>
<string name="message_certificate_expired">certificate is expired</string>
<string name="message_certificate_domain_mismatch">domain in certificate does not match the site domain</string>
<string name="message_certificate_invalid">certificate is invalid</string>
<string name="message_certificate_not_yet_valid">certificate is not yet valid</string>
<string name="message_certificate_untrusted">certificate is not trusted</string>
<string name="title_form_resubmission">Form Resubmission</string>
<string name="message_form_resubmission">Would you like to resend the data?</string>
<string name="message_location">\nWould like to use your location</string>
@ -218,4 +224,6 @@ @@ -218,4 +224,6 @@
<string name="hosts_source">Hosts File Ad Blocking Source</string>
<string name="settings_adblock">Ad Block Settings</string>
<string name="tabs_in_drawer">Show tabs in Navigation Drawer</string>
<string name="do_not_track">Request \'Do Not Track\'</string>
<string name="remove_identifying_headers">Remove Identifying Headers</string>
</resources>

1
app/src/main/res/values/styles.xml

@ -123,7 +123,6 @@ @@ -123,7 +123,6 @@
<style name="normalText">
<item name="android:textStyle">normal</item>
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="TwoWayView">

30
app/src/main/res/xml/preference_privacy.xml

@ -5,43 +5,51 @@ @@ -5,43 +5,51 @@
<CheckBoxPreference
android:defaultValue="true"
android:key="location"
android:title="@string/location" />
android:title="@string/location"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="third_party"
android:title="@string/third_party" />
android:title="@string/third_party"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="password"
android:summary="@string/recommended"
android:title="@string/password" />
android:title="@string/password"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="do_not_track"
android:title="@string/do_not_track"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="remove_identifying_headers"
android:title="@string/remove_identifying_headers"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="clear_cache_exit"
android:title="@string/cache" />
android:title="@string/cache"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="clear_history_exit"
android:title="@string/clear_history_exit" />
android:title="@string/clear_history_exit"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="clear_cookies_exit"
android:title="@string/clear_cookies_exit" />
android:title="@string/clear_cookies_exit"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="clear_webstorage_exit"
android:title="@string/clear_web_storage_exit" />
android:title="@string/clear_web_storage_exit"/>
<Preference
android:key="clear_cache"
android:title="@string/clear_cache" />
android:title="@string/clear_cache"/>
<Preference
android:key="clear_history"
android:title="@string/title_clear_history" />
android:title="@string/title_clear_history"/>
<Preference
android:key="clear_cookies"
android:title="@string/clear_cookies" />
android:title="@string/clear_cookies"/>
<Preference
android:key="clear_webstorage"
android:title="@string/clear_web_storage" />
android:title="@string/clear_web_storage"/>
</PreferenceCategory>
</PreferenceScreen>

2
build.gradle

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
@ -6,6 +5,7 @@ buildscript { @@ -6,6 +5,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7'
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.2.1'
}
}

Loading…
Cancel
Save