diff --git a/app/build.gradle b/app/build.gradle index a2e167e4..f8aee685 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,6 +37,7 @@ dependencies { // More libraries compile 'com.getbase:floatingactionbutton:1.9.1' compile 'com.jakewharton:butterknife:8.0.1' + compile 'info.guardianproject.netcipher:netcipher:1.2.1' apt 'com.jakewharton:butterknife-compiler:8.0.1' } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java index f4a64846..04240c73 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java @@ -23,7 +23,9 @@ import android.Manifest; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlarmManager; import android.app.AlertDialog; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; @@ -32,9 +34,11 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; +import android.os.StrictMode; import android.provider.MediaStore; import android.support.annotation.NonNull; import android.support.design.widget.CollapsingToolbarLayout; @@ -46,6 +50,7 @@ import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.ActionMenuView; +import android.support.v7.widget.SwitchCompat; import android.support.v7.widget.Toolbar; import android.text.Html; import android.text.SpannableString; @@ -66,6 +71,7 @@ import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; @@ -97,6 +103,8 @@ import java.util.Locale; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import info.guardianproject.netcipher.NetCipher; +import info.guardianproject.netcipher.web.WebkitProxy; public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, WebUserProfileChangedListener { @@ -216,6 +224,11 @@ public class MainActivity extends AppCompatActivity if (android.os.Build.VERSION.SDK_INT >= 21) webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + //Set proxy + if(appSettings.isProxyEnabled()) { + if(!setProxy()) Toast.makeText(this, R.string.toast_set_proxy_failed, Toast.LENGTH_LONG).show(); + } + /* * WebViewClient */ @@ -885,7 +898,7 @@ public class MainActivity extends AppCompatActivity case R.id.nav_aspects: { if (Helpers.isOnline(MainActivity.this)) { - // webView.loadUrl("https://" + podDomain + "/aspects"); + // webView.loadUrl("https://" + podDomain + "/aspects"); Helpers.showAspectList(webView, app); setTitle(R.string.title_aspects); } else { @@ -946,7 +959,8 @@ public class MainActivity extends AppCompatActivity case R.id.nav_settings_app: { final CharSequence[] options = {getString(R.string.settings_font), getString(R.string.settings_view), appSettings.isLoadImages() ? - getString(R.string.settings_images_switch_off) : getString(R.string.settings_images_switch_on), getString(R.string.jb_pod)}; + getString(R.string.settings_images_switch_off) : getString(R.string.settings_images_switch_on), getString(R.string.jb_pod), + getString(R.string.settings_proxy)}; if (Helpers.isOnline(MainActivity.this)) { new AlertDialog.Builder(MainActivity.this) @@ -979,6 +993,33 @@ public class MainActivity extends AppCompatActivity }) .show(); break; + case 4: + final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this); + final View dialogLayout = getLayoutInflater().inflate(R.layout.proxy_configuration_dialog, null); + final SwitchCompat enabled_toggle = (SwitchCompat) dialogLayout.findViewById(R.id.proxy_toggle); + final EditText host_edit = (EditText) dialogLayout.findViewById(R.id.proxy_host_edit); + final EditText port_edit = (EditText) dialogLayout.findViewById(R.id.proxy_port_edit); + + enabled_toggle.setChecked(appSettings.isProxyEnabled()); + host_edit.setText(appSettings.getProxyHost()); + port_edit.setText(""+appSettings.getProxyPort()); + dialogBuilder.setView(dialogLayout).setTitle(R.string.settings_proxy) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + boolean proxyEnabled = enabled_toggle.isChecked(); + String host = host_edit.getText().toString(); + int port = Integer.parseInt(port_edit.getText().toString()); + + if(proxyEnabled) { + if(!setProxy(host, port)) { + Toast.makeText(MainActivity.this, R.string.toast_set_proxy_failed,Toast.LENGTH_SHORT).show(); + } + } + else resetProxy(); + } + }).setNegativeButton(android.R.string.cancel, null).show(); + break; } } }).show(); @@ -1069,4 +1110,66 @@ public class MainActivity extends AppCompatActivity grantResults); } } + + /** + * Set proxy according to arguments. host must not be "" or null, port must be positive. + * Return true on success and update appSettings' proxy related values. + * @param host proxy host (eg. localhost or 127.0.0.1) + * @param port proxy port (eg. 8118) + * @return success + * @throws IllegalArgumentException if arguments do not fit specifications above + */ + private boolean setProxy(final String host, final int port) { + if(host != null && !host.equals("") && port >=0) { + //Temporary change thread policy + StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); + StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(tmp); + + NetCipher.setProxy(host, port); //Proxy for HttpsUrlConnections + try { + //Proxy for the webview + WebkitProxy.setProxy(MainActivity.class.getName(), getApplicationContext(), null, host, port); + } catch (Exception e) { /*Nothing we can do*/ } + + appSettings.setProxyEnabled(true); + appSettings.setProxyHost(host); + appSettings.setProxyPort(port); + + StrictMode.setThreadPolicy(old); + webView.reload(); + return true; + } else { + return false; + } + } + + private boolean setProxy() { + return setProxy(appSettings.getProxyHost(), appSettings.getProxyPort()); + } + + private void resetProxy() { + appSettings.setProxyEnabled(false); + + //Temporary change thread policy + StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy(); + StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(tmp); + + NetCipher.clearProxy(); + try{ + WebkitProxy.resetProxy(MainActivity.class.getName(), this); + } catch (Exception e) { + //Nothing we can do. + } + + StrictMode.setThreadPolicy(old); + + //Restart app + Intent restartActivity = new Intent(this, MainActivity.class); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT); + AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent); + System.exit(0); + } } \ No newline at end of file diff --git a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java index fe4e3178..77cc3ed7 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java @@ -70,6 +70,9 @@ public class AppSettings { private static final String PODUSERPROFILE_ID = "podUserProfile_guid"; private static final String PODDOMAIN = "podDomain"; private static final String PODUSERPROFILE_ASPECTS = "podUserProfile_aspects"; + private static final String PROXY_ENABLED = "isProxyEnabled"; + private static final String PROXY_HOST = "proxyHost"; + private static final String PROXY_PORT = "proxyPort"; } @@ -150,4 +153,41 @@ public class AppSettings { } return aspects; } + + public void setProxyEnabled(boolean enabled) { + //commit instead of apply because the app is likely to be killed before apply is called. + prefApp.edit().putBoolean(PREF.PROXY_ENABLED, enabled).commit(); + } + + /** + * Default return value: false + * @return whether proxy is enabled or not + */ + public boolean isProxyEnabled() { + return prefApp.getBoolean(PREF.PROXY_ENABLED, false); + } + + public void setProxyHost(String host) { + setString(prefApp, PREF.PROXY_HOST, host); + } + + /** + * Default value: "" + * @return proxy host + */ + public String getProxyHost() { + return prefApp.getString(PREF.PROXY_HOST, ""); + } + + public void setProxyPort(int port) { + setInt(prefApp, PREF.PROXY_PORT, port); + } + + /** + * Default value: 0 + * @return proxy port + */ + public int getProxyPort() { + return prefApp.getInt(PREF.PROXY_PORT, 0); + } } diff --git a/app/src/main/res/layout/proxy_configuration_dialog.xml b/app/src/main/res/layout/proxy_configuration_dialog.xml new file mode 100644 index 00000000..75bc4330 --- /dev/null +++ b/app/src/main/res/layout/proxy_configuration_dialog.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + \ 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 33c428cd..78f62f41 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -78,6 +78,10 @@ Do load images Do not load images Change view + Proxy + Enabled + Host + Port Share link as text Share screenshot of webpage Take screenshot of webpage @@ -218,4 +222,6 @@ https:// Share… #DiasporaForAndroid + + Warning: Could not set network proxy…