Browse Source

New Full-screen mode works better and doesn't hide the top of the WebView, +other

* Now using material alertdialog on all versions
* cleaned up some code
* fixed lint issues and other inspection related problems
* Attempted to fix bugs found
master
Anthony Restaino 9 years ago
parent
commit
969cab81e7
  1. 2
      Lightning-Browser.iml
  2. 20
      app/app.iml
  3. 5
      app/build.gradle
  4. 2
      app/src/LightningPlus/java/acr/browser/lightning/utils/ProxyUtils.java
  5. 2
      app/src/main/java/acr/browser/lightning/activity/AppCompatPreferenceActivity.java
  6. 5033
      app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java
  7. 109
      app/src/main/java/acr/browser/lightning/activity/IncognitoActivity.java
  8. 104
      app/src/main/java/acr/browser/lightning/activity/MainActivity.java
  9. 442
      app/src/main/java/acr/browser/lightning/activity/ReadingActivity.java
  10. 2
      app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java
  11. 4
      app/src/main/java/acr/browser/lightning/activity/ThemableActivity.java
  12. 11
      app/src/main/java/acr/browser/lightning/activity/ThemableSettingsActivity.java
  13. 4
      app/src/main/java/acr/browser/lightning/controller/BrowserController.java
  14. 770
      app/src/main/java/acr/browser/lightning/database/BookmarkManager.java
  15. 4
      app/src/main/java/acr/browser/lightning/database/HistoryDatabase.java
  16. 369
      app/src/main/java/acr/browser/lightning/download/DownloadHandler.java
  17. 140
      app/src/main/java/acr/browser/lightning/download/FetchUrlMimeType.java
  18. 5
      app/src/main/java/acr/browser/lightning/download/LightningDownloadListener.java
  19. 2
      app/src/main/java/acr/browser/lightning/fragment/AdvancedSettingsFragment.java
  20. 60
      app/src/main/java/acr/browser/lightning/fragment/BookmarkSettingsFragment.java
  21. 13
      app/src/main/java/acr/browser/lightning/fragment/DisplaySettingsFragment.java
  22. 14
      app/src/main/java/acr/browser/lightning/fragment/GeneralSettingsFragment.java
  23. 9
      app/src/main/java/acr/browser/lightning/fragment/PrivacySettingsFragment.java
  24. 789
      app/src/main/java/acr/browser/lightning/object/SearchAdapter.java
  25. 2
      app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java
  26. 15
      app/src/main/java/acr/browser/lightning/reading/ArticleTextExtractor.java
  27. 2
      app/src/main/java/acr/browser/lightning/reading/Converter.java
  28. 2
      app/src/main/java/acr/browser/lightning/reading/HtmlFetcher.java
  29. 9
      app/src/main/java/acr/browser/lightning/reading/SHelper.java
  30. 2
      app/src/main/java/acr/browser/lightning/utils/IntentUtils.java
  31. 34
      app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java
  32. 37
      app/src/main/java/acr/browser/lightning/utils/Utils.java
  33. 2195
      app/src/main/java/acr/browser/lightning/view/LightningView.java
  34. 20
      app/src/main/res/layout/picker_manual_proxy.xml
  35. 2
      app/src/main/res/layout/toolbar_content.xml
  36. 11
      app/src/main/res/layout/two_line_autocomplete.xml
  37. 3
      app/src/main/res/values-v21/styles.xml
  38. 5
      app/src/main/res/values/styles.xml

2
Lightning-Browser.iml

@ -8,7 +8,7 @@
</configuration> </configuration>
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" /> <excludeFolder url="file://$MODULE_DIR$/.gradle" />

20
app/app.iml

@ -12,10 +12,12 @@
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleLightningPlusDebug" /> <option name="ASSEMBLE_TASK_NAME" value="assembleLightningPlusDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileLightningPlusDebugSources" /> <option name="COMPILE_JAVA_TASK_NAME" value="compileLightningPlusDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateLightningPlusDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleLightningPlusDebugAndroidTest" /> <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleLightningPlusDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileLightningPlusDebugAndroidTestSources" /> <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileLightningPlusDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateLightningPlusDebugAndroidTestSources" /> <afterSyncTasks>
<task>generateLightningPlusDebugAndroidTestSources</task>
<task>generateLightningPlusDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
@ -24,7 +26,7 @@
</configuration> </configuration>
</facet> </facet>
</component> </component>
<component name="NewModuleRootManager" inherit-compiler-output="false"> <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/lightningPlus/debug" /> <output url="file://$MODULE_DIR$/build/intermediates/classes/lightningPlus/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/lightningPlus/debug" /> <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/lightningPlus/debug" />
<exclude-output /> <exclude-output />
@ -48,13 +50,13 @@
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/lightningPlus/debug" isTestSource="true" generated="true" /> <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/lightningPlus/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/lightningPlus/debug" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/lightningPlus/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/lightningPlus/debug" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/lightningPlus/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/res" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/resources" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/assets" type="java-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/aidl" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/java" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/jni" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/LightningPlus/rs" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src/lightningPlus/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/res" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/resources" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/assets" type="java-test-resource" /> <sourceFolder url="file://$MODULE_DIR$/src/androidTestLightningPlus/assets" type="java-test-resource" />
@ -109,7 +111,7 @@
<excludeFolder url="file://$MODULE_DIR$/build/outputs" /> <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" /> <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content> </content>
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" /> <orderEntry type="jdk" jdkName="Android API 22 Platform (1)" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="client-0.7" level="project" /> <orderEntry type="library" exported="" name="client-0.7" level="project" />
<orderEntry type="library" exported="" name="palette-v7-22.2.0" level="project" /> <orderEntry type="library" exported="" name="palette-v7-22.2.0" level="project" />

5
app/build.gradle

