From ef255d12ae3704b94441d7ac4bcacc4e2ad40f6f Mon Sep 17 00:00:00 2001 From: GDR! Date: Thu, 24 Dec 2015 14:55:33 +0100 Subject: [PATCH 01/10] Test tor code --- app/build.gradle | 3 +- .../java/org/schabi/newpipe/Downloader.java | 8 +++-- .../org/schabi/newpipe/PlayVideoActivity.java | 30 ++++++++++++++++++- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/settings_screen.xml | 5 ++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index fb4598597..9eb3ccef7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - + lintOptions { checkReleaseBuilds false // Or, if you prefer, you can continue to check for errors in release builds, @@ -35,4 +35,5 @@ dependencies { compile 'com.android.support:recyclerview-v7:23.1.1' compile 'org.jsoup:jsoup:1.8.3' compile 'org.mozilla:rhino:1.7.7' + compile 'info.guardianproject.netcipher:netcipher:1.2' } diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index f0a19cfc5..c15c2ddc3 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -7,6 +7,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; +import info.guardianproject.netcipher.NetCipher; + /** * Created by Christian Schabesberger on 14.08.15. * @@ -37,10 +39,11 @@ public class Downloader { * @param language the language (usually a 2-character code) to set as the preferred language * @return the contents of the specified text file*/ public static String download(String siteUrl, String language) { + NetCipher.useTor(); String ret = ""; try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -81,10 +84,11 @@ public class Downloader { * @return the contents of the specified text file*/ public static String download(String siteUrl) { String ret = ""; + NetCipher.useTor(); try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); ret = dl(con); } catch(Exception e) { diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index d5fea8c3e..a7aeda10f 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.media.MediaPlayer; @@ -25,6 +26,7 @@ import android.widget.Button; import android.widget.MediaController; import android.widget.ProgressBar; import android.widget.VideoView; +import info.guardianproject.netcipher.NetCipher; /** * Copyright (C) Christian Schabesberger 2015 @@ -44,7 +46,7 @@ import android.widget.VideoView; * along with NewPipe. If not, see . */ -public class PlayVideoActivity extends AppCompatActivity { +public class PlayVideoActivity extends AppCompatActivity implements OnSharedPreferenceChangeListener { //// TODO: 11.09.15 add "choose stream" menu @@ -170,6 +172,9 @@ public class PlayVideoActivity extends AppCompatActivity { if(prefs.getBoolean(PREF_IS_LANDSCAPE, false) && !isLandscape) { toggleOrientation(); } + + setTorPreference(prefs); + prefs.registerOnSharedPreferenceChangeListener(this); } @Override @@ -187,6 +192,13 @@ public class PlayVideoActivity extends AppCompatActivity { videoView.pause(); } + @Override + protected void onDestroy() { + super.onDestroy(); + prefs = getPreferences(Context.MODE_PRIVATE); + prefs.unregisterOnSharedPreferenceChangeListener(this); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); @@ -348,4 +360,20 @@ public class PlayVideoActivity extends AppCompatActivity { editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape); editor.apply(); } + + private void setTorPreference(SharedPreferences prefs) { + if(prefs.getBoolean(getString(R.string.useTor), false)) { + NetCipher.useTor(); + } else { + NetCipher.setProxy(null); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if(key.equals(getString(R.string.useTor))) { + setTorPreference(prefs); + } + } + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12fb9275d..c2d1becdd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,4 +63,6 @@ Uploader thumbnail Dislikes Likes + Use Tor + Proxy connections via The Onion Router diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index d4b21426f..953ded807 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -72,5 +72,10 @@ android:summary="@string/autoPlayThroughIntentSummary" android:defaultValue="false" /> + + From 0265da4ae61286b8137185108bdd10a1cde51931 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 24 Dec 2015 14:55:33 +0100 Subject: [PATCH 02/10] use HttpsURLConnections since youtube.com always uses HTTPS This helps enforce that the connection is encrypted. If for whatever reason an unencrypted connection is created, an Exception will be thrown. --- app/src/main/java/org/schabi/newpipe/Downloader.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index c15c2ddc3..9e33ce322 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -7,6 +7,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; +import javax.net.ssl.HttpsURLConnection; + import info.guardianproject.netcipher.NetCipher; /** @@ -43,7 +45,7 @@ public class Downloader { String ret = ""; try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); + HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -88,7 +90,7 @@ public class Downloader { try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); + HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); ret = dl(con); } catch(Exception e) { From e63d43151b711bdc032ae851c5eb053939026b77 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 19:45:41 +0100 Subject: [PATCH 03/10] add a title plus summary to "Use Tor" preference --- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/xml/settings_screen.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c2d1becdd..c7058759e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -64,5 +64,5 @@ Dislikes Likes Use Tor - Proxy connections via The Onion Router + Force download traffic through Tor for increased privacy (streaming videos not yet supported) diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 953ded807..f7ab99a53 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -74,7 +74,8 @@ From 6bd2468d44b09df89d95c999a98f7045c246303e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 20:29:21 +0100 Subject: [PATCH 04/10] if Orbot is installed, then default to using Tor If the user has not changed the "Use Tor" preference, then the default should be to use Tor if Orbot is installed. The user can still override it by going an unchecking "Use Tor". --- app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index a7aeda10f..f5e595624 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -27,6 +27,7 @@ import android.widget.MediaController; import android.widget.ProgressBar; import android.widget.VideoView; import info.guardianproject.netcipher.NetCipher; +import info.guardianproject.netcipher.proxy.OrbotHelper; /** * Copyright (C) Christian Schabesberger 2015 @@ -362,7 +363,8 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref } private void setTorPreference(SharedPreferences prefs) { - if(prefs.getBoolean(getString(R.string.useTor), false)) { + // if Orbot is installed, then default to using Tor, the user can still override + if(prefs.getBoolean(getString(R.string.useTor), OrbotHelper.isOrbotInstalled(this))) { NetCipher.useTor(); } else { NetCipher.setProxy(null); From d3879a03982f3e8da4831704fb0ef280b884405f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 22:16:41 +0100 Subject: [PATCH 05/10] setup Tor at app start, and config immediately when pref is changed This adds an Application subclass to get the onCreate() method, which is called once at the first start up of the app, before any Activity starts. Tor is configured there to ensure it is setup before anything happens. This also moves the "Use Tor" pref listener to a more appropriate place. --- app/src/main/AndroidManifest.xml | 1 + app/src/main/java/org/schabi/newpipe/App.java | 32 +++++++++++++++++++ .../java/org/schabi/newpipe/Downloader.java | 2 -- .../org/schabi/newpipe/PlayVideoActivity.java | 26 +-------------- .../org/schabi/newpipe/SettingsActivity.java | 19 +++++++++++ app/src/main/res/xml/settings_screen.xml | 3 +- 6 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/App.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d028886b1..ef84c57b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ @@ -47,7 +44,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; * along with NewPipe. If not, see . */ -public class PlayVideoActivity extends AppCompatActivity implements OnSharedPreferenceChangeListener { +public class PlayVideoActivity extends AppCompatActivity { //// TODO: 11.09.15 add "choose stream" menu @@ -173,9 +170,6 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref if(prefs.getBoolean(PREF_IS_LANDSCAPE, false) && !isLandscape) { toggleOrientation(); } - - setTorPreference(prefs); - prefs.registerOnSharedPreferenceChangeListener(this); } @Override @@ -197,7 +191,6 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref protected void onDestroy() { super.onDestroy(); prefs = getPreferences(Context.MODE_PRIVATE); - prefs.unregisterOnSharedPreferenceChangeListener(this); } @Override @@ -361,21 +354,4 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape); editor.apply(); } - - private void setTorPreference(SharedPreferences prefs) { - // if Orbot is installed, then default to using Tor, the user can still override - if(prefs.getBoolean(getString(R.string.useTor), OrbotHelper.isOrbotInstalled(this))) { - NetCipher.useTor(); - } else { - NetCipher.setProxy(null); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - if(key.equals(getString(R.string.useTor))) { - setTorPreference(prefs); - } - } - } diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index c8a548ab6..c8c089a98 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -2,6 +2,8 @@ package org.schabi.newpipe; import android.content.res.Configuration; import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.support.annotation.LayoutRes; @@ -13,6 +15,8 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import info.guardianproject.netcipher.proxy.OrbotHelper; + /** * Created by Christian Schabesberger on 31.08.15. * @@ -52,10 +56,25 @@ public class SettingsActivity extends PreferenceActivity { } public static class SettingsFragment extends PreferenceFragment { + private CheckBoxPreference useTorCheckBox; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings_screen); + + // if Orbot is installed, then default to using Tor, the user can still override + useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor)); + boolean useTor = OrbotHelper.isOrbotInstalled(getActivity()); + useTorCheckBox.setDefaultValue(useTor); + useTorCheckBox.setChecked(useTor); + useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object useTor) { + App.configureTor((Boolean) useTor); + return true; + } + }); } } diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index f7ab99a53..4d21b457b 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -75,8 +75,7 @@ + android:summary="@string/useTorSummary" /> From 5663e543a47eb90af320e5ebb09fcd2b8243c36d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:04:29 +0100 Subject: [PATCH 06/10] whenever an Activity resumes and tor is enabled, request it start This makes sure that Orbot is running when the user expects it to be. If NewPipe is configured to use Tor, then going to a NewPipe screen should ensure Tor is running. --- app/src/main/java/org/schabi/newpipe/App.java | 12 +++++++++++- .../java/org/schabi/newpipe/PlayVideoActivity.java | 6 ++++++ .../org/schabi/newpipe/VideoItemDetailActivity.java | 6 ++++++ .../org/schabi/newpipe/VideoItemListActivity.java | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index a8afccd4a..95127d7fe 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -1,6 +1,7 @@ package org.schabi.newpipe; import android.app.Application; +import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -9,6 +10,8 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; public class App extends Application { + private static boolean useTor; + @Override public void onCreate() { super.onCreate(); @@ -22,11 +25,18 @@ public class App extends Application { /** * Set the proxy settings based on whether Tor should be enabled or not. */ - static void configureTor(boolean useTor) { + static void configureTor(boolean enabled) { + useTor = enabled; if (useTor) { NetCipher.useTor(); } else { NetCipher.setProxy(null); } } + + static void checkStartTor(Context context) { + if (useTor) { + OrbotHelper.requestStartTor(context); + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index 2500c7dfe..13a1cefed 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -187,6 +187,12 @@ public class PlayVideoActivity extends AppCompatActivity { videoView.pause(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index 4a553241f..f93ca4b9e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -113,6 +113,12 @@ public class VideoItemDetailActivity extends AppCompatActivity { .commit(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + @Override public void onSaveInstanceState(Bundle outState) { outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index d15709b23..8c4f5c57e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -175,6 +175,12 @@ public class VideoItemListActivity extends AppCompatActivity PreferenceManager.setDefaultValues(this, R.xml.settings_screen, false); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + /** * Callback method from {@link VideoItemListFragment.Callbacks} * indicating that the item with the given ID was selected. From 984dd1cc25d6add07d136a6a602e836fb99f8462 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:06:16 +0100 Subject: [PATCH 07/10] checking on "Use Tor" when Orbot is not installed starts install If the user turns on "Use Tor" and they are missing Orbot, bring them to the screen to install Tor. --- .../org/schabi/newpipe/SettingsActivity.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index c8c089a98..f599ebd8b 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,5 +1,8 @@ package org.schabi.newpipe; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.preference.CheckBoxPreference; @@ -39,6 +42,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; public class SettingsActivity extends PreferenceActivity { + private static final int REQUEST_INSTALL_ORBOT = 0x1234; private AppCompatDelegate mDelegate = null; @Override @@ -65,19 +69,39 @@ public class SettingsActivity extends PreferenceActivity { // if Orbot is installed, then default to using Tor, the user can still override useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor)); - boolean useTor = OrbotHelper.isOrbotInstalled(getActivity()); + final Activity activity = getActivity(); + final boolean useTor = OrbotHelper.isOrbotInstalled(activity); useTorCheckBox.setDefaultValue(useTor); useTorCheckBox.setChecked(useTor); useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object useTor) { - App.configureTor((Boolean) useTor); + public boolean onPreferenceChange(Preference preference, Object o) { + boolean useTor = (Boolean) o; + if (useTor) { + if (OrbotHelper.isOrbotInstalled(activity)) { + App.configureTor(true); + } else { + Intent intent = OrbotHelper.getOrbotInstallIntent(activity); + activity.startActivityForResult(intent, REQUEST_INSTALL_ORBOT); + } + } else { + App.configureTor(false); + } return true; } }); } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + // try to start tor regardless of resultCode since clicking back after + // installing the app does not necessarily return RESULT_OK + App.configureTor(requestCode == REQUEST_INSTALL_ORBOT + && OrbotHelper.requestStartTor(this)); + } + @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); From b3a1a5dcc23ebc9de26137bdc31a3700ca22d43d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 21:53:48 +0100 Subject: [PATCH 08/10] Android provides global vars for the actual download directories --- app/src/main/java/org/schabi/newpipe/DownloadDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 3001455f9..dd2f2c9d6 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -61,17 +61,17 @@ public class DownloadDialog extends DialogFragment { String suffix = ""; String title = arguments.getString(TITLE); String url = ""; - String downloadFolder = "Download"; + String downloadFolder = Environment.DIRECTORY_DOWNLOADS; switch(which) { case 0: // Video suffix = arguments.getString(FILE_SUFFIX_VIDEO); url = arguments.getString(VIDEO_URL); - downloadFolder = "Movies"; + downloadFolder = Environment.DIRECTORY_MOVIES; break; case 1: suffix = arguments.getString(FILE_SUFFIX_AUDIO); url = arguments.getString(AUDIO_URL); - downloadFolder = "Music"; + downloadFolder = Environment.DIRECTORY_MUSIC; break; default: Log.d(TAG, "lolz"); From 0bb0226bc2d0d8e90ccc91ce9252d3db6410bf85 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 22:47:21 +0100 Subject: [PATCH 09/10] download files via Tor when Tor is enabled DownloadManager does not let you set its proxy or change how it connects to the internet. So we have to make a custom one, unfortunately. This is a very basic downloader with none of the special sauce that makes the built-in DownloadManager handy. --- app/src/main/java/org/schabi/newpipe/App.java | 4 ++ .../org/schabi/newpipe/DownloadDialog.java | 24 +++++--- .../java/org/schabi/newpipe/Downloader.java | 56 +++++++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 95127d7fe..877000e61 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -39,4 +39,8 @@ public class App extends Application { OrbotHelper.requestStartTor(context); } } + + static boolean isUsingTor() { + return useTor; + } } diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index dd2f2c9d6..c53ab8512 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -87,15 +87,21 @@ public class DownloadDialog extends DialogFragment { //TODO notify user "download directory should be changed" ? } } - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request( - Uri.parse(url)); - request.setDestinationUri(Uri.fromFile(new File(dir + "/" + title + suffix))); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - try { - dm.enqueue(request); - } catch (Exception e) { - e.printStackTrace(); + String saveFilePath = dir + "/" + title + suffix; + if (App.isUsingTor()) { + // if using Tor, do not use DownloadManager because the proxy cannot be set + Downloader.downloadFile(url, saveFilePath); + } else { + DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request( + Uri.parse(url)); + request.setDestinationUri(Uri.fromFile(new File(saveFilePath))); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + try { + dm.enqueue(request); + } catch (Exception e) { + e.printStackTrace(); + } } } }); diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index f0fe75582..b1ada078c 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,9 +1,17 @@ package org.schabi.newpipe; +import android.os.AsyncTask; +import android.util.Log; + +import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; @@ -32,6 +40,7 @@ import info.guardianproject.netcipher.NetCipher; */ public class Downloader { + public static final String TAG = "Downloader"; private static final String USER_AGENT = "Mozilla/5.0"; @@ -97,4 +106,51 @@ public class Downloader { return ret; } + + /** + * Downloads a file from a URL in the background using an {@link AsyncTask}. + * + * @param fileURL HTTP URL of the file to be downloaded + * @param saveFilePath path of the directory to save the file + * @throws IOException + */ + public static void downloadFile(final String fileURL, final String saveFilePath) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + HttpsURLConnection con = null; + try { + con = NetCipher.getHttpsURLConnection(fileURL); + int responseCode = con.getResponseCode(); + + // always check HTTP response code first + if (responseCode == HttpURLConnection.HTTP_OK) { + InputStream inputStream = new BufferedInputStream(con.getInputStream()); + FileOutputStream outputStream = new FileOutputStream(saveFilePath); + + int bytesRead = -1; + byte[] buffer = new byte[8192]; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); + + } else { + Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (con != null) { + con.disconnect(); + con = null; + } + } + return null; + } + }.execute(); + } + } From 9127f7f0c22591353a4ba3da8737872a2502eb4e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 3 Jan 2016 00:04:55 +0100 Subject: [PATCH 10/10] make progress notification for Tor downloader (closes #39) --- .../org/schabi/newpipe/DownloadDialog.java | 2 +- .../java/org/schabi/newpipe/Downloader.java | 53 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index c53ab8512..1f018618a 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -90,7 +90,7 @@ public class DownloadDialog extends DialogFragment { String saveFilePath = dir + "/" + title + suffix; if (App.isUsingTor()) { // if using Tor, do not use DownloadManager because the proxy cannot be set - Downloader.downloadFile(url, saveFilePath); + Downloader.downloadFile(getContext(), url, saveFilePath); } else { DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request( diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index b1ada078c..8a296c61e 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,6 +1,12 @@ package org.schabi.newpipe; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.AsyncTask; +import android.support.v4.app.NotificationCompat; import android.util.Log; import java.io.BufferedInputStream; @@ -114,8 +120,28 @@ public class Downloader { * @param saveFilePath path of the directory to save the file * @throws IOException */ - public static void downloadFile(final String fileURL, final String saveFilePath) { - new AsyncTask() { + public static void downloadFile(final Context context, final String fileURL, final String saveFilePath) { + new AsyncTask() { + + private NotificationManager nm; + private NotificationCompat.Builder builder; + private int notifyId = 0x1234; + private int fileSize = 0xffffffff; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + Drawable icon = context.getResources().getDrawable(R.mipmap.ic_launcher); + builder = new NotificationCompat.Builder(context) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setLargeIcon(((BitmapDrawable) icon).getBitmap()) + .setContentTitle(saveFilePath.substring(saveFilePath.lastIndexOf('/') + 1)) + .setContentText(saveFilePath) + .setProgress(fileSize, 0, false); + nm.notify(notifyId, builder.build()); + } + @Override protected Void doInBackground(Void... voids) { HttpsURLConnection con = null; @@ -125,17 +151,26 @@ public class Downloader { // always check HTTP response code first if (responseCode == HttpURLConnection.HTTP_OK) { + fileSize = con.getContentLength(); InputStream inputStream = new BufferedInputStream(con.getInputStream()); FileOutputStream outputStream = new FileOutputStream(saveFilePath); + int bufferSize = 8192; + int downloaded = 0; + int bytesRead = -1; - byte[] buffer = new byte[8192]; + byte[] buffer = new byte[bufferSize]; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); + downloaded += bytesRead; + if (downloaded % 50000 < bufferSize) { + publishProgress(downloaded); + } } outputStream.close(); inputStream.close(); + publishProgress(bufferSize); } else { Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode); @@ -150,6 +185,18 @@ public class Downloader { } return null; } + + @Override + protected void onProgressUpdate(Integer... progress) { + builder.setProgress(fileSize, progress[0], false); + nm.notify(notifyId, builder.build()); + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + nm.cancel(notifyId); + } }.execute(); }