From 46fbc5660416451a572cb27ac106f00abed20de6 Mon Sep 17 00:00:00 2001 From: str4d Date: Sun, 24 May 2015 13:19:02 +0000 Subject: [PATCH 1/8] Add I2P client library to dependencies --- app/build.gradle | 1 + app/proguard-project.txt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index b8f4727..ef8e7f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,4 +39,5 @@ dependencies { compile 'com.android.support:palette-v7:22.1.1' compile 'com.android.support:appcompat-v7:22.1.1' compile 'org.jsoup:jsoup:1.8.1' + compile 'net.i2p.android:client:0.6@aar' } diff --git a/app/proguard-project.txt b/app/proguard-project.txt index 4bab3ea..382c1d4 100644 --- a/app/proguard-project.txt +++ b/app/proguard-project.txt @@ -77,3 +77,8 @@ # Don't warn about those in case this app is linking against an older # platform version. We know about them, and they are safe. -dontwarn android.support.** + +# The I2P Java API bundled inside the I2P Android client library contains a +# method that references classes in javax.naming that Android doesn't have. But +# the method never uses those classes on Android, and is safe. +-dontwarn net.i2p.crypto.CertUtil From 6c2a55713524dcdf2dea0ec7a531e2cdab34656e Mon Sep 17 00:00:00 2001 From: str4d Date: Sun, 24 May 2015 13:20:08 +0000 Subject: [PATCH 2/8] Change Orbot checkbox to an HTTP proxy choice list (None, Orbot, I2P) --- .../lightning/activity/SettingsActivity.java | 96 +++++++++++++------ .../preference/PreferenceManager.java | 9 ++ app/src/main/res/layout/settings.xml | 30 +++--- app/src/main/res/values/strings.xml | 7 +- 4 files changed, 96 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index c5a8b92..e3a627f 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -22,11 +22,15 @@ import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.RelativeLayout; +import android.widget.TextView; +import net.i2p.android.ui.I2PAndroidHelper; + +import acr.browser.lightning.R; import acr.browser.lightning.constant.Constants; import acr.browser.lightning.preference.PreferenceManager; -import acr.browser.lightning.R; import acr.browser.lightning.utils.Utils; import info.guardianproject.onionkit.ui.OrbotHelper; @@ -36,6 +40,8 @@ public class SettingsActivity extends ThemableSettingsActivity { private PreferenceManager mPreferences; private Context mContext; private Activity mActivity; + private CharSequence[] mProxyChoices; + private TextView mProxyChoiceName; @Override protected void onCreate(Bundle savedInstanceState) { @@ -69,7 +75,7 @@ public class SettingsActivity extends ThemableSettingsActivity { layoutBlockAds.setEnabled(Constants.FULL_VERSION); RelativeLayout layoutImages = (RelativeLayout) findViewById(R.id.layoutImages); RelativeLayout layoutEnableJS = (RelativeLayout) findViewById(R.id.layoutEnableJS); - RelativeLayout layoutOrbot = (RelativeLayout) findViewById(R.id.layoutUseOrbot); + LinearLayout layoutProxyChoice = (LinearLayout) findViewById(R.id.layoutProxyChoice); RelativeLayout layoutColor = (RelativeLayout) findViewById(R.id.layoutColorMode); RelativeLayout layoutBookmarks = (RelativeLayout) findViewById(R.id.layoutBookmarks); @@ -89,12 +95,16 @@ public class SettingsActivity extends ThemableSettingsActivity { boolean imagesBool = mPreferences.getBlockImagesEnabled(); boolean enableJSBool = mPreferences.getJavaScriptEnabled(); + mProxyChoiceName = (TextView) findViewById(R.id.proxyChoiceName); + mProxyChoices = this.getResources().getStringArray(R.array.proxy_choices_array); + int choice = mPreferences.getProxyChoice(); + mProxyChoiceName.setText(mProxyChoices[choice]); + CheckBox flash = (CheckBox) findViewById(R.id.cbFlash); CheckBox adblock = (CheckBox) findViewById(R.id.cbAdblock); adblock.setEnabled(Constants.FULL_VERSION); CheckBox images = (CheckBox) findViewById(R.id.cbImageBlock); CheckBox enablejs = (CheckBox) findViewById(R.id.cbJavascript); - CheckBox orbot = (CheckBox) findViewById(R.id.cbOrbot); CheckBox color = (CheckBox) findViewById(R.id.cbColorMode); images.setChecked(imagesBool); @@ -105,12 +115,11 @@ public class SettingsActivity extends ThemableSettingsActivity { flash.setChecked(false); } adblock.setChecked(mPreferences.getAdBlockEnabled()); - orbot.setChecked(mPreferences.getUseProxy()); color.setChecked(mPreferences.getColorModeEnabled()); - initCheckBox(flash, adblock, images, enablejs, orbot, color); + initCheckBox(flash, adblock, images, enablejs, color); clickListenerForCheckBoxes(layoutFlash, layoutBlockAds, layoutImages, layoutEnableJS, - layoutOrbot, layoutColor, flash, adblock, images, enablejs, orbot, color); + layoutProxyChoice, layoutColor, flash, adblock, images, enablejs, color); RelativeLayout general = (RelativeLayout) findViewById(R.id.layoutGeneral); RelativeLayout display = (RelativeLayout) findViewById(R.id.layoutDisplay); @@ -127,9 +136,9 @@ public class SettingsActivity extends ThemableSettingsActivity { public void clickListenerForCheckBoxes(RelativeLayout layoutFlash, RelativeLayout layoutBlockAds, RelativeLayout layoutImages, - RelativeLayout layoutEnableJS, RelativeLayout layoutOrbot, RelativeLayout layoutColor, + RelativeLayout layoutEnableJS, LinearLayout layoutProxyChoice, RelativeLayout layoutColor, final CheckBox flash, final CheckBox adblock, final CheckBox images, - final CheckBox enablejs, final CheckBox orbot, final CheckBox color) { + final CheckBox enablejs, final CheckBox color) { layoutFlash.setOnClickListener(new OnClickListener() { @Override @@ -168,17 +177,12 @@ public class SettingsActivity extends ThemableSettingsActivity { } }); - layoutOrbot.setOnClickListener(new OnClickListener() { + layoutProxyChoice.setOnClickListener(new OnClickListener() { @Override - public void onClick(View v) { - if (orbot.isEnabled()) { - orbot.setChecked(!orbot.isChecked()); - } else { - Utils.showToast(mContext, getResources().getString(R.string.install_orbot)); - } + public void onClick(View view) { + proxyChoicePicker(); } - }); layoutColor.setOnClickListener(new OnClickListener() { @@ -191,7 +195,7 @@ public class SettingsActivity extends ThemableSettingsActivity { } public void initCheckBox(CheckBox flash, CheckBox adblock, CheckBox images, CheckBox enablejs, - CheckBox orbot, CheckBox color) { + CheckBox color) { flash.setEnabled(API < 19); flash.setOnCheckedChangeListener(new OnCheckedChangeListener() { @@ -253,20 +257,7 @@ public class SettingsActivity extends ThemableSettingsActivity { } }); - OrbotHelper oh = new OrbotHelper(this); - if (!oh.isOrbotInstalled()) { - orbot.setEnabled(false); - } - orbot.setOnCheckedChangeListener(new OnCheckedChangeListener() { - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - mPreferences.setUseProxy(isChecked); - - } - - }); color.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override @@ -309,6 +300,51 @@ public class SettingsActivity extends ThemableSettingsActivity { alert.show(); } + private void proxyChoicePicker() { + AlertDialog.Builder picker = new AlertDialog.Builder(mContext); + picker.setTitle(getResources().getString(R.string.http_proxy)); + picker.setSingleChoiceItems(mProxyChoices, mPreferences.getProxyChoice(), + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + setProxyChoice(which); + } + }); + picker.setNeutralButton(getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }); + picker.show(); + } + + private void setProxyChoice(int choice) { + switch (choice) { + case 1: + OrbotHelper oh = new OrbotHelper(this); + if (!oh.isOrbotInstalled()) { + choice = 0; + Utils.showToast(mContext, getResources().getString(R.string.install_orbot)); + } + break; + + case 2: + I2PAndroidHelper ih = new I2PAndroidHelper(this); + if (!ih.isI2PAndroidInstalled()) { + choice = 0; + ih.promptToInstall(this); + } + break; + } + + mPreferences.setUseProxy(choice != 0); + mPreferences.setProxyChoice(choice); + if (choice < mProxyChoices.length) + mProxyChoiceName.setText(mProxyChoices[choice]); + } + public void agentPicker() { final AlertDialog.Builder agentStringPicker = new AlertDialog.Builder(mActivity); diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index 275e93d..f03651d 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -49,6 +49,7 @@ public class PreferenceManager { public static final String DEFAULT_BOOKMARKS = "defaultBookmarks"; public static final String USE_PROXY = "useProxy"; + public static final String PROXY_CHOICE = "proxyChoice"; public static final String USE_PROXY_HOST = "useProxyHost"; public static final String USE_PROXY_PORT = "useProxyPort"; public static final String INITIAL_CHECK_FOR_TOR = "checkForTor"; @@ -226,6 +227,10 @@ public class PreferenceManager { return mPrefs.getBoolean(Name.USE_PROXY, false); } + public int getProxyChoice() { + return mPrefs.getInt(Name.PROXY_CHOICE, 0); + } + public int getUserAgentChoice() { return mPrefs.getInt(Name.USER_AGENT, 1); } @@ -398,6 +403,10 @@ public class PreferenceManager { putBoolean(Name.USE_PROXY, enable); } + public void setProxyChoice(int choice) { + putInt(Name.PROXY_CHOICE, choice); + } + public void setUserAgentChoice(int choice) { putInt(Name.USER_AGENT, choice); } diff --git a/app/src/main/res/layout/settings.xml b/app/src/main/res/layout/settings.xml index 3a04e18..4ba9191 100644 --- a/app/src/main/res/layout/settings.xml +++ b/app/src/main/res/layout/settings.xml @@ -1,8 +1,9 @@ + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> @@ -159,33 +160,32 @@ android:layout_marginRight="10dp" android:background="?attr/dividerColor" /> - - - + android:paddingLeft="16dp" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@color/light" + tools:text="Disabled" /> + Powered by Google AdBlock AdBlock is currently only available in the browser\'s paid version, Lightning Browser+. It is available to download on Google Play. - Enable Orbot + HTTP proxy + + None + Orbot + I2P + It looks like you have Orbot installed. Do you want to use Tor? Please install Orbot in order to proxy with Tor. Yes From 111d594c6bd89cccddf4f02ef0edd1df04f31da5 Mon Sep 17 00:00:00 2001 From: str4d Date: Mon, 25 May 2015 12:09:36 +0000 Subject: [PATCH 3/8] Use I2P if configured --- .../lightning/activity/BrowserActivity.java | 232 +++++++++++++----- .../lightning/activity/SettingsActivity.java | 1 - .../preference/PreferenceManager.java | 19 +- app/src/main/res/values/strings.xml | 1 + 4 files changed, 187 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index bde3d06..f06169c 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -10,7 +10,11 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; -import android.content.*; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.database.Cursor; @@ -36,15 +40,26 @@ import android.support.v4.view.GravityCompat; import android.support.v4.view.ViewCompat; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; +import android.support.v7.app.ActionBar; +import android.support.v7.graphics.Palette; +import android.support.v7.widget.Toolbar; import android.text.TextUtils; import android.util.Log; -import android.view.*; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; import android.view.View.OnKeyListener; import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; +import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; @@ -52,42 +67,69 @@ import android.view.animation.DecelerateInterpolator; import android.view.animation.Transformation; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.webkit.*; +import android.webkit.CookieManager; +import android.webkit.CookieSyncManager; +import android.webkit.ValueCallback; import android.webkit.WebChromeClient.CustomViewCallback; +import android.webkit.WebIconDatabase; +import android.webkit.WebStorage; +import android.webkit.WebView; import android.webkit.WebView.HitTestResult; -import android.widget.*; -import android.support.v7.app.ActionBar; -import android.support.v7.graphics.Palette; -import android.support.v7.widget.Toolbar; +import android.webkit.WebViewDatabase; +import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.RelativeLayout; +import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import android.widget.Toast; +import android.widget.VideoView; -import acr.browser.lightning.view.AnimatedProgressBar; -import acr.browser.lightning.database.BookmarkManager; +import net.i2p.android.ui.I2PAndroidHelper; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import acr.browser.lightning.R; import acr.browser.lightning.constant.BookmarkPage; -import acr.browser.lightning.controller.BrowserController; -import acr.browser.lightning.object.ClickHandler; import acr.browser.lightning.constant.Constants; -import acr.browser.lightning.object.DrawerArrowDrawable; +import acr.browser.lightning.constant.HistoryPage; +import acr.browser.lightning.controller.BrowserController; +import acr.browser.lightning.database.BookmarkManager; import acr.browser.lightning.database.HistoryDatabase; import acr.browser.lightning.database.HistoryItem; -import acr.browser.lightning.constant.HistoryPage; -import acr.browser.lightning.view.LightningView; -import acr.browser.lightning.preference.PreferenceManager; -import acr.browser.lightning.R; +import acr.browser.lightning.object.ClickHandler; +import acr.browser.lightning.object.DrawerArrowDrawable; import acr.browser.lightning.object.SearchAdapter; +import acr.browser.lightning.preference.PreferenceManager; import acr.browser.lightning.utils.Utils; +import acr.browser.lightning.view.AnimatedProgressBar; +import acr.browser.lightning.view.LightningView; import info.guardianproject.onionkit.ui.OrbotHelper; import info.guardianproject.onionkit.web.WebkitProxy; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLEncoder; -import java.util.*; - public class BrowserActivity extends ThemableActivity implements BrowserController, OnClickListener { // Layout @@ -140,6 +182,9 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll private Drawable mDeleteIcon, mRefreshIcon, mCopyIcon, mIcon; private DrawerArrowDrawable mArrowDrawable; + // Helper + private I2PAndroidHelper mI2PHelper; + // Constant private static final int API = android.os.Build.VERSION.SDK_INT; private static final LayoutParams MATCH_PARENT = new LayoutParams(LayoutParams.MATCH_PARENT, @@ -221,6 +266,8 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll R.id.arrow_button); arrowButton.setOnClickListener(this); + mI2PHelper = new I2PAndroidHelper(this); + RelativeLayout back = (RelativeLayout) findViewById(R.id.action_back); back.setOnClickListener(this); @@ -304,7 +351,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll WebIconDatabase.getInstance().open(getDir("icons", MODE_PRIVATE).getPath()); } - checkForTor(); + checkForProxy(); } private class SearchClass { @@ -494,56 +541,104 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll } /* - * If Orbot/Tor is installed, prompt the user if they want to enable + * If Orbot/Tor or I2P is installed, prompt the user if they want to enable * proxying for this session */ - private boolean checkForTor() { + private void checkForProxy() { boolean useProxy = mPreferences.getUseProxy(); OrbotHelper oh = new OrbotHelper(this); - if (oh.isOrbotInstalled() && !mPreferences.getCheckedForTor()) { - mPreferences.setCheckedForTor(true); - DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - switch (which) { - case DialogInterface.BUTTON_POSITIVE: - mPreferences.setUseProxy(true); - initializeTor(); - break; - case DialogInterface.BUTTON_NEGATIVE: - mPreferences.setUseProxy(false); - break; - } - } - }; - + final boolean orbotInstalled = oh.isOrbotInstalled(); + boolean orbotChecked = mPreferences.getCheckedForTor(); + boolean orbot = orbotInstalled && !orbotChecked; + + boolean i2pInstalled = mI2PHelper.isI2PAndroidInstalled(); + boolean i2pChecked = mPreferences.getCheckedForI2P(); + boolean i2p = i2pInstalled && !i2pChecked; + + // TODO Is the idea to show this per-session, or only once? + if (!useProxy && (orbot || i2p)) { + if (orbot) mPreferences.setCheckedForTor(true); + if (i2p) mPreferences.setCheckedForI2P(true); AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage(R.string.use_tor_prompt) - .setPositiveButton(R.string.yes, dialogClickListener) - .setNegativeButton(R.string.no, dialogClickListener).show(); - return true; - } else if (oh.isOrbotInstalled() & useProxy) { - return true; - } else { - mPreferences.setUseProxy(false); - return false; + if (orbotInstalled && i2pInstalled) { + String[] proxyChoices = this.getResources().getStringArray(R.array.proxy_choices_array); + builder.setTitle(getResources().getString(R.string.http_proxy)) + .setSingleChoiceItems(proxyChoices, mPreferences.getProxyChoice(), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mPreferences.setProxyChoice(which); + } + }) + .setNeutralButton(getResources().getString(R.string.action_ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (mPreferences.getUseProxy()) + initializeProxy(); + } + }); + } else { + DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case DialogInterface.BUTTON_POSITIVE: + mPreferences.setProxyChoice(orbotInstalled ? 1 : 2); + initializeProxy(); + break; + case DialogInterface.BUTTON_NEGATIVE: + mPreferences.setProxyChoice(0); + break; + } + } + }; + + builder.setMessage(orbotInstalled ? R.string.use_tor_prompt : R.string.use_i2p_prompt) + .setPositiveButton(R.string.yes, dialogClickListener) + .setNegativeButton(R.string.no, dialogClickListener); + } + builder.show(); } } /* - * Initialize WebKit Proxying for Tor + * Initialize WebKit Proxying */ - private void initializeTor() { + private void initializeProxy() { + String host; + int port; - OrbotHelper oh = new OrbotHelper(this); - if (!oh.isOrbotRunning()) { - oh.requestOrbotStart(this); + switch (mPreferences.getProxyChoice()) { + case 0: + // We shouldn't be here + return; + + case 1: + OrbotHelper oh = new OrbotHelper(this); + if (!oh.isOrbotRunning()) { + oh.requestOrbotStart(this); + } + host = "localhost"; + port = 8118; + break; + + case 2: + if (!mI2PHelper.isI2PAndroidRunning()) { + mI2PHelper.requestI2PAndroidStart(this); + } + host = "localhost"; + port = 4444; + break; + + default: + host = mPreferences.getProxyHost(); + port = mPreferences.getProxyPort(); } + try { - String host = mPreferences.getProxyHost(); - int port = mPreferences.getProxyPort(); WebkitProxy.setProxy(BrowserApp.class.getName(), getApplicationContext(), host, port); } catch (Exception e) { @@ -704,7 +799,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll updateCookiePreference(); if (mPreferences.getUseProxy()) { - initializeTor(); + initializeProxy(); } else { try { WebkitProxy.resetProxy(BrowserApp.class.getName(), @@ -1369,6 +1464,12 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll } } + @Override + protected void onStop() { + super.onStop(); + mI2PHelper.unbind(); + } + @Override protected void onDestroy() { Log.d(Constants.TAG, "onDestroy"); @@ -1378,6 +1479,15 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll super.onDestroy(); } + @Override + protected void onStart() { + super.onStart(); + if (mPreferences.getProxyChoice() == 2) { + // Try to bind to I2P Android + mI2PHelper.bind(); + } + } + @Override protected void onResume() { super.onResume(); diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index e3a627f..cd2bf9c 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -339,7 +339,6 @@ public class SettingsActivity extends ThemableSettingsActivity { break; } - mPreferences.setUseProxy(choice != 0); mPreferences.setProxyChoice(choice); if (choice < mProxyChoices.length) mProxyChoiceName.setText(mProxyChoices[choice]); diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index f03651d..78375ce 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -53,6 +53,7 @@ public class PreferenceManager { public static final String USE_PROXY_HOST = "useProxyHost"; public static final String USE_PROXY_PORT = "useProxyPort"; public static final String INITIAL_CHECK_FOR_TOR = "checkForTor"; + public static final String INITIAL_CHECK_FOR_I2P = "checkForI2P"; } private static PreferenceManager mInstance; @@ -87,6 +88,10 @@ public class PreferenceManager { return mPrefs.getBoolean(Name.INITIAL_CHECK_FOR_TOR, false); } + public boolean getCheckedForI2P() { + return mPrefs.getBoolean(Name.INITIAL_CHECK_FOR_I2P, false); + } + public boolean getClearCacheExit() { return mPrefs.getBoolean(Name.CLEAR_CACHE_EXIT, false); } @@ -271,6 +276,10 @@ public class PreferenceManager { putBoolean(Name.INITIAL_CHECK_FOR_TOR, check); } + public void setCheckedForI2P(boolean check) { + putBoolean(Name.INITIAL_CHECK_FOR_I2P, check); + } + public void setClearCacheExit(boolean enable) { putBoolean(Name.CLEAR_CACHE_EXIT, enable); } @@ -399,11 +408,13 @@ public class PreferenceManager { putBoolean(Name.DARK_THEME, use); } - public void setUseProxy(boolean enable) { - putBoolean(Name.USE_PROXY, enable); - } - + /** + * 0: None. 1: Orbot. 2: I2P. + * + * @param choice the proxy to use. + */ public void setProxyChoice(int choice) { + putBoolean(Name.USE_PROXY, choice != 0); putInt(Name.PROXY_CHOICE, choice); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3bccd84..42b77ff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -165,6 +165,7 @@ I2P It looks like you have Orbot installed. Do you want to use Tor? + It looks like you have I2P installed. Do you want to use I2P? Please install Orbot in order to proxy with Tor. Yes No From 6e8da9f6d30fa9dd316466716eb2ed5db3d5cc87 Mon Sep 17 00:00:00 2001 From: str4d Date: Tue, 26 May 2015 03:25:47 +0000 Subject: [PATCH 4/8] Fix for I2PAndroidHelper.isI2PAndroidRunning() always returning false Requires v0.7 of the I2P client library, which will be released once I2P 0.9.20 is released. --- app/build.gradle | 2 +- app/proguard-project.txt | 7 ++++--- .../lightning/activity/BrowserActivity.java | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ef8e7f7..ddbae40 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,5 +39,5 @@ dependencies { compile 'com.android.support:palette-v7:22.1.1' compile 'com.android.support:appcompat-v7:22.1.1' compile 'org.jsoup:jsoup:1.8.1' - compile 'net.i2p.android:client:0.6@aar' + compile 'net.i2p.android:client:0.7@aar' } diff --git a/app/proguard-project.txt b/app/proguard-project.txt index 382c1d4..c821b33 100644 --- a/app/proguard-project.txt +++ b/app/proguard-project.txt @@ -78,7 +78,8 @@ # platform version. We know about them, and they are safe. -dontwarn android.support.** -# The I2P Java API bundled inside the I2P Android client library contains a -# method that references classes in javax.naming that Android doesn't have. But -# the method never uses those classes on Android, and is safe. +# The I2P Java API bundled inside the I2P Android client library contains +# references to javax.naming classes that Android doesn't have. But those +# classes are never used on Android, and it is safe to ignore the warnings. -dontwarn net.i2p.crypto.CertUtil +-dontwarn org.apache.http.conn.ssl.DefaultHostnameVerifier diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index f06169c..13d8262 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -184,6 +184,8 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll // Helper private I2PAndroidHelper mI2PHelper; + private boolean mI2PHelperBound; + private boolean mI2PProxyInitialized; // Constant private static final int API = android.os.Build.VERSION.SDK_INT; @@ -626,7 +628,8 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll break; case 2: - if (!mI2PHelper.isI2PAndroidRunning()) { + mI2PProxyInitialized = true; + if (mI2PHelperBound && !mI2PHelper.isI2PAndroidRunning()) { mI2PHelper.requestI2PAndroidStart(this); } host = "localhost"; @@ -807,6 +810,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll } catch (Exception e) { e.printStackTrace(); } + mI2PProxyInitialized = false; } } @@ -1468,6 +1472,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll protected void onStop() { super.onStop(); mI2PHelper.unbind(); + mI2PHelperBound = false; } @Override @@ -1484,7 +1489,14 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll super.onStart(); if (mPreferences.getProxyChoice() == 2) { // Try to bind to I2P Android - mI2PHelper.bind(); + mI2PHelper.bind(new I2PAndroidHelper.Callback() { + @Override + public void onI2PAndroidBound() { + mI2PHelperBound = true; + if (mI2PProxyInitialized && !mI2PHelper.isI2PAndroidRunning()) + mI2PHelper.requestI2PAndroidStart(BrowserActivity.this); + } + }); } } From a5a20eebbda0bcbd7dcaf5553a189123365d4fc8 Mon Sep 17 00:00:00 2001 From: str4d Date: Tue, 26 May 2015 10:36:02 +0000 Subject: [PATCH 5/8] Notify user if proxy is not ready when they try to load a URL --- .../lightning/activity/BrowserActivity.java | 14 ++++++++++++++ .../controller/BrowserController.java | 2 ++ .../browser/lightning/view/LightningView.java | 18 ++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 4 files changed, 36 insertions(+) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 13d8262..78f92b9 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -650,6 +650,20 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll } + public boolean isProxyReady() { + if (mPreferences.getProxyChoice() == 2) { + if (!mI2PHelper.isI2PAndroidRunning()) { + Utils.showToast(this, getString(R.string.i2p_not_running)); + return false; + } else if (!mI2PHelper.areTunnelsActive()) { + Utils.showToast(this, getString(R.string.i2p_tunnels_not_ready)); + return false; + } + } + + return true; + } + private boolean isTablet() { return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE; } diff --git a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java index 8fdbd53..c48e805 100644 --- a/app/src/main/java/acr/browser/lightning/controller/BrowserController.java +++ b/app/src/main/java/acr/browser/lightning/controller/BrowserController.java @@ -54,5 +54,7 @@ public interface BrowserController { boolean isIncognito(); + boolean isProxyReady(); + int getMenu(); } diff --git a/app/src/main/java/acr/browser/lightning/view/LightningView.java b/app/src/main/java/acr/browser/lightning/view/LightningView.java index f50b87d..d65fc4c 100644 --- a/app/src/main/java/acr/browser/lightning/view/LightningView.java +++ b/app/src/main/java/acr/browser/lightning/view/LightningView.java @@ -526,6 +526,12 @@ public class LightningView { } public synchronized void reload() { + // Check if configured proxy is available + if (!mBrowserController.isProxyReady()) { + // User has been notified + return; + } + if (mWebView != null) { mWebView.reload(); } @@ -611,6 +617,12 @@ public class LightningView { } public synchronized void loadUrl(String url) { + // Check if configured proxy is available + if (!mBrowserController.isProxyReady()) { + // User has been notified + return; + } + if (mWebView != null) { mWebView.loadUrl(url); } @@ -815,6 +827,12 @@ public class LightningView { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { + // Check if configured proxy is available + if (!mBrowserController.isProxyReady()) { + // User has been notified + return true; + } + if (mBrowserController.isIncognito()) { return super.shouldOverrideUrlLoading(view, url); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 42b77ff..392068c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -167,6 +167,8 @@ It looks like you have Orbot installed. Do you want to use Tor? It looks like you have I2P installed. Do you want to use I2P? Please install Orbot in order to proxy with Tor. + I2P is not running. + I2P tunnels are not ready yet. Yes No Clear cookies on exit From a0b2197d8fc5507bc6e17f623b42e71f00feaaef Mon Sep 17 00:00:00 2001 From: str4d Date: Tue, 26 May 2015 10:52:58 +0000 Subject: [PATCH 6/8] Use constants for proxy choices --- .../browser/lightning/activity/BrowserActivity.java | 10 +++++----- .../browser/lightning/activity/SettingsActivity.java | 8 ++++---- .../java/acr/browser/lightning/constant/Constants.java | 5 +++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 78f92b9..7b23d91 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -614,11 +614,11 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll int port; switch (mPreferences.getProxyChoice()) { - case 0: + case Constants.NO_PROXY: // We shouldn't be here return; - case 1: + case Constants.PROXY_ORBOT: OrbotHelper oh = new OrbotHelper(this); if (!oh.isOrbotRunning()) { oh.requestOrbotStart(this); @@ -627,7 +627,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll port = 8118; break; - case 2: + case Constants.PROXY_I2P: mI2PProxyInitialized = true; if (mI2PHelperBound && !mI2PHelper.isI2PAndroidRunning()) { mI2PHelper.requestI2PAndroidStart(this); @@ -651,7 +651,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll } public boolean isProxyReady() { - if (mPreferences.getProxyChoice() == 2) { + if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) { if (!mI2PHelper.isI2PAndroidRunning()) { Utils.showToast(this, getString(R.string.i2p_not_running)); return false; @@ -1501,7 +1501,7 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll @Override protected void onStart() { super.onStart(); - if (mPreferences.getProxyChoice() == 2) { + if (mPreferences.getProxyChoice() == Constants.PROXY_I2P) { // Try to bind to I2P Android mI2PHelper.bind(new I2PAndroidHelper.Callback() { @Override diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index cd2bf9c..80e17ec 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -322,18 +322,18 @@ public class SettingsActivity extends ThemableSettingsActivity { private void setProxyChoice(int choice) { switch (choice) { - case 1: + case Constants.PROXY_ORBOT: OrbotHelper oh = new OrbotHelper(this); if (!oh.isOrbotInstalled()) { - choice = 0; + choice = Constants.NO_PROXY; Utils.showToast(mContext, getResources().getString(R.string.install_orbot)); } break; - case 2: + case Constants.PROXY_I2P: I2PAndroidHelper ih = new I2PAndroidHelper(this); if (!ih.isI2PAndroidInstalled()) { - choice = 0; + choice = Constants.NO_PROXY; ih.promptToInstall(this); } break; diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index f8a25ce..4c15eb9 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -38,4 +38,9 @@ public final class Constants { public static final String FILE = "file://"; public static final String FOLDER = "folder://"; public static final String TAG = "Lightning"; + + // These should match the order of @array/proxy_choices_array + public static final int NO_PROXY = 0; + public static final int PROXY_ORBOT = 1; + public static final int PROXY_I2P = 2; } From 810483ec74181a1fee3f7dfe04048905a29eb969 Mon Sep 17 00:00:00 2001 From: str4d Date: Tue, 26 May 2015 12:52:11 +0000 Subject: [PATCH 7/8] Use constants for proxy choices, part 2 --- .../browser/lightning/activity/BrowserActivity.java | 5 +++-- .../lightning/preference/PreferenceManager.java | 11 ++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java index 7b23d91..8190213 100644 --- a/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/BrowserActivity.java @@ -588,11 +588,12 @@ public class BrowserActivity extends ThemableActivity implements BrowserControll public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: - mPreferences.setProxyChoice(orbotInstalled ? 1 : 2); + mPreferences.setProxyChoice(orbotInstalled ? + Constants.PROXY_ORBOT : Constants.PROXY_I2P); initializeProxy(); break; case DialogInterface.BUTTON_NEGATIVE: - mPreferences.setProxyChoice(0); + mPreferences.setProxyChoice(Constants.NO_PROXY); break; } } diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index 78375ce..224959f 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -233,7 +233,7 @@ public class PreferenceManager { } public int getProxyChoice() { - return mPrefs.getInt(Name.PROXY_CHOICE, 0); + return mPrefs.getInt(Name.PROXY_CHOICE, Constants.NO_PROXY); } public int getUserAgentChoice() { @@ -409,12 +409,17 @@ public class PreferenceManager { } /** - * 0: None. 1: Orbot. 2: I2P. + * Valid choices: + *
    + *
  • {@link Constants#NO_PROXY}
  • + *
  • {@link Constants#PROXY_ORBOT}
  • + *
  • {@link Constants#PROXY_I2P}
  • + *
* * @param choice the proxy to use. */ public void setProxyChoice(int choice) { - putBoolean(Name.USE_PROXY, choice != 0); + putBoolean(Name.USE_PROXY, choice != Constants.NO_PROXY); putInt(Name.PROXY_CHOICE, choice); } From 2eec8be4ce9944aafd88730d47d00287e0bcddd3 Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 3 Jun 2015 06:50:32 +0000 Subject: [PATCH 8/8] Add manual proxy picker --- .../lightning/activity/SettingsActivity.java | 32 +++++++++++++- .../browser/lightning/constant/Constants.java | 1 + .../preference/PreferenceManager.java | 8 ++++ .../main/res/layout/picker_manual_proxy.xml | 43 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 ++ 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/layout/picker_manual_proxy.xml diff --git a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java index 80e17ec..9ee017a 100644 --- a/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java +++ b/app/src/main/java/acr/browser/lightning/activity/SettingsActivity.java @@ -98,7 +98,10 @@ public class SettingsActivity extends ThemableSettingsActivity { mProxyChoiceName = (TextView) findViewById(R.id.proxyChoiceName); mProxyChoices = this.getResources().getStringArray(R.array.proxy_choices_array); int choice = mPreferences.getProxyChoice(); - mProxyChoiceName.setText(mProxyChoices[choice]); + if (choice == Constants.PROXY_MANUAL) + mProxyChoiceName.setText(mPreferences.getProxyHost() + ":" + mPreferences.getProxyPort()); + else + mProxyChoiceName.setText(mProxyChoices[choice]); CheckBox flash = (CheckBox) findViewById(R.id.cbFlash); CheckBox adblock = (CheckBox) findViewById(R.id.cbAdblock); @@ -337,6 +340,10 @@ public class SettingsActivity extends ThemableSettingsActivity { ih.promptToInstall(this); } break; + + case Constants.PROXY_MANUAL: + manualProxyPicker(); + break; } mPreferences.setProxyChoice(choice); @@ -344,6 +351,29 @@ public class SettingsActivity extends ThemableSettingsActivity { mProxyChoiceName.setText(mProxyChoices[choice]); } + public void manualProxyPicker() { + View v = getLayoutInflater().inflate(R.layout.picker_manual_proxy, null); + final EditText eProxyHost = (EditText) v.findViewById(R.id.proxyHost); + final EditText eProxyPort = (EditText) v.findViewById(R.id.proxyPort); + eProxyHost.setText(mPreferences.getProxyHost()); + eProxyPort.setText(Integer.toString(mPreferences.getProxyPort())); + + new AlertDialog.Builder(mActivity) + .setTitle(R.string.manual_proxy) + .setView(v) + .setPositiveButton(R.string.action_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + String proxyHost = eProxyHost.getText().toString(); + int proxyPort = Integer.parseInt(eProxyPort.getText().toString()); + mPreferences.setProxyHost(proxyHost); + mPreferences.setProxyPort(proxyPort); + mProxyChoiceName.setText(proxyHost + ":" + proxyPort); + } + }) + .show(); + } + public void agentPicker() { final AlertDialog.Builder agentStringPicker = new AlertDialog.Builder(mActivity); diff --git a/app/src/main/java/acr/browser/lightning/constant/Constants.java b/app/src/main/java/acr/browser/lightning/constant/Constants.java index 4c15eb9..c3ba14c 100644 --- a/app/src/main/java/acr/browser/lightning/constant/Constants.java +++ b/app/src/main/java/acr/browser/lightning/constant/Constants.java @@ -43,4 +43,5 @@ public final class Constants { public static final int NO_PROXY = 0; public static final int PROXY_ORBOT = 1; public static final int PROXY_I2P = 2; + public static final int PROXY_MANUAL = 3; } diff --git a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java index 224959f..c6d1316 100644 --- a/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java +++ b/app/src/main/java/acr/browser/lightning/preference/PreferenceManager.java @@ -423,6 +423,14 @@ public class PreferenceManager { putInt(Name.PROXY_CHOICE, choice); } + public void setProxyHost(String proxyHost) { + putString(Name.USE_PROXY_HOST, proxyHost); + } + + public void setProxyPort(int proxyPort) { + putInt(Name.USE_PROXY_PORT, proxyPort); + } + public void setUserAgentChoice(int choice) { putInt(Name.USER_AGENT, choice); } diff --git a/app/src/main/res/layout/picker_manual_proxy.xml b/app/src/main/res/layout/picker_manual_proxy.xml new file mode 100644 index 0000000..f8568ac --- /dev/null +++ b/app/src/main/res/layout/picker_manual_proxy.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 392068c..71099f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -163,7 +163,11 @@ None Orbot I2P + Manual + Manual proxy + Host: + Port: It looks like you have Orbot installed. Do you want to use Tor? It looks like you have I2P installed. Do you want to use I2P? Please install Orbot in order to proxy with Tor.