@ -12,8 +12,8 @@ android {
buildTypes { buildTypes {
debug { debug {
minifyEnabled true minifyEnabled false
shrinkResources true shrinkResources false
proguardFiles 'proguard-project.txt' proguardFiles 'proguard-project.txt'
} }
@ -48,6 +48,7 @@ dependencies {
compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:appcompat-v7:22.2.0'
compile 'org.jsoup:jsoup:1.8.1' compile 'org.jsoup:jsoup:1.8.1'
// Only Lightning Plus needs the proxy libraries
lightningPlusCompile 'net.i2p.android:client:0.7' lightningPlusCompile 'net.i2p.android:client:0.7'
lightningPlusCompile(project(':libnetcipher')) lightningPlusCompile(project(':libnetcipher'))
} }

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

@ -1,9 +1,9 @@
package acr.browser.lightning.utils; package acr.browser.lightning.utils;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log; import android.util.Log;
import net.i2p.android.ui.I2PAndroidHelper; import net.i2p.android.ui.I2PAndroidHelper;

2
app/src/main/java/acr/browser/lightning/activity/AppCompatPreferenceActivity.java

@ -4,6 +4,7 @@ import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceActivity; import android.preference.PreferenceActivity;
import android.support.annotation.LayoutRes; import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
@ -44,6 +45,7 @@ public abstract class AppCompatPreferenceActivity extends PreferenceActivity {
getDelegate().setSupportActionBar(toolbar); getDelegate().setSupportActionBar(toolbar);
} }
@NonNull
@Override @Override
public MenuInflater getMenuInflater() { public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater(); return getDelegate().getMenuInflater();

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

File diff suppressed because it is too large Load Diff

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

@ -13,69 +13,66 @@ import acr.browser.lightning.R;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class IncognitoActivity extends BrowserActivity { public class IncognitoActivity extends BrowserActivity {
private CookieManager mCookieManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void updateCookiePreference() {
super.onCreate(savedInstanceState); CookieManager cookieManager = CookieManager.getInstance();
} if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(this);
}
cookieManager.setAcceptCookie(PreferenceManager.getInstance().getIncognitoCookiesEnabled());
super.updateCookiePreference();
}
@Override @Override
public void updateCookiePreference() { public synchronized void initializeTabs() {
mCookieManager = CookieManager.getInstance(); super.initializeTabs();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // restoreOrNewTab();
CookieSyncManager.createInstance(this); newTab(null, true);
} // if incognito mode use newTab(null, true); instead
mCookieManager }
.setAcceptCookie(PreferenceManager.getInstance().getIncognitoCookiesEnabled());
super.updateCookiePreference();
}
@Override @Override
public synchronized void initializeTabs() { public boolean onCreateOptionsMenu(Menu menu) {
super.initializeTabs(); getMenuInflater().inflate(R.menu.incognito, menu);
// restoreOrNewTab(); return super.onCreateOptionsMenu(menu);
newTab(null, true); }
// if incognito mode use newTab(null, true); instead
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { protected void onNewIntent(Intent intent) {
getMenuInflater().inflate(R.menu.incognito, menu); // handleNewIntent(intent);
return super.onCreateOptionsMenu(menu); super.onNewIntent(intent);
} }
@Override @Override
protected void onNewIntent(Intent intent) { protected void onPause() {
// handleNewIntent(intent); super.onPause();
super.onNewIntent(intent); // saveOpenTabs();
} }
@Override @Override
protected void onPause() { public void updateHistory(String title, String url) {
super.onPause(); super.updateHistory(title, url);
// saveOpenTabs(); // addItemToHistory(title, url);
} }
@Override @Override
public void updateHistory(String title, String url) { public boolean isIncognito() {
super.updateHistory(title, url); return true;
// addItemToHistory(title, url); }
}
@Override @Override
public boolean isIncognito() { public void closeActivity() {
return true; closeDrawers();
} finish();
}
@Override @Override
public void closeActivity() { public int getMenu() {
closeDrawers(); return R.menu.incognito;
finish(); }
}
@Override
public int getMenu() {
return R.menu.incognito;
}
} }

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

@ -13,66 +13,64 @@ import acr.browser.lightning.R;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class MainActivity extends BrowserActivity { public class MainActivity extends BrowserActivity {
private CookieManager mCookieManager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { public void updateCookiePreference() {
super.onCreate(savedInstanceState); CookieManager cookieManager = CookieManager.getInstance();
} if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(this);
}
cookieManager.setAcceptCookie(PreferenceManager.getInstance().getCookiesEnabled());
super.updateCookiePreference();
}
@Override @Override
public void updateCookiePreference() { public synchronized void initializeTabs() {
mCookieManager = CookieManager.getInstance(); restoreOrNewTab();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // if incognito mode use newTab(null, true); instead
CookieSyncManager.createInstance(this); }
}
mCookieManager.setAcceptCookie(PreferenceManager.getInstance().getCookiesEnabled());
super.updateCookiePreference();
}
@Override @Override
public synchronized void initializeTabs() { public boolean onCreateOptionsMenu(Menu menu) {
restoreOrNewTab(); getMenuInflater().inflate(R.menu.main, menu);
// if incognito mode use newTab(null, true); instead return super.onCreateOptionsMenu(menu);
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { protected void onNewIntent(Intent intent) {
getMenuInflater().inflate(R.menu.main, menu); handleNewIntent(intent);
return super.onCreateOptionsMenu(menu); super.onNewIntent(intent);
} }
@Override @Override
protected void onNewIntent(Intent intent) { protected void onPause() {
handleNewIntent(intent); super.onPause();
super.onNewIntent(intent); saveOpenTabs();
} }
@Override @Override
protected void onPause() { public void updateHistory(String title, String url) {
super.onPause(); super.updateHistory(title, url);
saveOpenTabs(); addItemToHistory(title, url);
} }
@Override @Override
public void updateHistory(String title, String url) { public boolean isIncognito() {
super.updateHistory(title, url); return false;
addItemToHistory(title, url); }
}
@Override @Override
public boolean isIncognito() { public int getMenu() {
return false; return R.menu.main;
} }
@Override @Override
public int getMenu() { public void closeActivity() {
return R.menu.main; closeDrawers();
} moveTaskToBack(true);
}
@Override
public void closeActivity() {
closeDrawers();
moveTaskToBack(true);
}
} }

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

@ -1,7 +1,6 @@
package acr.browser.lightning.activity; package acr.browser.lightning.activity;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -9,6 +8,7 @@ import android.content.DialogInterface.OnClickListener;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -31,223 +31,225 @@ import acr.browser.lightning.utils.Utils;
public class ReadingActivity extends AppCompatActivity { public class ReadingActivity extends AppCompatActivity {
private TextView mTitle; private TextView mTitle;
private TextView mBody; private TextView mBody;
private boolean mInvert; private boolean mInvert;
private String mUrl = null; private String mUrl = null;
private PreferenceManager mPreferences; private PreferenceManager mPreferences;
private int mTextSize; private int mTextSize;
private static final float XXLARGE = 30.0f; private static final float XXLARGE = 30.0f;
private static final float XLARGE = 26.0f; private static final float XLARGE = 26.0f;
private static final float LARGE = 22.0f; private static final float LARGE = 22.0f;
private static final float MEDIUM = 18.0f; private static final float MEDIUM = 18.0f;
private static final float SMALL = 14.0f; private static final float SMALL = 14.0f;
private static final float XSMALL = 10.0f; private static final float XSMALL = 10.0f;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
mPreferences = PreferenceManager.getInstance(); mPreferences = PreferenceManager.getInstance();
mInvert = mPreferences.getInvertColors(); mInvert = mPreferences.getInvertColors();
if (mInvert) { if (mInvert) {
this.setTheme(R.style.Theme_SettingsTheme_Dark); this.setTheme(R.style.Theme_SettingsTheme_Dark);
} }
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.reading_view); setContentView(R.layout.reading_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (getSupportActionBar() != null)
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mTitle = (TextView) findViewById(R.id.textViewTitle);
mBody = (TextView) findViewById(R.id.textViewBody); mTitle = (TextView) findViewById(R.id.textViewTitle);
mBody = (TextView) findViewById(R.id.textViewBody);
mTextSize = mPreferences.getReadingTextSize();
mBody.setTextSize(getTextSize(mTextSize)); mTextSize = mPreferences.getReadingTextSize();
mTitle.setText(getString(R.string.untitled)); mBody.setTextSize(getTextSize(mTextSize));
mBody.setText(getString(R.string.loading)); mTitle.setText(getString(R.string.untitled));
mBody.setText(getString(R.string.loading));
mTitle.setVisibility(View.INVISIBLE);
mBody.setVisibility(View.INVISIBLE); mTitle.setVisibility(View.INVISIBLE);
mBody.setVisibility(View.INVISIBLE);
Intent intent = getIntent();
if (!loadPage(intent)) { Intent intent = getIntent();
setText(getString(R.string.untitled), getString(R.string.loading_failed)); if (!loadPage(intent)) {
} setText(getString(R.string.untitled), getString(R.string.loading_failed));
} }
}
private float getTextSize(int size) {
switch (size) { private float getTextSize(int size) {
case 0: switch (size) {
return XSMALL; case 0:
case 1: return XSMALL;
return SMALL; case 1:
case 2: return SMALL;
return MEDIUM; case 2:
case 3: return MEDIUM;
return LARGE; case 3:
case 4: return LARGE;
return XLARGE; case 4:
case 5: return XLARGE;
return XXLARGE; case 5:
default: return XXLARGE;
return MEDIUM; default:
} return MEDIUM;
} }
}
@Override
public boolean onCreateOptionsMenu(Menu menu) { @Override
getMenuInflater().inflate(R.menu.reading, menu); public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.reading, menu);
} return super.onCreateOptionsMenu(menu);
}
protected boolean loadPage(Intent intent) {
if (intent == null) { private boolean loadPage(Intent intent) {
return false; if (intent == null) {
} return false;
mUrl = intent.getStringExtra(Constants.LOAD_READING_URL); }
if (mUrl == null) { mUrl = intent.getStringExtra(Constants.LOAD_READING_URL);
return false; if (mUrl == null) {
} return false;
getSupportActionBar().setTitle(Utils.getDomainName(mUrl)); }
new PageLoader(this).execute(mUrl); if (getSupportActionBar() != null)
return true; getSupportActionBar().setTitle(Utils.getDomainName(mUrl));
} new PageLoader(this).execute(mUrl);
return true;
private class PageLoader extends AsyncTask<String, Void, Void> { }
private final Context mContext; private class PageLoader extends AsyncTask<String, Void, Void> {
private ProgressDialog mProgressDialog;
private String mTitleText; private final Context mContext;
private List<String> mBodyText; private ProgressDialog mProgressDialog;
private String mTitleText;
public PageLoader(Context context) { private List<String> mBodyText;
mContext = context;
} public PageLoader(Context context) {
mContext = context;
@Override }
protected void onPreExecute() {
super.onPreExecute(); @Override
mProgressDialog = new ProgressDialog(mContext); protected void onPreExecute() {
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); super.onPreExecute();
mProgressDialog.setCancelable(false); mProgressDialog = new ProgressDialog(mContext);
mProgressDialog.setIndeterminate(true); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setMessage(mContext.getString(R.string.loading)); mProgressDialog.setCancelable(false);
mProgressDialog.show(); mProgressDialog.setIndeterminate(true);
} mProgressDialog.setMessage(mContext.getString(R.string.loading));
mProgressDialog.show();
@Override }
protected Void doInBackground(String... params) {
@Override
HtmlFetcher fetcher = new HtmlFetcher(); protected Void doInBackground(String... params) {
try {
JResult result = fetcher.fetchAndExtract(params[0], 2500, true); HtmlFetcher fetcher = new HtmlFetcher();
mTitleText = result.getTitle(); try {
mBodyText = result.getTextList(); JResult result = fetcher.fetchAndExtract(params[0], 2500, true);
} catch (Exception e) { mTitleText = result.getTitle();
mTitleText = ""; mBodyText = result.getTextList();
mBodyText = new ArrayList<>(); } catch (Exception e) {
e.printStackTrace(); mTitleText = "";
} catch (OutOfMemoryError e) { mBodyText = new ArrayList<>();
System.gc(); e.printStackTrace();
mTitleText = ""; } catch (OutOfMemoryError e) {
mBodyText = new ArrayList<>(); System.gc();
e.printStackTrace(); mTitleText = "";
} mBodyText = new ArrayList<>();
return null; e.printStackTrace();
} }
return null;
@Override }
protected void onPostExecute(Void result) {
mProgressDialog.dismiss(); @Override
if (mTitleText.isEmpty() || mBodyText.isEmpty()) { protected void onPostExecute(Void result) {
setText(getString(R.string.untitled), getString(R.string.loading_failed)); mProgressDialog.dismiss();
} else { if (mTitleText.isEmpty() || mBodyText.isEmpty()) {
StringBuilder builder = new StringBuilder(); setText(getString(R.string.untitled), getString(R.string.loading_failed));
for (String text : mBodyText) { } else {
builder.append(text).append("\n\n"); StringBuilder builder = new StringBuilder();
} for (String text : mBodyText) {
setText(mTitleText, builder.toString()); builder.append(text).append("\n\n");
} }
super.onPostExecute(result); setText(mTitleText, builder.toString());
} }
super.onPostExecute(result);
} }
private void setText(String title, String body) { }
if (mTitle.getVisibility() == View.INVISIBLE) {
mTitle.setAlpha(0.0f); private void setText(String title, String body) {
mTitle.setVisibility(View.VISIBLE); if (mTitle.getVisibility() == View.INVISIBLE) {
mTitle.setText(title); mTitle.setAlpha(0.0f);
ObjectAnimator animator = ObjectAnimator.ofFloat(mTitle, "alpha", 1.0f); mTitle.setVisibility(View.VISIBLE);
animator.setDuration(300); mTitle.setText(title);
animator.start(); ObjectAnimator animator = ObjectAnimator.ofFloat(mTitle, "alpha", 1.0f);
} else { animator.setDuration(300);
mTitle.setText(title); animator.start();
} } else {
mTitle.setText(title);
if (mBody.getVisibility() == View.INVISIBLE) { }
mBody.setAlpha(0.0f);
mBody.setVisibility(View.VISIBLE); if (mBody.getVisibility() == View.INVISIBLE) {
mBody.setText(body); mBody.setAlpha(0.0f);
ObjectAnimator animator = ObjectAnimator.ofFloat(mBody, "alpha", 1.0f); mBody.setVisibility(View.VISIBLE);
animator.setDuration(300); mBody.setText(body);
animator.start(); ObjectAnimator animator = ObjectAnimator.ofFloat(mBody, "alpha", 1.0f);
} else { animator.setDuration(300);
mBody.setText(body); animator.start();
} } else {
} mBody.setText(body);
}
@Override }
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { @Override
case R.id.invert_item: public boolean onOptionsItemSelected(MenuItem item) {
mPreferences.setInvertColors(!mInvert); switch (item.getItemId()) {
Intent read = new Intent(this, ReadingActivity.class); case R.id.invert_item:
read.putExtra(Constants.LOAD_READING_URL, mUrl); mPreferences.setInvertColors(!mInvert);
startActivity(read); Intent read = new Intent(this, ReadingActivity.class);
finish(); read.putExtra(Constants.LOAD_READING_URL, mUrl);
break; startActivity(read);
case R.id.text_size_item: finish();
AlertDialog.Builder builder = new AlertDialog.Builder(this); break;
LayoutInflater inflater = this.getLayoutInflater(); case R.id.text_size_item:
View view = inflater.inflate(R.layout.seek_layout, null); AlertDialog.Builder builder = new AlertDialog.Builder(this);
final SeekBar bar = (SeekBar) view.findViewById(R.id.text_size_seekbar); LayoutInflater inflater = this.getLayoutInflater();
bar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { View view = inflater.inflate(R.layout.seek_layout, null);
final SeekBar bar = (SeekBar) view.findViewById(R.id.text_size_seekbar);
@Override bar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar view, int size, boolean user) {
mBody.setTextSize(getTextSize(size)); @Override
} public void onProgressChanged(SeekBar view, int size, boolean user) {
mBody.setTextSize(getTextSize(size));
@Override }
public void onStartTrackingTouch(SeekBar arg0) {
} @Override
public void onStartTrackingTouch(SeekBar arg0) {
@Override }
public void onStopTrackingTouch(SeekBar arg0) {
} @Override
public void onStopTrackingTouch(SeekBar arg0) {
}); }
bar.setMax(5);
bar.setProgress(mTextSize); });
builder.setView(view); bar.setMax(5);
builder.setTitle(R.string.size); bar.setProgress(mTextSize);
builder.setPositiveButton(android.R.string.ok, new OnClickListener() { builder.setView(view);
builder.setTitle(R.string.size);
@Override builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
mTextSize = bar.getProgress(); @Override
mBody.setTextSize(getTextSize(mTextSize)); public void onClick(DialogInterface arg0, int arg1) {
mPreferences.setReadingTextSize(bar.getProgress()); mTextSize = bar.getProgress();
} mBody.setTextSize(getTextSize(mTextSize));
mPreferences.setReadingTextSize(bar.getProgress());
}); }
builder.show();
break; });
default: builder.show();
finish(); break;
break; default:
} finish();
return super.onOptionsItemSelected(item); break;
} }
return super.onOptionsItemSelected(item);
}
} }

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

@ -17,7 +17,7 @@ import acr.browser.lightning.R;
public class SettingsActivity extends ThemableSettingsActivity { public class SettingsActivity extends ThemableSettingsActivity {
private static List<String> fragments = new ArrayList<>(); private static final List<String> fragments = new ArrayList<>();
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {

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

@ -33,9 +33,7 @@ public abstract class ThemableActivity extends AppCompatActivity {
} }
protected void restart() { protected void restart() {
final Bundle outState = new Bundle(); Intent intent = getIntent();
onSaveInstanceState(outState);
final Intent intent = new Intent(this, getClass());
finish(); finish();
overridePendingTransition(0, 0); overridePendingTransition(0, 0);
startActivity(intent); startActivity(intent);

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

@ -6,8 +6,9 @@ import android.os.Bundle;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.ThemeUtils;
public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivity { public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivity {
private int mTheme; private int mTheme;
@ -16,11 +17,15 @@ public abstract class ThemableSettingsActivity extends AppCompatPreferenceActivi
mTheme = PreferenceManager.getInstance().getUseTheme(); mTheme = PreferenceManager.getInstance().getUseTheme();
// set the theme // set the theme
if (mTheme == 1) { if (mTheme == 0) {
setTheme(R.style.Theme_SettingsTheme);
this.getWindow().setBackgroundDrawable(new ColorDrawable(ThemeUtils.getPrimaryColor(this)));
} else if (mTheme == 1) {
setTheme(R.style.Theme_SettingsTheme_Dark); setTheme(R.style.Theme_SettingsTheme_Dark);
this.getWindow().setBackgroundDrawable(new ColorDrawable(ThemeUtils.getPrimaryColorDark(this)));
} else if (mTheme == 2) { } else if (mTheme == 2) {
setTheme(R.style.Theme_SettingsTheme_Black); setTheme(R.style.Theme_SettingsTheme_Black);
this.getWindow().setBackgroundDrawable(new ColorDrawable(this.getResources().getColor(R.color.black))); this.getWindow().setBackgroundDrawable(new ColorDrawable(ThemeUtils.getPrimaryColorDark(this)));
} }
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }

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

@ -26,7 +26,7 @@ public interface BrowserController {
void onLongPress(); void onLongPress();
void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback); void onShowCustomView(View view, CustomViewCallback callback);
void onHideCustomView(); void onHideCustomView();
@ -34,7 +34,7 @@ public interface BrowserController {
View getVideoLoadingProgressView(); View getVideoLoadingProgressView();
void onCreateWindow(boolean isUserGesture, Message resultMsg); void onCreateWindow(Message resultMsg);
Activity getActivity(); Activity getActivity();

770
app/src/main/java/acr/browser/lightning/database/BookmarkManager.java

@ -30,398 +30,422 @@ import acr.browser.lightning.utils.Utils;
public class BookmarkManager { public class BookmarkManager {
private final Context mContext; private final Context mContext;
private static final String TITLE = "title"; private static final String TITLE = "title";
private static final String URL = "url"; private static final String URL = "url";
private static final String FOLDER = "folder"; private static final String FOLDER = "folder";
private static final String ORDER = "order"; private static final String ORDER = "order";
private static final String FILE_BOOKMARKS = "bookmarks.dat"; private static final String FILE_BOOKMARKS = "bookmarks.dat";
private static SortedMap<String, Integer> mBookmarkMap = new TreeMap<>( private static SortedMap<String, Integer> mBookmarkMap = new TreeMap<>(
String.CASE_INSENSITIVE_ORDER); String.CASE_INSENSITIVE_ORDER);
private static BookmarkManager mInstance; private static BookmarkManager mInstance;
public static BookmarkManager getInstance(Context context) { public static BookmarkManager getInstance(Context context) {
if (mInstance == null) { if (mInstance == null) {
mInstance = new BookmarkManager(context); mInstance = new BookmarkManager(context);
} }
return mInstance; return mInstance;
} }
private BookmarkManager(Context context) { private BookmarkManager(Context context) {
mContext = context; mContext = context;
mBookmarkMap = getBookmarkUrls(); mBookmarkMap = getBookmarkUrls();
} }
/** /**
* This method adds the the HistoryItem item to permanent bookmark storage * This method adds the the HistoryItem item to permanent bookmark storage
* *
* @param item * @param item the item to add
*/ */
public synchronized boolean addBookmark(HistoryItem item) { public synchronized boolean addBookmark(HistoryItem item) {
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
if (item.getUrl() == null || mBookmarkMap.containsKey(item.getUrl())) { if (item.getUrl() == null || mBookmarkMap.containsKey(item.getUrl())) {
return false; return false;
} }
try { BufferedWriter bookmarkWriter = null;
BufferedWriter bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true)); try {
JSONObject object = new JSONObject(); bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true));
object.put(TITLE, item.getTitle()); JSONObject object = new JSONObject();
object.put(URL, item.getUrl()); object.put(TITLE, item.getTitle());
object.put(FOLDER, item.getFolder()); object.put(URL, item.getUrl());
object.put(ORDER, item.getOrder()); object.put(FOLDER, item.getFolder());
bookmarkWriter.write(object.toString()); object.put(ORDER, item.getOrder());
bookmarkWriter.newLine(); bookmarkWriter.write(object.toString());
bookmarkWriter.close(); bookmarkWriter.newLine();
mBookmarkMap.put(item.getUrl(), 1); bookmarkWriter.close();
} catch (IOException | JSONException e) { mBookmarkMap.put(item.getUrl(), 1);
e.printStackTrace(); } catch (IOException | JSONException e) {
} e.printStackTrace();
return true; } finally {
} Utils.close(bookmarkWriter);
}
return true;
}
/** /**
* This method adds the list of HistoryItems to permanent bookmark storage * This method adds the list of HistoryItems to permanent bookmark storage
* *
* @param list * @param list the list of HistoryItems to add to bookmarks
*/ */
public synchronized void addBookmarkList(List<HistoryItem> list) { private synchronized void addBookmarkList(List<HistoryItem> list) {
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try { BufferedWriter bookmarkWriter = null;
BufferedWriter bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true)); try {
for (HistoryItem item : list) { bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, true));
if (item.getUrl() != null && !mBookmarkMap.containsKey(item.getUrl())) { JSONObject object = new JSONObject();
JSONObject object = new JSONObject(); for (HistoryItem item : list) {
object.put(TITLE, item.getTitle()); if (item.getUrl() != null && !mBookmarkMap.containsKey(item.getUrl())) {
object.put(URL, item.getUrl()); object.put(TITLE, item.getTitle());
object.put(FOLDER, item.getFolder()); object.put(URL, item.getUrl());
object.put(ORDER, item.getOrder()); object.put(FOLDER, item.getFolder());
bookmarkWriter.write(object.toString()); object.put(ORDER, item.getOrder());
bookmarkWriter.newLine(); bookmarkWriter.write(object.toString());
mBookmarkMap.put(item.getUrl(), 1); bookmarkWriter.newLine();
} mBookmarkMap.put(item.getUrl(), 1);
} }
bookmarkWriter.close(); }
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); e.printStackTrace();
} } finally {
} Utils.close(bookmarkWriter);
}
}
/** /**
* This method deletes the bookmark with the given url * This method deletes the bookmark with the given url
* *
* @param url * @param url the url of the bookmark to delete
*/ */
public synchronized boolean deleteBookmark(String url) { public synchronized boolean deleteBookmark(String url) {
List<HistoryItem> list; List<HistoryItem> list;
if (url == null) { if (url == null) {
return false; return false;
} }
mBookmarkMap.remove(url); mBookmarkMap.remove(url);
list = getBookmarks(false); list = getBookmarks(false);
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
boolean bookmarkDeleted = false; boolean bookmarkDeleted = false;
try { BufferedWriter fileWriter = null;
BufferedWriter fileWriter = new BufferedWriter(new FileWriter(bookmarksFile, false)); try {
for (HistoryItem item : list) { fileWriter = new BufferedWriter(new FileWriter(bookmarksFile, false));
if (!item.getUrl().equalsIgnoreCase(url)) { JSONObject object = new JSONObject();
JSONObject object = new JSONObject(); for (HistoryItem item : list) {
object.put(TITLE, item.getTitle()); if (!item.getUrl().equalsIgnoreCase(url)) {
object.put(URL, item.getUrl()); object.put(TITLE, item.getTitle());
object.put(FOLDER, item.getFolder()); object.put(URL, item.getUrl());
object.put(ORDER, item.getOrder()); object.put(FOLDER, item.getFolder());
fileWriter.write(object.toString()); object.put(ORDER, item.getOrder());
fileWriter.newLine(); fileWriter.write(object.toString());
} else { fileWriter.newLine();
bookmarkDeleted = true; } else {
} bookmarkDeleted = true;
} }
fileWriter.close(); }
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); e.printStackTrace();
} } finally {
return bookmarkDeleted; Utils.close(fileWriter);
} }
return bookmarkDeleted;
}
/** /**
* This method exports the stored bookmarks to a text file in the device's * This method exports the stored bookmarks to a text file in the device's
* external download directory * external download directory
*/ */
public synchronized void exportBookmarks() { public synchronized void exportBookmarks() {
List<HistoryItem> bookmarkList = getBookmarks(true); List<HistoryItem> bookmarkList = getBookmarks(true);
File bookmarksExport = new File( File bookmarksExport = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"BookmarksExport.txt"); "BookmarksExport.txt");
int counter = 0; int counter = 0;
while (bookmarksExport.exists()) { while (bookmarksExport.exists()) {
counter++; counter++;
bookmarksExport = new File( bookmarksExport = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"BookmarksExport-" + counter + ".txt"); "BookmarksExport-" + counter + ".txt");
} }
try { BufferedWriter bookmarkWriter = null;
BufferedWriter bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksExport, try {
false)); bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksExport,
for (HistoryItem item : bookmarkList) { false));
JSONObject object = new JSONObject(); JSONObject object = new JSONObject();
object.put(TITLE, item.getTitle()); for (HistoryItem item : bookmarkList) {
object.put(URL, item.getUrl()); object.put(TITLE, item.getTitle());
object.put(FOLDER, item.getFolder()); object.put(URL, item.getUrl());
object.put(ORDER, item.getOrder()); object.put(FOLDER, item.getFolder());
bookmarkWriter.write(object.toString()); object.put(ORDER, item.getOrder());
bookmarkWriter.newLine(); bookmarkWriter.write(object.toString());
} bookmarkWriter.newLine();
bookmarkWriter.close(); }
Toast.makeText( if (mContext != null)
mContext, Toast.makeText(
mContext.getString(R.string.bookmark_export_path) + " " mContext,
+ bookmarksExport.getPath(), Toast.LENGTH_SHORT).show(); mContext.getString(R.string.bookmark_export_path) + ' '
} catch (IOException | JSONException e) { + bookmarksExport.getPath(), Toast.LENGTH_SHORT).show();
e.printStackTrace(); } catch (IOException | JSONException e) {
} e.printStackTrace();
} finally {
Utils.close(bookmarkWriter);
}
} }
/** /**
* This method returns a list of all stored bookmarks * This method returns a list of all stored bookmarks
* *
* @return * @return returns a list of bookmarks that can be sorted
*/ */
public synchronized List<HistoryItem> getBookmarks(boolean sort) { public synchronized List<HistoryItem> getBookmarks(boolean sort) {
List<HistoryItem> bookmarks = new ArrayList<>(); List<HistoryItem> bookmarks = new ArrayList<>();
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try { BufferedReader bookmarksReader = null;
BufferedReader bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); try {
String line; bookmarksReader = new BufferedReader(new FileReader(bookmarksFile));
while ((line = bookmarksReader.readLine()) != null) { String line;
JSONObject object = new JSONObject(line); while ((line = bookmarksReader.readLine()) != null) {
HistoryItem item = new HistoryItem(); JSONObject object = new JSONObject(line);
item.setTitle(object.getString(TITLE)); HistoryItem item = new HistoryItem();
item.setUrl(object.getString(URL)); item.setTitle(object.getString(TITLE));
item.setFolder(object.getString(FOLDER)); item.setUrl(object.getString(URL));
item.setOrder(object.getInt(ORDER)); item.setFolder(object.getString(FOLDER));
item.setImageId(R.drawable.ic_bookmark); item.setOrder(object.getInt(ORDER));
bookmarks.add(item); item.setImageId(R.drawable.ic_bookmark);
} bookmarks.add(item);
bookmarksReader.close(); }
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); e.printStackTrace();
} } finally {
if (sort) { Utils.close(bookmarksReader);
Collections.sort(bookmarks, new SortIgnoreCase()); }
} if (sort) {
return bookmarks; Collections.sort(bookmarks, new SortIgnoreCase());
} }
return bookmarks;
}
/** /**
* This method returns a list of bookmarks located in the specified folder * This method returns a list of bookmarks located in the specified folder
* *
* @param folder * @param folder the name of the folder to retrieve bookmarks from
* @return * @return a list of bookmarks found in that folder
*/ */
public synchronized List<HistoryItem> getBookmarksFromFolder(String folder) { public synchronized List<HistoryItem> getBookmarksFromFolder(String folder) {
List<HistoryItem> bookmarks = new ArrayList<>(); List<HistoryItem> bookmarks = new ArrayList<>();
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try { BufferedReader bookmarksReader = null;
BufferedReader bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); try {
String line; bookmarksReader = new BufferedReader(new FileReader(bookmarksFile));
while ((line = bookmarksReader.readLine()) != null) { String line;
JSONObject object = new JSONObject(line); while ((line = bookmarksReader.readLine()) != null) {
if (object.getString(FOLDER).equals(folder)) { JSONObject object = new JSONObject(line);
HistoryItem item = new HistoryItem(); if (object.getString(FOLDER).equals(folder)) {
item.setTitle(object.getString(TITLE)); HistoryItem item = new HistoryItem();
item.setUrl(object.getString(URL)); item.setTitle(object.getString(TITLE));
item.setFolder(object.getString(FOLDER)); item.setUrl(object.getString(URL));
item.setOrder(object.getInt(ORDER)); item.setFolder(object.getString(FOLDER));
item.setImageId(R.drawable.ic_bookmark); item.setOrder(object.getInt(ORDER));
bookmarks.add(item); item.setImageId(R.drawable.ic_bookmark);
} bookmarks.add(item);
} }
bookmarksReader.close(); }
} catch (IOException | JSONException e) { bookmarksReader.close();
e.printStackTrace(); } catch (IOException | JSONException e) {
} e.printStackTrace();
return bookmarks; } finally {
} Utils.close(bookmarksReader);
}
return bookmarks;
}
/** /**
* Method is used internally for searching the bookmarks * Method is used internally for searching the bookmarks
* *
* @return * @return a sorted map of all bookmarks, useful for seeing if a bookmark exists
*/ */
private synchronized SortedMap<String, Integer> getBookmarkUrls() { private synchronized SortedMap<String, Integer> getBookmarkUrls() {
SortedMap<String, Integer> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); SortedMap<String, Integer> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try { BufferedReader bookmarksReader = null;
BufferedReader bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); try {
String line; bookmarksReader = new BufferedReader(new FileReader(bookmarksFile));
while ((line = bookmarksReader.readLine()) != null) { String line;
JSONObject object = new JSONObject(line); while ((line = bookmarksReader.readLine()) != null) {
map.put(object.getString(URL), 1); JSONObject object = new JSONObject(line);
} map.put(object.getString(URL), 1);
bookmarksReader.close(); }
} catch (JSONException | IOException e) { bookmarksReader.close();
e.printStackTrace(); } catch (JSONException | IOException e) {
} e.printStackTrace();
return map; } finally {
} Utils.close(bookmarksReader);
}
return map;
}
/** /**
* This method returns a list of all folders * This method returns a list of all folders
* *
* @return * @return a list of all folders
*/ */
public synchronized List<HistoryItem> getFolders() { public synchronized List<HistoryItem> getFolders() {
List<HistoryItem> folders = new ArrayList<>(); List<HistoryItem> folders = new ArrayList<>();
SortedMap<String, Integer> folderMap = new TreeMap<>( SortedMap<String, Integer> folderMap = new TreeMap<>(
String.CASE_INSENSITIVE_ORDER); String.CASE_INSENSITIVE_ORDER);
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS); File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try { BufferedReader bookmarksReader = null;
BufferedReader bookmarksReader = new BufferedReader(new FileReader(bookmarksFile)); try {
String line; bookmarksReader = new BufferedReader(new FileReader(bookmarksFile));
while ((line = bookmarksReader.readLine()) != null) { String line;
JSONObject object = new JSONObject(line); while ((line = bookmarksReader.readLine()) != null) {
String folderName = object.getString(FOLDER); JSONObject object = new JSONObject(line);
if (!folderName.isEmpty() && !folderMap.containsKey(folderName)) { String folderName = object.getString(FOLDER);
HistoryItem item = new HistoryItem(); if (!folderName.isEmpty() && !folderMap.containsKey(folderName)) {
item.setTitle(folderName); HistoryItem item = new HistoryItem();
item.setUrl(Constants.FOLDER + folderName); item.setTitle(folderName);
folderMap.put(folderName, 1); item.setUrl(Constants.FOLDER + folderName);
folders.add(item); folderMap.put(folderName, 1);
} folders.add(item);
} }
bookmarksReader.close(); }
} catch (IOException | JSONException e) { } catch (IOException | JSONException e) {
e.printStackTrace(); e.printStackTrace();
} } finally {
return folders; Utils.close(bookmarksReader);
} }
return folders;
}
/** /**
* This method imports all bookmarks that are included in the device's * This method imports all bookmarks that are included in the device's
* permanent bookmark storage * permanent bookmark storage
*/ */
public synchronized void importBookmarksFromBrowser(Context context) { public synchronized void importBookmarksFromBrowser(Context context) {
if (PreferenceManager.getInstance().getSystemBrowserPresent()) { if (PreferenceManager.getInstance().getSystemBrowserPresent()) {
List<HistoryItem> bookmarkList = new ArrayList<>(); List<HistoryItem> bookmarkList = new ArrayList<>();
String[] columns = new String[] { Browser.BookmarkColumns.TITLE, String[] columns = new String[]{Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL }; Browser.BookmarkColumns.URL};
String selection = Browser.BookmarkColumns.BOOKMARK + " = 1"; String selection = Browser.BookmarkColumns.BOOKMARK + " = 1";
Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI, columns, Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI, columns,
selection, null, null); selection, null, null);
if (cursor == null)
return;
String title, url;
int number = 0;
if (cursor.moveToFirst()) {
do {
title = cursor.getString(0);
url = cursor.getString(1);
if (title.isEmpty()) {
title = Utils.getDomainName(url);
}
number++;
bookmarkList.add(new HistoryItem(url, title));
} while (cursor.moveToNext());
}
String title, url; cursor.close();
int number = 0; addBookmarkList(bookmarkList);
if (cursor.moveToFirst()) {
do {
title = cursor.getString(0);
url = cursor.getString(1);
if (title.isEmpty()) {
title = Utils.getDomainName(url);
}
number++;
bookmarkList.add(new HistoryItem(url, title));
} while (cursor.moveToNext());
}
cursor.close(); Utils.showToast(context,
addBookmarkList(bookmarkList); number + " " + mContext.getResources().getString(R.string.message_import));
} else {
Utils.createInformativeDialog(context,
mContext.getResources().getString(R.string.title_error), mContext
.getResources().getString(R.string.dialog_import_error));
}
}
Utils.showToast(mContext, /**
number + " " + mContext.getResources().getString(R.string.message_import)); * This method imports the bookmarks from a backup file that is located on
} else { * external storage
Utils.createInformativeDialog(context, *
mContext.getResources().getString(R.string.title_error), mContext * @param file the file to attempt to import bookmarks from
.getResources().getString(R.string.dialog_import_error)); */
} public synchronized void importBookmarksFromFile(File file, Context context) {
} if (file == null) {
return;
}
List<HistoryItem> list = new ArrayList<>();
BufferedReader bookmarksReader = null;
try {
bookmarksReader = new BufferedReader(new FileReader(file));
String line;
int number = 0;
while ((line = bookmarksReader.readLine()) != null) {
JSONObject object = new JSONObject(line);
HistoryItem item = new HistoryItem();
item.setTitle(object.getString(TITLE));
item.setUrl(object.getString(URL));
item.setFolder(object.getString(FOLDER));
item.setOrder(object.getInt(ORDER));
list.add(item);
number++;
}
addBookmarkList(list);
Utils.showToast(context,
number + " " + mContext.getResources().getString(R.string.message_import));
} catch (IOException | JSONException e) {
e.printStackTrace();
Utils.createInformativeDialog(context,
mContext.getResources().getString(R.string.title_error), mContext
.getResources().getString(R.string.import_bookmark_error));
} finally {
Utils.close(bookmarksReader);
}
}
/** /**
* This method imports the bookmarks from a backup file that is located on * This method overwrites the entire bookmark file with the list of
* external storage * bookmarks. This is useful when an edit has been made to one or more
* * bookmarks in the list
* @param dir *
* @param file * @param list the list of bookmarks to overwrite the old ones with
*/ */
public synchronized void importBookmarksFromFile(File file, Context context) { public synchronized void overwriteBookmarks(List<HistoryItem> list) {
if (file == null) { File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
return; BufferedWriter bookmarkWriter = null;
} try {
List<HistoryItem> list = new ArrayList<>(); bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, false));
try { JSONObject object = new JSONObject();
BufferedReader bookmarksReader = new BufferedReader(new FileReader(file)); for (HistoryItem item : list) {
String line; object.put(TITLE, item.getTitle());
int number = 0; object.put(URL, item.getUrl());
while ((line = bookmarksReader.readLine()) != null) { object.put(FOLDER, item.getFolder());
JSONObject object = new JSONObject(line); object.put(ORDER, item.getOrder());
HistoryItem item = new HistoryItem(); bookmarkWriter.write(object.toString());
item.setTitle(object.getString(TITLE)); bookmarkWriter.newLine();
item.setUrl(object.getString(URL)); }
item.setFolder(object.getString(FOLDER)); } catch (IOException | JSONException e) {
item.setOrder(object.getInt(ORDER)); e.printStackTrace();
list.add(item); } finally {
number++; Utils.close(bookmarkWriter);
} }
bookmarksReader.close(); }
addBookmarkList(list);
Utils.showToast(mContext,
number + " " + mContext.getResources().getString(R.string.message_import));
} catch (IOException | JSONException e) {
e.printStackTrace();
Utils.createInformativeDialog(context,
mContext.getResources().getString(R.string.title_error), mContext
.getResources().getString(R.string.import_bookmark_error));
}
}
/** private class SortIgnoreCase implements Comparator<HistoryItem> {
* This method overwrites the entire bookmark file with the list of
* bookmarks. This is useful when an edit has been made to one or more
* bookmarks in the list
*
* @param list
*/
public synchronized void overwriteBookmarks(List<HistoryItem> list) {
File bookmarksFile = new File(mContext.getFilesDir(), FILE_BOOKMARKS);
try {
BufferedWriter bookmarkWriter = new BufferedWriter(new FileWriter(bookmarksFile, false));
for (HistoryItem item : list) {
JSONObject object = new JSONObject();
object.put(TITLE, item.getTitle());
object.put(URL, item.getUrl());
object.put(FOLDER, item.getFolder());
object.put(ORDER, item.getOrder());
bookmarkWriter.write(object.toString());
bookmarkWriter.newLine();
}
bookmarkWriter.close();
} catch (IOException | JSONException e) {
e.printStackTrace();
}
}
private class SortIgnoreCase implements Comparator<HistoryItem> { public int compare(HistoryItem o1, HistoryItem o2) {
if (o1 == null || o2 == null || o1.getTitle() == null || o2.getTitle() == null) {
return 0;
}
return o1.getTitle().toLowerCase(Locale.getDefault())
.compareTo(o2.getTitle().toLowerCase(Locale.getDefault()));
}
public int compare(HistoryItem o1, HistoryItem o2) { }
if (o1 == null || o2 == null || o1.getTitle() == null || o2.getTitle() == null) {
return 0;
}
return o1.getTitle().toLowerCase(Locale.getDefault())
.compareTo(o2.getTitle().toLowerCase(Locale.getDefault()));
}
} private static final String[] DEV = {"https://twitter.com/RestainoAnthony", "The Developer"};
private static final String[] FACEBOOK = {"https://www.facebook.com/", "Facebook"};
private static final String[] DEV = {"https://twitter.com/RestainoAnthony", "The Developer"}; private static final String[] TWITTER = {"https://twitter.com", "Twitter"};
private static final String[] FACEBOOK = {"https://www.facebook.com/", "Facebook"}; private static final String[] GOOGLE = {"https://www.google.com/", "Google"};
private static final String[] TWITTER = {"https://twitter.com", "Twitter"}; private static final String[] YAHOO = {"https://www.yahoo.com/", "Yahoo"};
private static final String[] GOOGLE = {"https://www.google.com/", "Google"}; public static final String[][] DEFAULT_BOOKMARKS = {
private static final String[] YAHOO = {"https://www.yahoo.com/", "Yahoo"}; DEV,
public static final String[][] DEFAULT_BOOKMARKS = { FACEBOOK,
DEV, TWITTER,
FACEBOOK, GOOGLE,
TWITTER, YAHOO
GOOGLE, };
YAHOO
};
} }

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

@ -65,7 +65,7 @@ public class HistoryDatabase extends SQLiteOpenHelper {
onCreate(db); onCreate(db);
} }
public boolean isClosed() { private boolean isClosed() {
return mDatabase == null || !mDatabase.isOpen(); return mDatabase == null || !mDatabase.isOpen();
} }
@ -95,7 +95,7 @@ public class HistoryDatabase extends SQLiteOpenHelper {
q.close(); q.close();
} }
public synchronized void addHistoryItem(HistoryItem item) { private synchronized void addHistoryItem(HistoryItem item) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(KEY_URL, item.getUrl()); values.put(KEY_URL, item.getUrl());
values.put(KEY_TITLE, item.getTitle()); values.put(KEY_TITLE, item.getTitle());

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

@ -4,7 +4,6 @@
package acr.browser.lightning.download; package acr.browser.lightning.download;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.app.DownloadManager; import android.app.DownloadManager;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
import android.content.ComponentName; import android.content.ComponentName;
@ -14,6 +13,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Environment; import android.os.Environment;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.webkit.CookieManager; import android.webkit.CookieManager;
@ -22,197 +22,190 @@ import android.widget.Toast;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
/** /**
* Handle download requests * Handle download requests
*/ */
public class DownloadHandler { public class DownloadHandler {
private static final String LOGTAG = "DLHandler"; private static final String LOGTAG = "DLHandler";
/** /**
* Notify the host application a download should be done, or that the data * Notify the host application a download should be done, or that the data
* should be streamed if a streaming viewer is available. * should be streamed if a streaming viewer is available.
* *
* @param activity * @param activity Activity requesting the download.
* Activity requesting the download. * @param url The full url to the content that should be downloaded
* @param url * @param userAgent User agent of the downloading application.
* The full url to the content that should be downloaded * @param contentDisposition Content-disposition http header, if present.
* @param userAgent * @param mimetype The mimetype of the content reported by the server
* User agent of the downloading application. */
* @param contentDisposition public static void onDownloadStart(Activity activity, String url, String userAgent,
* Content-disposition http header, if present. String contentDisposition, String mimetype) {
* @param mimetype // if we're dealing wih A/V content that's not explicitly marked
* The mimetype of the content reported by the server // for download, check if it's streamable.
* @param privateBrowsing if (contentDisposition == null
* If the request is coming from a private browsing tab. || !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) {
*/ // query the package manager to see if there's a registered handler
public static void onDownloadStart(Activity activity, String url, String userAgent, // that matches.
String contentDisposition, String mimetype, boolean privateBrowsing) { Intent intent = new Intent(Intent.ACTION_VIEW);
// if we're dealing wih A/V content that's not explicitly marked intent.setDataAndType(Uri.parse(url), mimetype);
// for download, check if it's streamable. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (contentDisposition == null ResolveInfo info = activity.getPackageManager().resolveActivity(intent,
|| !contentDisposition.regionMatches(true, 0, "attachment", 0, 10)) { PackageManager.MATCH_DEFAULT_ONLY);
// query the package manager to see if there's a registered handler if (info != null) {
// that matches. ComponentName myName = activity.getComponentName();
Intent intent = new Intent(Intent.ACTION_VIEW); // If we resolved to ourselves, we don't want to attempt to
intent.setDataAndType(Uri.parse(url), mimetype); // load the url only to try and download it again.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (!myName.getPackageName().equals(info.activityInfo.packageName)
ResolveInfo info = activity.getPackageManager().resolveActivity(intent, || !myName.getClassName().equals(info.activityInfo.name)) {
PackageManager.MATCH_DEFAULT_ONLY); // someone (other than us) knows how to handle this mime
if (info != null) { // type with this scheme, don't download.
ComponentName myName = activity.getComponentName(); try {
// If we resolved to ourselves, we don't want to attempt to activity.startActivity(intent);
// load the url only to try and download it again. return;
if (!myName.getPackageName().equals(info.activityInfo.packageName) } catch (ActivityNotFoundException ex) {
|| !myName.getClassName().equals(info.activityInfo.name)) { // Best behavior is to fall back to a download in this
// someone (other than us) knows how to handle this mime // case
// type with this scheme, don't download. }
try { }
activity.startActivity(intent); }
return; }
} catch (ActivityNotFoundException ex) { onDownloadStartNoStream(activity, url, userAgent, contentDisposition, mimetype
// Best behavior is to fall back to a download in this );
// case }
}
} // This is to work around the fact that java.net.URI throws Exceptions
} // instead of just encoding URL's properly
} // Helper method for onDownloadStartNoStream
onDownloadStartNoStream(activity, url, userAgent, contentDisposition, mimetype, private static String encodePath(String path) {
privateBrowsing); char[] chars = path.toCharArray();
}
boolean needed = false;
// This is to work around the fact that java.net.URI throws Exceptions for (char c : chars) {
// instead of just encoding URL's properly if (c == '[' || c == ']' || c == '|') {
// Helper method for onDownloadStartNoStream needed = true;
private static String encodePath(String path) { break;
char[] chars = path.toCharArray(); }
}
boolean needed = false; if (!needed) {
for (char c : chars) { return path;
if (c == '[' || c == ']' || c == '|') { }
needed = true;
break; StringBuilder sb = new StringBuilder("");
} for (char c : chars) {
} if (c == '[' || c == ']' || c == '|') {
if (!needed) { sb.append('%');
return path; sb.append(Integer.toHexString(c));
} } else {
sb.append(c);
StringBuilder sb = new StringBuilder(""); }
for (char c : chars) { }
if (c == '[' || c == ']' || c == '|') {
sb.append('%'); return sb.toString();
sb.append(Integer.toHexString(c)); }
} else {
sb.append(c); /**
} * Notify the host application a download should be done, even if there is a
} * streaming viewer available for thise type.
*
return sb.toString(); * @param activity Activity requesting the download.
} * @param url The full url to the content that should be downloaded
* @param userAgent User agent of the downloading application.
/** * @param contentDisposition Content-disposition http header, if present.
* Notify the host application a download should be done, even if there is a * @param mimetype The mimetype of the content reported by the server
* streaming viewer available for thise type. */
* /* package */
* @param activity private static void onDownloadStartNoStream(final Activity activity, String url, String userAgent,
* Activity requesting the download. String contentDisposition, String mimetype) {
* @param url
* The full url to the content that should be downloaded String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
* @param userAgent
* User agent of the downloading application. // Check to see if we have an SDCard
* @param contentDisposition String status = Environment.getExternalStorageState();
* Content-disposition http header, if present. if (!status.equals(Environment.MEDIA_MOUNTED)) {
* @param mimetype int title;
* The mimetype of the content reported by the server String msg;
* @param privateBrowsing
* If the request is coming from a private browsing tab. // Check to see if the SDCard is busy, same as the music app
*/ if (status.equals(Environment.MEDIA_SHARED)) {
/* package */ msg = activity.getString(R.string.download_sdcard_busy_dlg_msg);
private static void onDownloadStartNoStream(Activity activity, String url, String userAgent, title = R.string.download_sdcard_busy_dlg_title;
String contentDisposition, String mimetype, boolean privateBrowsing) { } else {
msg = activity.getString(R.string.download_no_sdcard_dlg_msg, filename);
String filename = URLUtil.guessFileName(url, contentDisposition, mimetype); title = R.string.download_no_sdcard_dlg_title;
}
// Check to see if we have an SDCard
String status = Environment.getExternalStorageState(); new AlertDialog.Builder(activity).setTitle(title)
if (!status.equals(Environment.MEDIA_MOUNTED)) { .setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg)
int title; .setPositiveButton(R.string.action_ok, null).show();
String msg; return;
}
// Check to see if the SDCard is busy, same as the music app
if (status.equals(Environment.MEDIA_SHARED)) { // java.net.URI is a lot stricter than KURL so we have to encode some
msg = activity.getString(R.string.download_sdcard_busy_dlg_msg); // extra characters. Fix for b 2538060 and b 1634719
title = R.string.download_sdcard_busy_dlg_title; WebAddress webAddress;
} else { try {
msg = activity.getString(R.string.download_no_sdcard_dlg_msg, filename); webAddress = new WebAddress(url);
title = R.string.download_no_sdcard_dlg_title; webAddress.setPath(encodePath(webAddress.getPath()));
} } catch (Exception e) {
// This only happens for very bad urls, we want to catch the
new AlertDialog.Builder(activity).setTitle(title) // exception here
.setIcon(android.R.drawable.ic_dialog_alert).setMessage(msg) Log.e(LOGTAG, "Exception while trying to parse url '" + url + '\'', e);
.setPositiveButton(R.string.action_ok, null).show(); return;
return; }
}
String addressString = webAddress.toString();
// java.net.URI is a lot stricter than KURL so we have to encode some Uri uri = Uri.parse(addressString);
// extra characters. Fix for b 2538060 and b 1634719 final DownloadManager.Request request;
WebAddress webAddress; try {
try { request = new DownloadManager.Request(uri);
webAddress = new WebAddress(url); } catch (IllegalArgumentException e) {
webAddress.setPath(encodePath(webAddress.getPath())); Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show();
} catch (Exception e) { return;
// This only happens for very bad urls, we want to catch the }
// exception here request.setMimeType(mimetype);
Log.e(LOGTAG, "Exception while trying to parse url '" + url + '\'', e); // set downloaded file destination to /sdcard/Download.
return; // or, should it be set to one of several Environment.DIRECTORY* dirs
} // depending on mimetype?
String addressString = webAddress.toString(); String location = PreferenceManager.getInstance().getDownloadDirectory();
Uri uri = Uri.parse(addressString); request.setDestinationInExternalPublicDir(location, filename);
final DownloadManager.Request request; // let this downloaded file be scanned by MediaScanner - so that it can
try { // show up in Gallery app, for example.
request = new DownloadManager.Request(uri); request.allowScanningByMediaScanner();
} catch (IllegalArgumentException e) { request.setDescription(webAddress.getHost());
Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show(); // XXX: Have to use the old url since the cookies were stored using the
return; // old percent-encoded url.
} String cookies = CookieManager.getInstance().getCookie(url);
request.setMimeType(mimetype); request.addRequestHeader("cookie", cookies);
// set downloaded file destination to /sdcard/Download. request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// or, should it be set to one of several Environment.DIRECTORY* dirs if (mimetype == null) {
// depending on mimetype? if (TextUtils.isEmpty(addressString)) {
return;
String location = PreferenceManager.getInstance().getDownloadDirectory(); }
request.setDestinationInExternalPublicDir(location, filename); // We must have long pressed on a link or image to download it. We
// let this downloaded file be scanned by MediaScanner - so that it can // are not sure of the mimetype in this case, so do a head request
// show up in Gallery app, for example. new FetchUrlMimeType(activity, request, addressString, cookies, userAgent).start();
request.allowScanningByMediaScanner(); } else {
request.setDescription(webAddress.getHost()); final DownloadManager manager = (DownloadManager) activity
// XXX: Have to use the old url since the cookies were stored using the .getSystemService(Context.DOWNLOAD_SERVICE);
// old percent-encoded url. new Thread("Browser download") {
String cookies = CookieManager.getInstance().getCookie(url); @Override
request.addRequestHeader("cookie", cookies); public void run() {
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); try {
if (mimetype == null) { manager.enqueue(request);
if (TextUtils.isEmpty(addressString)) { } catch (IllegalArgumentException e) {
return; // Probably got a bad URL or something
} e.printStackTrace();
// We must have long pressed on a link or image to download it. We Utils.showToast(activity, R.string.cannot_download);
// are not sure of the mimetype in this case, so do a head request }
new FetchUrlMimeType(activity, request, addressString, cookies, userAgent).start(); }
} else { }.start();
final DownloadManager manager = (DownloadManager) activity Toast.makeText(activity, R.string.download_pending, Toast.LENGTH_SHORT).show();
.getSystemService(Context.DOWNLOAD_SERVICE); }
new Thread("Browser download") {
@Override }
public void run() {
manager.enqueue(request);
}
}.start();
Toast.makeText(activity, R.string.download_pending, Toast.LENGTH_SHORT).show();
}
}
} }

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

@ -26,82 +26,82 @@ import acr.browser.lightning.R;
*/ */
public class FetchUrlMimeType extends Thread { public class FetchUrlMimeType extends Thread {
private final Context mContext; private final Context mContext;
private final DownloadManager.Request mRequest; private final DownloadManager.Request mRequest;
private final String mUri; private final String mUri;
private final String mCookies; private final String mCookies;
private final String mUserAgent; private final String mUserAgent;
public FetchUrlMimeType(Context context, DownloadManager.Request request, String uri, public FetchUrlMimeType(Context context, DownloadManager.Request request, String uri,
String cookies, String userAgent) { String cookies, String userAgent) {
mContext = context.getApplicationContext(); mContext = context.getApplicationContext();
mRequest = request; mRequest = request;
mUri = uri; mUri = uri;
mCookies = cookies; mCookies = cookies;
mUserAgent = userAgent; mUserAgent = userAgent;
Toast.makeText(mContext, R.string.download_pending, Toast.LENGTH_SHORT).show(); Toast.makeText(mContext, R.string.download_pending, Toast.LENGTH_SHORT).show();
} }
@Override @Override
public void run() { public void run() {
// User agent is likely to be null, though the AndroidHttpClient // User agent is likely to be null, though the AndroidHttpClient
// seems ok with that. // seems ok with that.
String mimeType = null; String mimeType = null;
String contentDisposition = null; String contentDisposition = null;
HttpURLConnection connection = null; HttpURLConnection connection = null;
try { try {
URL url = new URL(mUri); URL url = new URL(mUri);
connection = (HttpURLConnection) url.openConnection(); connection = (HttpURLConnection) url.openConnection();
if (mCookies != null && mCookies.length() > 0) { if (mCookies != null && mCookies.length() > 0) {
connection.addRequestProperty("Cookie", mCookies); connection.addRequestProperty("Cookie", mCookies);
connection.setRequestProperty("User-Agent", mUserAgent); connection.setRequestProperty("User-Agent", mUserAgent);
} }
connection.connect(); connection.connect();
// We could get a redirect here, but if we do lets let // We could get a redirect here, but if we do lets let
// the download manager take care of it, and thus trust that // the download manager take care of it, and thus trust that
// the server sends the right mimetype // the server sends the right mimetype
if (connection.getResponseCode() == 200) { if (connection.getResponseCode() == 200) {
String header = connection.getHeaderField("Content-Type"); String header = connection.getHeaderField("Content-Type");
if (header != null) { if (header != null) {
mimeType = header; mimeType = header;
final int semicolonIndex = mimeType.indexOf(';'); final int semicolonIndex = mimeType.indexOf(';');
if (semicolonIndex != -1) { if (semicolonIndex != -1) {
mimeType = mimeType.substring(0, semicolonIndex); mimeType = mimeType.substring(0, semicolonIndex);
} }
} }
String contentDispositionHeader = connection.getHeaderField("Content-Disposition"); String contentDispositionHeader = connection.getHeaderField("Content-Disposition");
if (contentDispositionHeader != null) { if (contentDispositionHeader != null) {
contentDisposition = contentDispositionHeader; contentDisposition = contentDispositionHeader;
} }
} }
} catch (IllegalArgumentException | IOException ex) { } catch (IllegalArgumentException | IOException ex) {
if (connection != null) if (connection != null)
connection.disconnect(); connection.disconnect();
} finally { } finally {
if (connection != null) if (connection != null)
connection.disconnect(); connection.disconnect();
} }
if (mimeType != null) { if (mimeType != null) {
if (mimeType.equalsIgnoreCase("text/plain") if (mimeType.equalsIgnoreCase("text/plain")
|| mimeType.equalsIgnoreCase("application/octet-stream")) { || mimeType.equalsIgnoreCase("application/octet-stream")) {
String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension( String newMimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
MimeTypeMap.getFileExtensionFromUrl(mUri)); MimeTypeMap.getFileExtensionFromUrl(mUri));
if (newMimeType != null) { if (newMimeType != null) {
mRequest.setMimeType(newMimeType); mRequest.setMimeType(newMimeType);
} }
} }
String filename = URLUtil.guessFileName(mUri, contentDisposition, mimeType); String filename = URLUtil.guessFileName(mUri, contentDisposition, mimeType);
mRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename); mRequest.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
} }
// Start the download // Start the download
DownloadManager manager = (DownloadManager) mContext DownloadManager manager = (DownloadManager) mContext
.getSystemService(Context.DOWNLOAD_SERVICE); .getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(mRequest); manager.enqueue(mRequest);
} }
} }

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

@ -4,15 +4,14 @@
package acr.browser.lightning.download; package acr.browser.lightning.download;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.util.Log; import android.util.Log;
import android.webkit.DownloadListener; import android.webkit.DownloadListener;
import android.webkit.URLUtil; import android.webkit.URLUtil;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.constant.Constants; import acr.browser.lightning.constant.Constants;
import acr.browser.lightning.download.DownloadHandler;
public class LightningDownloadListener implements DownloadListener { public class LightningDownloadListener implements DownloadListener {
@ -32,7 +31,7 @@ public class LightningDownloadListener implements DownloadListener {
switch (which) { switch (which) {
case DialogInterface.BUTTON_POSITIVE: case DialogInterface.BUTTON_POSITIVE:
DownloadHandler.onDownloadStart(mActivity, url, userAgent, DownloadHandler.onDownloadStart(mActivity, url, userAgent,
contentDisposition, mimetype, false); contentDisposition, mimetype);
break; break;
case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEGATIVE:

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

@ -4,12 +4,12 @@
package acr.browser.lightning.fragment; package acr.browser.lightning.fragment;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;

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

@ -4,13 +4,12 @@
package acr.browser.lightning.fragment; package acr.browser.lightning.fragment;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
@ -27,12 +26,10 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
private static final String SETTINGS_BROWSER_IMPORT = "import_browser_bookmark"; private static final String SETTINGS_BROWSER_IMPORT = "import_browser_bookmark";
private Activity mActivity; private Activity mActivity;
private PreferenceManager mPreferences;
private BookmarkManager mBookmarkManager; private BookmarkManager mBookmarkManager;
private File[] mFileList; private File[] mFileList;
private String[] mFileNameList; private String[] mFileNameList;
private static final File mPath = new File(Environment.getExternalStorageDirectory().toString()); private static final File mPath = new File(Environment.getExternalStorageDirectory().toString());
private static final int DIALOG_LOAD_FILE = 1000;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -42,14 +39,14 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
mActivity = getActivity(); mActivity = getActivity();
mBookmarkManager = BookmarkManager.getInstance(mActivity); mBookmarkManager = BookmarkManager.getInstance(mActivity.getApplicationContext());
initPrefs(); initPrefs();
} }
private void initPrefs() { private void initPrefs() {
// mPreferences storage // mPreferences storage
mPreferences = PreferenceManager.getInstance(); PreferenceManager mPreferences = PreferenceManager.getInstance();
Preference exportpref = findPreference(SETTINGS_EXPORT); Preference exportpref = findPreference(SETTINGS_EXPORT);
Preference importpref = findPreference(SETTINGS_IMPORT); Preference importpref = findPreference(SETTINGS_IMPORT);
@ -74,10 +71,10 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
return true; return true;
case SETTINGS_IMPORT: case SETTINGS_IMPORT:
loadFileList(null); loadFileList(null);
onCreateDialog(DIALOG_LOAD_FILE); createDialog();
return true; return true;
case SETTINGS_BROWSER_IMPORT: case SETTINGS_BROWSER_IMPORT:
mBookmarkManager.importBookmarksFromBrowser(mActivity); mBookmarkManager.importBookmarksFromBrowser(getActivity());
return true; return true;
default: default:
return false; return false;
@ -135,34 +132,29 @@ public class BookmarkSettingsFragment extends PreferenceFragment implements Pref
} }
} }
protected Dialog onCreateDialog(int id) { protected void createDialog() {
Dialog dialog;
final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
switch (id) { final String title = getString(R.string.title_chooser);
case DIALOG_LOAD_FILE: builder.setTitle(title + ": " + Environment.getExternalStorageDirectory());
builder.setTitle(R.string.title_chooser); if (mFileList == null) {
if (mFileList == null) { builder.show();
dialog = builder.create();
return dialog;
}
builder.setItems(mFileNameList, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (mFileList[which].isDirectory()) {
loadFileList(mFileList[which]);
builder.setItems(mFileNameList, this);
builder.show();
} else {
mBookmarkManager.importBookmarksFromFile(mFileList[which], mActivity);
}
}
});
break;
} }
dialog = builder.show(); builder.setItems(mFileNameList, new DialogInterface.OnClickListener() {
return dialog;
@Override
public void onClick(DialogInterface dialog, int which) {
if (mFileList[which].isDirectory()) {
builder.setTitle(title + ": " + mFileList[which]);
loadFileList(mFileList[which]);
builder.setItems(mFileNameList, this);
builder.show();
} else {
mBookmarkManager.importBookmarksFromFile(mFileList[which], getActivity());
}
}
});
builder.show();
} }
} }

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

@ -4,15 +4,14 @@
package acr.browser.lightning.fragment; package acr.browser.lightning.fragment;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.activity.SettingsActivity;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
public class DisplaySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener { public class DisplaySettingsFragment extends PreferenceFragment implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
@ -28,7 +27,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
private Activity mActivity; private Activity mActivity;
private PreferenceManager mPreferences; private PreferenceManager mPreferences;
private CheckBoxPreference cbstatus, cbfullscreen, cbviewport, cboverview, cbreflow; private CheckBoxPreference cbstatus, cbfullscreen, cbviewport, cboverview, cbreflow;
private Preference theme, textsize; private Preference theme;
private String[] mThemeOptions; private String[] mThemeOptions;
private int mCurrentTheme; private int mCurrentTheme;
@ -50,7 +49,7 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
mCurrentTheme = mPreferences.getUseTheme(); mCurrentTheme = mPreferences.getUseTheme();
theme = findPreference(SETTINGS_THEME); theme = findPreference(SETTINGS_THEME);
textsize = findPreference(SETTINGS_TEXTSIZE); Preference textsize = findPreference(SETTINGS_TEXTSIZE);
cbstatus = (CheckBoxPreference) findPreference(SETTINGS_HIDESTATUSBAR); cbstatus = (CheckBoxPreference) findPreference(SETTINGS_HIDESTATUSBAR);
cbfullscreen = (CheckBoxPreference) findPreference(SETTINGS_FULLSCREEN); cbfullscreen = (CheckBoxPreference) findPreference(SETTINGS_FULLSCREEN);
cbviewport = (CheckBoxPreference) findPreference(SETTINGS_VIEWPORT); cbviewport = (CheckBoxPreference) findPreference(SETTINGS_VIEWPORT);
@ -163,7 +162,8 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (mCurrentTheme != mPreferences.getUseTheme()) { if (mCurrentTheme != mPreferences.getUseTheme()) {
((SettingsActivity) getActivity()).restart(); // ((SettingsActivity) getActivity()).restart();
getActivity().onBackPressed();
} }
} }
}); });
@ -171,7 +171,8 @@ public class DisplaySettingsFragment extends PreferenceFragment implements Prefe
@Override @Override
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
if (mCurrentTheme != mPreferences.getUseTheme()) { if (mCurrentTheme != mPreferences.getUseTheme()) {
((SettingsActivity) getActivity()).restart(); // ((SettingsActivity) getActivity()).restart();
getActivity().onBackPressed();
} }
} }
}); });

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

@ -4,14 +4,16 @@
package acr.browser.lightning.fragment; package acr.browser.lightning.fragment;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.support.v7.app.AlertDialog;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.View; import android.view.View;
@ -468,10 +470,16 @@ public class GeneralSettingsFragment extends PreferenceFragment implements Prefe
v.setPadding(padding, padding, 0, padding); v.setPadding(padding, padding, 0, padding);
layout.addView(v); layout.addView(v);
layout.addView(getDownload); layout.addView(getDownload);
if (API < 16) { if (API < Build.VERSION_CODES.JELLY_BEAN) {
layout.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.edit_text)); layout.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.edit_text));
} else { } else {
layout.setBackground(getResources().getDrawable(android.R.drawable.edit_text)); Drawable drawable;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable = getResources().getDrawable(android.R.drawable.edit_text, getActivity().getTheme());
} else {
drawable = getResources().getDrawable(android.R.drawable.edit_text);
}
layout.setBackground(drawable);
} }
downLocationPicker.setView(layout); downLocationPicker.setView(layout);
downLocationPicker.setPositiveButton(getResources().getString(R.string.action_ok), downLocationPicker.setPositiveButton(getResources().getString(R.string.action_ok),

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

@ -4,7 +4,6 @@
package acr.browser.lightning.fragment; package acr.browser.lightning.fragment;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Build; import android.os.Build;
@ -15,6 +14,7 @@ import android.preference.CheckBoxPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.provider.Browser; import android.provider.Browser;
import android.support.v7.app.AlertDialog;
import android.webkit.CookieManager; import android.webkit.CookieManager;
import android.webkit.CookieSyncManager; import android.webkit.CookieSyncManager;
import android.webkit.WebIconDatabase; import android.webkit.WebIconDatabase;
@ -45,7 +45,6 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
private PreferenceManager mPreferences; private PreferenceManager mPreferences;
private CheckBoxPreference cblocation, cb3cookies, cbsavepasswords, cbcacheexit, cbhistoryexit, private CheckBoxPreference cblocation, cb3cookies, cbsavepasswords, cbcacheexit, cbhistoryexit,
cbcookiesexit, cbsynchistory; cbcookiesexit, cbsynchistory;
private Preference clearcache, clearhistory, clearcookies;
private boolean mSystemBrowser; private boolean mSystemBrowser;
private Handler messageHandler; private Handler messageHandler;
@ -65,9 +64,9 @@ public class PrivacySettingsFragment extends PreferenceFragment implements Prefe
mPreferences = PreferenceManager.getInstance(); mPreferences = PreferenceManager.getInstance();
mSystemBrowser = mPreferences.getSystemBrowserPresent(); mSystemBrowser = mPreferences.getSystemBrowserPresent();
clearcache = findPreference(SETTINGS_CLEARCACHE); Preference clearcache = findPreference(SETTINGS_CLEARCACHE);
clearhistory = findPreference(SETTINGS_CLEARHISTORY); Preference clearhistory = findPreference(SETTINGS_CLEARHISTORY);
clearcookies = findPreference(SETTINGS_CLEARCOOKIES); Preference clearcookies = findPreference(SETTINGS_CLEARCOOKIES);
cblocation = (CheckBoxPreference) findPreference(SETTINGS_LOCATION); cblocation = (CheckBoxPreference) findPreference(SETTINGS_LOCATION);
cb3cookies = (CheckBoxPreference) findPreference(SETTINGS_THIRDPCOOKIES); cb3cookies = (CheckBoxPreference) findPreference(SETTINGS_THIRDPCOOKIES);
cbsavepasswords = (CheckBoxPreference) findPreference(SETTINGS_SAVEPASSWORD); cbsavepasswords = (CheckBoxPreference) findPreference(SETTINGS_SAVEPASSWORD);

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

@ -1,23 +1,5 @@
package acr.browser.lightning.object; package acr.browser.lightning.object;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
@ -36,399 +18,398 @@ import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import acr.browser.lightning.R; import acr.browser.lightning.R;
import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.BookmarkManager;
import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryDatabase;
import acr.browser.lightning.database.HistoryItem; import acr.browser.lightning.database.HistoryItem;
import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.preference.PreferenceManager;
import acr.browser.lightning.utils.Utils;
public class SearchAdapter extends BaseAdapter implements Filterable { public class SearchAdapter extends BaseAdapter implements Filterable {
private List<HistoryItem> mHistory; private final List<HistoryItem> mHistory = new ArrayList<>();
private List<HistoryItem> mBookmarks; private final List<HistoryItem> mBookmarks = new ArrayList<>();
private List<HistoryItem> mSuggestions; private final List<HistoryItem> mSuggestions = new ArrayList<>();
private List<HistoryItem> mFilteredList; private final List<HistoryItem> mFilteredList = new ArrayList<>();
private List<HistoryItem> mAllBookmarks; private final List<HistoryItem> mAllBookmarks = new ArrayList<>();
private HistoryDatabase mDatabaseHandler; private HistoryDatabase mDatabaseHandler;
private final Context mContext; private final Context mContext;
private boolean mUseGoogle = true; private boolean mUseGoogle = true;
private boolean mIsExecuting = false; private boolean mIsExecuting = false;
private final boolean mDarkTheme; private final boolean mDarkTheme;
private final boolean mIncognito; private final boolean mIncognito;
private final BookmarkManager mBookmarkManager; private final BookmarkManager mBookmarkManager;
private static final String ENCODING = "ISO-8859-1"; private static final String ENCODING = "ISO-8859-1";
private static final long INTERVAL_DAY = 86400000; private static final long INTERVAL_DAY = 86400000;
private final String mSearchSubtitle; private final String mSearchSubtitle;
private static final int API = Build.VERSION.SDK_INT; private static final int API = Build.VERSION.SDK_INT;
private final Theme mTheme; private final Theme mTheme;
private SearchFilter mFilter; private SearchFilter mFilter;
public SearchAdapter(Context context, boolean dark, boolean incognito) { public SearchAdapter(Context context, boolean dark, boolean incognito) {
mDatabaseHandler = HistoryDatabase.getInstance(context.getApplicationContext()); mDatabaseHandler = HistoryDatabase.getInstance(context.getApplicationContext());
mTheme = context.getTheme(); mTheme = context.getTheme();
mFilteredList = new ArrayList<>(); mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext());
mHistory = new ArrayList<>(); mAllBookmarks.addAll(mBookmarkManager.getBookmarks(true));
mBookmarks = new ArrayList<>(); mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
mSuggestions = new ArrayList<>(); mContext = context;
mBookmarkManager = BookmarkManager.getInstance(context.getApplicationContext()); mSearchSubtitle = mContext.getString(R.string.suggestion);
mAllBookmarks = mBookmarkManager.getBookmarks(true); mDarkTheme = dark || incognito;
mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled(); mIncognito = incognito;
mContext = context; Thread delete = new Thread(new Runnable() {
mSearchSubtitle = mContext.getString(R.string.suggestion);
mDarkTheme = dark || incognito; @Override
mIncognito = incognito; public void run() {
Thread delete = new Thread(new Runnable() { deleteOldCacheFiles(mContext);
}
@Override
public void run() { });
deleteOldCacheFiles(mContext); delete.start();
} }
}); private void deleteOldCacheFiles(Context context) {
delete.start(); File dir = new File(context.getCacheDir().toString());
} String[] fileList = dir.list(new NameFilter());
long earliestTimeAllowed = System.currentTimeMillis() - INTERVAL_DAY;
private void deleteOldCacheFiles(Context context) { for (String fileName : fileList) {
File dir = new File(context.getCacheDir().toString()); File file = new File(dir.getPath() + fileName);
String[] fileList = dir.list(new NameFilter()); if (earliestTimeAllowed > file.lastModified()) {
long earliestTimeAllowed = System.currentTimeMillis() - INTERVAL_DAY; file.delete();
for (String fileName : fileList) { }
File file = new File(dir.getPath() + fileName); }
if (earliestTimeAllowed > file.lastModified()) { }
file.delete();
} private class NameFilter implements FilenameFilter {
}
} private static final String ext = ".sgg";
private class NameFilter implements FilenameFilter { @Override
public boolean accept(File dir, String filename) {
private static final String ext = ".sgg"; return filename.endsWith(ext);
}
@Override
public boolean accept(File dir, String filename) { }
return filename.endsWith(ext);
} public void refreshPreferences() {
mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled();
} if (!mUseGoogle) {
mSuggestions.clear();
public void refreshPreferences() { }
mUseGoogle = PreferenceManager.getInstance().getGoogleSearchSuggestionsEnabled(); mDatabaseHandler = HistoryDatabase.getInstance(mContext.getApplicationContext());
if (!mUseGoogle && mSuggestions != null) { }
mSuggestions.clear();
} public void refreshBookmarks() {
mDatabaseHandler = HistoryDatabase.getInstance(mContext.getApplicationContext()); mAllBookmarks.clear();
} mAllBookmarks.addAll(mBookmarkManager.getBookmarks(true));
}
public void refreshBookmarks() {
mAllBookmarks = mBookmarkManager.getBookmarks(true); @Override
} public int getCount() {
return mFilteredList.size();
@Override }
public int getCount() {
if (mFilteredList != null) { @Override
return mFilteredList.size(); public Object getItem(int position) {
} else { return mFilteredList.get(position);
return 0; }
}
} @Override
public long getItemId(int position) {
@Override return 0;
public Object getItem(int position) { }
return mFilteredList.get(position);
} @SuppressWarnings("deprecation")
@SuppressLint("NewApi")
@Override @Override
public long getItemId(int position) { public View getView(int position, View convertView, ViewGroup parent) {
return 0; SuggestionHolder holder;
}
if (convertView == null) {
@SuppressWarnings("deprecation") LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
@SuppressLint("NewApi") convertView = inflater.inflate(R.layout.two_line_autocomplete, parent, false);
@Override
public View getView(int position, View convertView, ViewGroup parent) { holder = new SuggestionHolder();
View row = convertView; holder.mTitle = (TextView) convertView.findViewById(R.id.title);
SuggestionHolder holder; holder.mUrl = (TextView) convertView.findViewById(R.id.url);
holder.mImage = (ImageView) convertView.findViewById(R.id.suggestionIcon);
if (row == null) { convertView.setTag(holder);
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); } else {
row = inflater.inflate(R.layout.two_line_autocomplete, parent, false); holder = (SuggestionHolder) convertView.getTag();
}
holder = new SuggestionHolder(); HistoryItem web;
holder.mTitle = (TextView) row.findViewById(R.id.title); web = mFilteredList.get(position);
holder.mUrl = (TextView) row.findViewById(R.id.url); holder.mTitle.setText(web.getTitle());
holder.mImage = (ImageView) row.findViewById(R.id.suggestionIcon); holder.mUrl.setText(web.getUrl());
row.setTag(holder);
} else { int imageId = R.drawable.ic_bookmark;
holder = (SuggestionHolder) row.getTag(); switch (web.getImageId()) {
} case R.drawable.ic_bookmark: {
if (!mDarkTheme) {
HistoryItem web = mFilteredList.get(position); imageId = R.drawable.ic_bookmark;
holder.mTitle.setText(web.getTitle()); } else {
holder.mUrl.setText(web.getUrl()); holder.mTitle.setTextColor(Color.WHITE);
imageId = R.drawable.ic_bookmark_dark;
int imageId = R.drawable.ic_bookmark; }
switch (web.getImageId()) { break;
case R.drawable.ic_bookmark: { }
if (!mDarkTheme) { case R.drawable.ic_search: {
imageId = R.drawable.ic_bookmark; if (!mDarkTheme) {
} else { imageId = R.drawable.ic_search;
holder.mTitle.setTextColor(Color.WHITE); } else {
imageId = R.drawable.ic_bookmark_dark; holder.mTitle.setTextColor(Color.WHITE);
} imageId = R.drawable.ic_search_dark;
break; }
} break;
case R.drawable.ic_search: { }
if (!mDarkTheme) { case R.drawable.ic_history: {
imageId = R.drawable.ic_search; if (!mDarkTheme) {
} else { imageId = R.drawable.ic_history;
holder.mTitle.setTextColor(Color.WHITE); } else {
imageId = R.drawable.ic_search_dark; holder.mTitle.setTextColor(Color.WHITE);
} imageId = R.drawable.ic_history_dark;
break; }
} break;
case R.drawable.ic_history: { }
if (!mDarkTheme) { }
imageId = R.drawable.ic_history;
} else { if (API < Build.VERSION_CODES.LOLLIPOP) {
holder.mTitle.setTextColor(Color.WHITE); holder.mImage.setImageDrawable(mContext.getResources().getDrawable(imageId));
imageId = R.drawable.ic_history_dark; } else {
} holder.mImage.setImageDrawable(mContext.getResources().getDrawable(imageId, mTheme));
break; }
}
} return convertView;
}
if (API < Build.VERSION_CODES.LOLLIPOP) {
holder.mImage.setImageDrawable(mContext.getResources().getDrawable(imageId)); public void setContents(List<HistoryItem> list) {
} else { mFilteredList.clear();
holder.mImage.setImageDrawable(mContext.getResources().getDrawable(imageId, mTheme)); mFilteredList.addAll(list);
} notifyDataSetChanged();
}
return row;
} @Override
public Filter getFilter() {
public void setContents(List<HistoryItem> list) { if (mFilter == null) {
if (mFilteredList != null) { mFilter = new SearchFilter();
mFilteredList.clear(); }
mFilteredList.addAll(list); return mFilter;
} else { }
mFilteredList = list;
} private class SearchFilter extends Filter {
notifyDataSetChanged();
} @Override
protected FilterResults performFiltering(CharSequence constraint) {
@Override FilterResults results = new FilterResults();
public Filter getFilter() { if (constraint == null) {
if (mFilter == null) { return results;
mFilter = new SearchFilter(); }
} String query = constraint.toString().toLowerCase(Locale.getDefault());
return mFilter; if (mUseGoogle && !mIncognito && !mIsExecuting) {
} new RetrieveSearchSuggestions().execute(query);
}
private class SearchFilter extends Filter {
int counter = 0;
@Override mBookmarks.clear();
protected FilterResults performFiltering(CharSequence constraint) { for (int n = 0; n < mAllBookmarks.size(); n++) {
FilterResults results = new FilterResults(); if (counter >= 5) {
if (constraint == null) { break;
return results; }
} if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault())
String query = constraint.toString().toLowerCase(Locale.getDefault()); .startsWith(query)) {
if (mUseGoogle && !mIncognito && !mIsExecuting) { mBookmarks.add(mAllBookmarks.get(n));
new RetrieveSearchSuggestions().execute(query); counter++;
} } else if (mAllBookmarks.get(n).getUrl().contains(query)) {
mBookmarks.add(mAllBookmarks.get(n));
int counter = 0; counter++;
mBookmarks = new ArrayList<>(); }
for (int n = 0; n < mAllBookmarks.size(); n++) {
if (counter >= 5) { }
break; if (mDatabaseHandler == null) {
} mDatabaseHandler = HistoryDatabase.getInstance(mContext.getApplicationContext());
if (mAllBookmarks.get(n).getTitle().toLowerCase(Locale.getDefault()) }
.startsWith(query)) { List<HistoryItem> historyList = mDatabaseHandler.findItemsContaining(constraint.toString());
mBookmarks.add(mAllBookmarks.get(n)); mHistory.clear();
counter++; mHistory.addAll(historyList);
} else if (mAllBookmarks.get(n).getUrl().contains(query)) { results.count = 1;
mBookmarks.add(mAllBookmarks.get(n)); return results;
counter++; }
}
@Override
} public CharSequence convertResultToString(Object resultValue) {
if (mDatabaseHandler == null) { return ((HistoryItem) resultValue).getUrl();
mDatabaseHandler = HistoryDatabase.getInstance(mContext.getApplicationContext()); }
}
mHistory = mDatabaseHandler.findItemsContaining(constraint.toString()); @Override
protected void publishResults(CharSequence constraint, FilterResults results) {
results.count = 1; mFilteredList.clear();
return results; mFilteredList.addAll(getSuggestions());
} notifyDataSetChanged();
}
@Override
public CharSequence convertResultToString(Object resultValue) { }
return ((HistoryItem) resultValue).getUrl();
} private class SuggestionHolder {
ImageView mImage;
@Override TextView mTitle;
protected void publishResults(CharSequence constraint, FilterResults results) { TextView mUrl;
mFilteredList = getSuggestions(); }
notifyDataSetChanged();
} private class RetrieveSearchSuggestions extends AsyncTask<String, Void, List<HistoryItem>> {
} private XmlPullParserFactory mFactory;
private XmlPullParser mXpp;
private class SuggestionHolder {
ImageView mImage; @Override
TextView mTitle; protected List<HistoryItem> doInBackground(String... arg0) {
TextView mUrl; mIsExecuting = true;
}
List<HistoryItem> filter = new ArrayList<>();
private class RetrieveSearchSuggestions extends AsyncTask<String, Void, List<HistoryItem>> { String query = arg0[0];
try {
private XmlPullParserFactory mFactory; query = query.replace(" ", "+");
private XmlPullParser mXpp; URLEncoder.encode(query, ENCODING);
} catch (UnsupportedEncodingException e) {
@Override e.printStackTrace();
protected List<HistoryItem> doInBackground(String... arg0) { }
mIsExecuting = true; File cache = downloadSuggestionsForQuery(query);
if (!cache.exists()) {
List<HistoryItem> filter = new ArrayList<>(); return filter;
String query = arg0[0]; }
try { InputStream fileInput = null;
query = query.replace(" ", "+"); try {
URLEncoder.encode(query, ENCODING); fileInput = new BufferedInputStream(new FileInputStream(cache));
} catch (UnsupportedEncodingException e) { if (mFactory == null) {
e.printStackTrace(); mFactory = XmlPullParserFactory.newInstance();
} mFactory.setNamespaceAware(true);
File cache = downloadSuggestionsForQuery(query); }
if (!cache.exists()) { if (mXpp == null) {
return filter; mXpp = mFactory.newPullParser();
} }
InputStream fileInput = null; mXpp.setInput(fileInput, ENCODING);
try { int eventType = mXpp.getEventType();
fileInput = new BufferedInputStream(new FileInputStream(cache)); int counter = 0;
if (mFactory == null) { while (eventType != XmlPullParser.END_DOCUMENT) {
mFactory = XmlPullParserFactory.newInstance(); if (eventType == XmlPullParser.START_TAG && "suggestion".equals(mXpp.getName())) {
mFactory.setNamespaceAware(true); String suggestion = mXpp.getAttributeValue(null, "data");
} filter.add(new HistoryItem(mSearchSubtitle + " \"" + suggestion + '"',
if (mXpp == null) { suggestion, R.drawable.ic_search));
mXpp = mFactory.newPullParser(); counter++;
} if (counter >= 5) {
mXpp.setInput(fileInput, ENCODING); break;
int eventType = mXpp.getEventType(); }
int counter = 0; }
while (eventType != XmlPullParser.END_DOCUMENT) { eventType = mXpp.next();
if (eventType == XmlPullParser.START_TAG && "suggestion".equals(mXpp.getName())) { }
String suggestion = mXpp.getAttributeValue(null, "data"); } catch (Exception e) {
filter.add(new HistoryItem(mSearchSubtitle + " \"" + suggestion + '"', return filter;
suggestion, R.drawable.ic_search)); } finally {
counter++; Utils.close(fileInput);
if (counter >= 5) { }
break; return filter;
} }
}
eventType = mXpp.next(); @Override
} protected void onPostExecute(List<HistoryItem> result) {
} catch (Exception e) { mSuggestions.clear();
return filter; mSuggestions.addAll(result);
} finally { mFilteredList.clear();
if (fileInput != null) { mFilteredList.addAll(getSuggestions());
try { notifyDataSetChanged();
fileInput.close(); mIsExecuting = false;
} catch (IOException e) { }
e.printStackTrace();
} }
}
} private File downloadSuggestionsForQuery(String query) {
return filter; File cacheFile = new File(mContext.getCacheDir(), query.hashCode() + ".sgg");
} if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) {
return cacheFile;
@Override }
protected void onPostExecute(List<HistoryItem> result) { if (!isNetworkConnected(mContext)) {
mSuggestions = result; return cacheFile;
mFilteredList = getSuggestions(); }
notifyDataSetChanged(); try {
mIsExecuting = false; URL url = new URL("http://google.com/complete/search?q=" + query
} + "&output=toolbar&hl=en");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
} connection.setDoInput(true);
connection.connect();
private File downloadSuggestionsForQuery(String query) { InputStream in = connection.getInputStream();
File cacheFile = new File(mContext.getCacheDir(), query.hashCode() + ".sgg");
if (System.currentTimeMillis() - INTERVAL_DAY < cacheFile.lastModified()) { if (in != null) {
return cacheFile; FileOutputStream fos = new FileOutputStream(cacheFile);
} int buffer;
if (!isNetworkConnected(mContext)) { while ((buffer = in.read()) != -1) {
return cacheFile; fos.write(buffer);
} }
try { fos.flush();
URL url = new URL("http://google.com/complete/search?q=" + query fos.close();
+ "&output=toolbar&hl=en"); }
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); cacheFile.setLastModified(System.currentTimeMillis());
connection.setDoInput(true); } catch (Exception e) {
connection.connect(); e.printStackTrace();
InputStream in = connection.getInputStream(); }
return cacheFile;
if (in != null) { }
FileOutputStream fos = new FileOutputStream(cacheFile);
int buffer; private boolean isNetworkConnected(Context context) {
while ((buffer = in.read()) != -1) { NetworkInfo networkInfo = getActiveNetworkInfo(context);
fos.write(buffer); return networkInfo != null && networkInfo.isConnected();
} }
fos.flush();
fos.close(); private NetworkInfo getActiveNetworkInfo(Context context) {
} ConnectivityManager connectivity = (ConnectivityManager) context
cacheFile.setLastModified(System.currentTimeMillis()); .getSystemService(Context.CONNECTIVITY_SERVICE);
} catch (Exception e) { if (connectivity == null) {
e.printStackTrace(); return null;
} }
return cacheFile; return connectivity.getActiveNetworkInfo();
} }
private boolean isNetworkConnected(Context context) { //TODO Write simpler algorithm
NetworkInfo networkInfo = getActiveNetworkInfo(context); private List<HistoryItem> getSuggestions() {
return networkInfo != null && networkInfo.isConnected(); List<HistoryItem> filteredList = new ArrayList<>();
}
int suggestionsSize = mSuggestions.size();
private NetworkInfo getActiveNetworkInfo(Context context) { int historySize = mHistory.size();
ConnectivityManager connectivity = (ConnectivityManager) context int bookmarkSize = mBookmarks.size();
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) { int maxSuggestions = (bookmarkSize + historySize < 3) ? (5 - bookmarkSize - historySize)
return null; : (bookmarkSize < 2) ? (4 - bookmarkSize) : (historySize < 1) ? 3 : 2;
} int maxHistory = (suggestionsSize + bookmarkSize < 4) ? (5 - suggestionsSize - bookmarkSize)
return connectivity.getActiveNetworkInfo(); : 1;
} int maxBookmarks = (suggestionsSize + historySize < 3) ? (5 - suggestionsSize - historySize)
: 2;
//TODO Write simpler algorithm
private List<HistoryItem> getSuggestions() { for (int n = 0; n < bookmarkSize && n < maxBookmarks; n++) {
List<HistoryItem> filteredList = new ArrayList<>(); filteredList.add(mBookmarks.get(n));
}
int suggestionsSize = (mSuggestions == null) ? 0 : mSuggestions.size();
int historySize = (mHistory == null) ? 0 : mHistory.size(); for (int n = 0; n < historySize && n < maxHistory; n++) {
int bookmarkSize = (mBookmarks == null) ? 0 : mBookmarks.size(); filteredList.add(mHistory.get(n));
}
int maxSuggestions = (bookmarkSize + historySize < 3) ? (5 - bookmarkSize - historySize)
: (bookmarkSize < 2) ? (4 - bookmarkSize) : (historySize < 1) ? 3 : 2; for (int n = 0; n < suggestionsSize && n < maxSuggestions; n++) {
int maxHistory = (suggestionsSize + bookmarkSize < 4) ? (5 - suggestionsSize - bookmarkSize) filteredList.add(mSuggestions.get(n));
: 1; }
int maxBookmarks = (suggestionsSize + historySize < 3) ? (5 - suggestionsSize - historySize) return filteredList;
: 2; }
if (!mUseGoogle || mIncognito) {
maxHistory++;
maxBookmarks++;
}
for (int n = 0; n < bookmarkSize && n < maxBookmarks; n++) {
filteredList.add(mBookmarks.get(n));
}
for (int n = 0; n < historySize && n < maxHistory; n++) {
filteredList.add(mHistory.get(n));
}
for (int n = 0; n < suggestionsSize && n < maxSuggestions; n++) {
filteredList.add(mSuggestions.get(n));
}
return filteredList;
}
} }

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

@ -357,7 +357,7 @@ public class PreferenceManager {
} }
public void setReadingTextSize(int size) { public void setReadingTextSize(int size) {
putInt(Name.READING_TEXT_SIZE, 2); putInt(Name.READING_TEXT_SIZE, size);
} }
public void setRenderingMode(int mode) { public void setRenderingMode(int mode) {

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

@ -95,11 +95,10 @@ public class ArticleTextExtractor {
} }
/** /**
* @param html * @param doc the document to extract
* extracts article text from given html string. wasn't tested * extracts article text from given html string. wasn't tested
* with improper HTML, although jSoup should be able to handle * with improper HTML, although jSoup should be able to handle
* minor stuff. * minor stuff.
* @returns extracted article, all HTML tags stripped
*/ */
public JResult extractContent(Document doc) throws Exception { public JResult extractContent(Document doc) throws Exception {
return extractContent(new JResult(), doc, formatter); return extractContent(new JResult(), doc, formatter);
@ -235,14 +234,12 @@ public class ArticleTextExtractor {
protected Collection<String> extractKeywords(Document doc) { protected Collection<String> extractKeywords(Document doc) {
String content = SHelper.innerTrim(doc.select("head meta[name=keywords]").attr("content")); String content = SHelper.innerTrim(doc.select("head meta[name=keywords]").attr("content"));
if (content != null) { if (content.startsWith("[") && content.endsWith("]"))
if (content.startsWith("[") && content.endsWith("]")) content = content.substring(1, content.length() - 1);
content = content.substring(1, content.length() - 1);
String[] split = content.split("\\s*,\\s*"); String[] split = content.split("\\s*,\\s*");
if (split.length > 1 || (split.length > 0 && !"".equals(split[0]))) if (split.length > 1 || (split.length > 0 && !"".equals(split[0])))
return Arrays.asList(split); return Arrays.asList(split);
}
return Collections.emptyList(); return Collections.emptyList();
} }

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

@ -94,7 +94,7 @@ public class Converter {
/** /**
* reads bytes off the string and returns a string * reads bytes off the string and returns a string
* *
* @param is * @param is input stream to read
* @param maxBytes * @param maxBytes
* The max bytes that we want to read from the input stream * The max bytes that we want to read from the input stream
* @return String * @return String

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

@ -230,7 +230,7 @@ public class HtmlFetcher {
} }
// if resolved url is longer then use it! // if resolved url is longer then use it!
if (resUrl != null && resUrl.trim().length() > url.length()) { if (resUrl.trim().length() > url.length()) {
// this is necessary e.g. for some homebaken url resolvers which // this is necessary e.g. for some homebaken url resolvers which
// return // return
// the resolved url relative to url! // the resolved url relative to url!

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

@ -164,7 +164,7 @@ public class SHelper {
* extract the domain from this url * extract the domain from this url
* @param path * @param path
* this url does not have a domain * this url does not have a domain
* @return * @return returns the domain
*/ */
public static String useDomainOfFirstArg4Second(String urlForDomain, String path) { public static String useDomainOfFirstArg4Second(String urlForDomain, String path) {
if (path.startsWith("http")) if (path.startsWith("http"))
@ -257,8 +257,7 @@ public class SHelper {
} }
/** /**
* @see http * http://blogs.sun.com/CoreJavaTechTips/entry/cookie_handling_in_java_se
* ://blogs.sun.com/CoreJavaTechTips/entry/cookie_handling_in_java_se
*/ */
public static void enableCookieMgmt() { public static void enableCookieMgmt() {
CookieManager manager = new CookieManager(); CookieManager manager = new CookieManager();
@ -267,9 +266,7 @@ public class SHelper {
} }
/** /**
* @see http * http://stackoverflow.com/questions/2529682/setting-user-agent-of-a-java-urlconnection
* ://stackoverflow.com/questions/2529682/setting-user-agent-of-a-java
* -urlconnection
*/ */
public static void enableUserAgentOverwrite() { public static void enableUserAgentOverwrite() {
System.setProperty("http.agent", ""); System.setProperty("http.agent", "");

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

@ -21,7 +21,7 @@ public class IntentUtils {
private final Activity mActivity; private final Activity mActivity;
static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile("(?i)" private static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile("(?i)"
+ // switch on case insensitive matching + // switch on case insensitive matching
"(" "("
+ // begin group for schema + // begin group for schema

34
app/src/main/java/acr/browser/lightning/utils/ThemeUtils.java

@ -0,0 +1,34 @@
package acr.browser.lightning.utils;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.util.TypedValue;
import acr.browser.lightning.R;
public class ThemeUtils {
private static final TypedValue sTypedValue = new TypedValue();
public static int getPrimaryColor(@NonNull Context context) {
return getColor(context, R.attr.colorPrimary);
}
public static int getPrimaryColorDark(@NonNull Context context) {
return getColor(context, R.attr.colorPrimaryDark);
}
public static int getAccentColor(@NonNull Context context) {
return getColor(context, R.attr.colorAccent);
}
private static int getColor(@NonNull Context context, @AttrRes int resource) {
TypedArray a = context.obtainStyledAttributes(sTypedValue.data, new int[]{resource});
int color = a.getColor(0, 0);
a.recycle();
return color;
}
}

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

@ -5,7 +5,6 @@ package acr.browser.lightning.utils;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@ -17,11 +16,14 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
import android.os.Environment; import android.os.Environment;
import android.support.annotation.StringRes;
import android.support.v7.app.AlertDialog;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.webkit.URLUtil; import android.webkit.URLUtil;
import android.widget.Toast; import android.widget.Toast;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -39,15 +41,15 @@ public final class Utils {
} }
public static void downloadFile(final Activity activity, final String url, public static void downloadFile(final Activity activity, final String url,
final String userAgent, final String contentDisposition, final boolean privateBrowsing) { final String userAgent, final String contentDisposition) {
String fileName = URLUtil.guessFileName(url, null, null); String fileName = URLUtil.guessFileName(url, null, null);
DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null, DownloadHandler.onDownloadStart(activity, url, userAgent, contentDisposition, null
privateBrowsing); );
Log.i(Constants.TAG, "Downloading" + fileName); Log.i(Constants.TAG, "Downloading" + fileName);
} }
public static Intent newEmailIntent(Context context, String address, String subject, public static Intent newEmailIntent(String address, String subject,
String body, String cc) { String body, String cc) {
Intent intent = new Intent(Intent.ACTION_SEND); Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, new String[] { address }); intent.putExtra(Intent.EXTRA_EMAIL, new String[] { address });
intent.putExtra(Intent.EXTRA_TEXT, body); intent.putExtra(Intent.EXTRA_TEXT, body);
@ -63,11 +65,11 @@ public final class Utils {
builder.setMessage(message) builder.setMessage(message)
.setCancelable(true) .setCancelable(true)
.setPositiveButton(context.getResources().getString(R.string.action_ok), .setPositiveButton(context.getResources().getString(R.string.action_ok),
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) { public void onClick(DialogInterface dialog, int id) {
} }
}); });
AlertDialog alert = builder.create(); AlertDialog alert = builder.create();
alert.show(); alert.show();
} }
@ -76,6 +78,10 @@ public final class Utils {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
} }
public static void showToast(Context context, @StringRes int resource) {
Toast.makeText(context, resource, Toast.LENGTH_SHORT).show();
}
/** /**
* Returns the number of pixels corresponding to the passed density pixels * Returns the number of pixels corresponding to the passed density pixels
*/ */
@ -237,4 +243,13 @@ public final class Utils {
private static Bitmap mWebIconLight; private static Bitmap mWebIconLight;
private static Bitmap mWebIconDark; private static Bitmap mWebIconDark;
public static void close(Closeable closeable) {
if (closeable == null)
return;
try {
closeable.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }

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

File diff suppressed because it is too large Load Diff

20
app/src/main/res/layout/picker_manual_proxy.xml

@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="4dp" android:paddingEnd="4dp"
android:paddingStart="4dp"> android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingStart="4dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -13,14 +15,14 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/host"/> android:text="@string/host" />
<EditText <EditText
android:id="@+id/proxyHost" android:id="@+id/proxyHost"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:inputType="text"/> android:inputType="text" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -30,14 +32,14 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/port"/> android:text="@string/port" />
<EditText <EditText
android:id="@+id/proxyPort" android:id="@+id/proxyPort"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:inputType="number"/> android:inputType="number" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

2
app/src/main/res/layout/toolbar_content.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" > android:orientation="horizontal" >
@ -9,7 +8,6 @@
android:id="@+id/arrow_button" android:id="@+id/arrow_button"
android:layout_width="?attr/actionBarSize" android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:layout_marginLeft="2dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:background="?attr/actionBarItemBackground" android:background="?attr/actionBarItemBackground"
android:clickable="true" android:clickable="true"

11
app/src/main/res/layout/two_line_autocomplete.xml

@ -3,22 +3,25 @@
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="false" android:clickable="false"
android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingBottom="3dp" android:paddingBottom="3dp"
android:paddingEnd="6dp"
android:paddingLeft="6dp" android:paddingLeft="6dp"
android:paddingTop="3dp" android:paddingRight="6dp"
android:gravity="center_vertical"> android:paddingStart="6dp"
android:paddingTop="3dp">
<ImageView <ImageView
android:id="@+id/suggestionIcon" android:id="@+id/suggestionIcon"
android:layout_width="25dp" android:layout_width="25dp"
android:layout_height="25dp"/> android:layout_height="25dp" />
<LinearLayout <LinearLayout
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="5dp" > android:paddingLeft="5dp">
<TextView <TextView
android:id="@+id/title" android:id="@+id/title"

3
app/src/main/res/values-v21/styles.xml

@ -4,6 +4,7 @@
<style name="Theme.SettingsTheme" parent="Theme.AppCompat.Light"> <style name="Theme.SettingsTheme" parent="Theme.AppCompat.Light">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@color/primary_color</item> <item name="toolbarSettingsBackground">@color/primary_color</item>
<item name="listBackground">?attr/listChoiceBackgroundIndicator</item> <item name="listBackground">?attr/listChoiceBackgroundIndicator</item>
<item name="colorPrimary">@color/primary_color</item> <item name="colorPrimary">@color/primary_color</item>
@ -20,6 +21,7 @@
<style name="Theme.SettingsTheme.Dark" parent="Theme.AppCompat"> <style name="Theme.SettingsTheme.Dark" parent="Theme.AppCompat">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@color/primary_color_dark</item> <item name="toolbarSettingsBackground">@color/primary_color_dark</item>
<item name="listBackground">?attr/listChoiceBackgroundIndicator</item> <item name="listBackground">?attr/listChoiceBackgroundIndicator</item>
<item name="colorPrimary">@color/primary_color_dark</item> <item name="colorPrimary">@color/primary_color_dark</item>
@ -36,6 +38,7 @@
<style name="Theme.SettingsTheme.Black" parent="Theme.AppCompat"> <style name="Theme.SettingsTheme.Black" parent="Theme.AppCompat">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@color/black</item> <item name="toolbarSettingsBackground">@color/black</item>
<item name="listBackground">?attr/listChoiceBackgroundIndicator</item> <item name="listBackground">?attr/listChoiceBackgroundIndicator</item>
<item name="colorPrimary">@color/black</item> <item name="colorPrimary">@color/black</item>

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

@ -4,6 +4,7 @@
<style name="Theme.SettingsTheme" parent="Theme.AppCompat.Light"> <style name="Theme.SettingsTheme" parent="Theme.AppCompat.Light">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@drawable/toolbar_elevate</item> <item name="toolbarSettingsBackground">@drawable/toolbar_elevate</item>
<item name="listBackground">@drawable/list_bg</item> <item name="listBackground">@drawable/list_bg</item>
<item name="colorPrimary">@color/primary_color</item> <item name="colorPrimary">@color/primary_color</item>
@ -20,6 +21,7 @@
<style name="Theme.SettingsTheme.Dark" parent="Theme.AppCompat"> <style name="Theme.SettingsTheme.Dark" parent="Theme.AppCompat">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@drawable/toolbar_elevate_dark</item> <item name="toolbarSettingsBackground">@drawable/toolbar_elevate_dark</item>
<item name="listBackground">@drawable/list_bg</item> <item name="listBackground">@drawable/list_bg</item>
<item name="colorPrimary">@color/primary_color_dark</item> <item name="colorPrimary">@color/primary_color_dark</item>
@ -36,6 +38,7 @@
<style name="Theme.SettingsTheme.Black" parent="Theme.AppCompat"> <style name="Theme.SettingsTheme.Black" parent="Theme.AppCompat">
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="android:windowBackground">@color/transparent</item>
<item name="toolbarSettingsBackground">@drawable/toolbar_elevate_black</item> <item name="toolbarSettingsBackground">@drawable/toolbar_elevate_black</item>
<item name="listBackground">@drawable/list_bg</item> <item name="listBackground">@drawable/list_bg</item>
<item name="colorPrimary">@color/black</item> <item name="colorPrimary">@color/black</item>
@ -53,13 +56,13 @@
<!-- customize the color palette --> <!-- customize the color palette -->
<item name="searchBackground">@drawable/card_bg_elevate</item> <item name="searchBackground">@drawable/card_bg_elevate</item>
<item name="listBackground">@drawable/list_bg</item>
<item name="colorPrimary">@color/primary_color</item> <item name="colorPrimary">@color/primary_color</item>
<item name="colorPrimaryDark">@color/secondary_color</item> <item name="colorPrimaryDark">@color/secondary_color</item>
<item name="colorAccent">@color/accent_color</item> <item name="colorAccent">@color/accent_color</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="progressBackgroundColor">@color/secondary_color</item> <item name="progressBackgroundColor">@color/secondary_color</item>
<item name="listBackground">@drawable/list_bg</item>
<item name="android:windowContentOverlay">@null</item> <item name="android:windowContentOverlay">@null</item>
<item name="progressColor">@color/gray_medium</item> <item name="progressColor">@color/gray_medium</item>
<item name="numberColor">@color/gray_dark</item> <item name="numberColor">@color/gray_dark</item>

Loading…
Cancel
Save