From 5d3cafb4a4fbb2bf851d36f973cc1e8b23ecebab Mon Sep 17 00:00:00 2001
From: Soren Stoutner Trotz ihrer Einschränkungen können Proxies unter bestimmen Umständen durchaus nützlich sein.
- Tor und I2p
+ Tor und I2P
existieren Android-Apps, die die einfache Nutzung dieser Proxy-Netzwerke ermöglichen.
Wird die Nutzung dieser Proxy-Netzwerke in Privacy Browser aktiviert, wird die App-Leiste mit einem hellblauen statt hellgrauen Hintergrund versehen.
Da der Datenverkehr in solchen Fällen jedoch über mehrere Proxy-Knoten geleitet wird,
diff --git a/app/src/main/assets/de/guide_proxies_light.html b/app/src/main/assets/de/guide_proxies_light.html
index 9aaa3b9b..841554df 100644
--- a/app/src/main/assets/de/guide_proxies_light.html
+++ b/app/src/main/assets/de/guide_proxies_light.html
@@ -77,7 +77,7 @@
Trotz ihrer Einschränkungen können Proxies unter bestimmen Umständen durchaus nützlich sein.
- Tor und I2p
+ Tor und I2P
existieren Android-Apps, die die einfache Nutzung dieser Proxy-Netzwerke ermöglichen.
Wird die Nutzung dieser Proxy-Netzwerke in Privacy Browser aktiviert, wird die App-Leiste mit einem hellblauen statt hellgrauen Hintergrund versehen.
Da der Datenverkehr in solchen Fällen jedoch über mehrere Proxy-Knoten geleitet wird,
diff --git a/app/src/main/assets/en/guide_proxies_dark.html b/app/src/main/assets/en/guide_proxies_dark.html
index cc723eab..a02c6e67 100644
--- a/app/src/main/assets/en/guide_proxies_dark.html
+++ b/app/src/main/assets/en/guide_proxies_dark.html
@@ -68,7 +68,7 @@
Despite their limitations, proxies can be useful in some circumstances.
- Tor and I2p
+ Tor and I2P
have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey.
Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet. Despite their limitations, proxies can be useful in some circumstances.
- Tor and I2p
+ Tor and I2P
have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey.
Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet. A pesar de sus limitaciones, los proxis pueden ser útiles en algunas circunstancias.
- Tor e I2p
+ Tor e I2P
tienen aplicaciones Android que facilitan el uso de sus redes de proxy. Cuando se activa el proxy en Navegador Privado,
la barra de aplicaciones tendrá un fondo azul claro en lugar del gris claro predeterminado.
Debido a que el tráfico está siendo enrutado a través de varios nodos proxy, usar un proxy en capas es a menudo mucho más lento que conectarse directamente a Internet. A pesar de sus limitaciones, los proxis pueden ser útiles en algunas circunstancias.
- Tor e I2p
+ Tor e I2P
tienen aplicaciones Android que facilitan el uso de sus redes de proxy. Cuando se activa el proxy en Navegador Privado,
la barra de aplicaciones tendrá un fondo azul claro en lugar del gris claro predeterminado.
Debido a que el tráfico está siendo enrutado a través de varios nodos proxy, usar un proxy en capas es a menudo mucho más lento que conectarse directamente a Internet. Malgré leurs limites, les proxies peuvent être utiles dans certaines circonstances.
- Tor et I2p
+ Tor et I2P
ont des applications Android qui facilitent l'utilisation de leurs réseaux proxy.
Lorsque le proxy est activé dans Privacy Browser, la barre d'application aura un fond bleu clair au lieu du gris clair par défaut.
Ãtant donné que le trafic est acheminé via plusieurs nÅuds proxy, l'utilisation d'un proxy en couches est souvent beaucoup plus lente que la connexion directe à Internet. Malgré leurs limites, les proxies peuvent être utiles dans certaines circonstances.
- Tor et I2p
+ Tor et I2P
ont des applications Android qui facilitent l'utilisation de leurs réseaux proxy.
Lorsque le proxy est activé dans Privacy Browser, la barre d'application aura un fond bleu clair au lieu du gris clair par défaut.
Ãtant donné que le trafic est acheminé via plusieurs nÅuds proxy, l'utilisation d'un proxy en couches est souvent beaucoup plus lente que la connexion directe à Internet. Esistono due categorie generali di cattivi soggetti che vogliono violare la privacy del web:
governi maliziosi con accesso agli ISP (Internet Service Providers) e mega corporations che gestiscono social network e agenzie pubblicitarie.
- Proxies like TOR (The Onion Router) and I2P (the Invisible Internet Project) are useful in protecting privacy from malicious governments (which spy on traffic in transit)
- but not from mega corporations (which embed malicious code on web servers). Nutzung von Proxies
Nutzung von Proxies
Using Proxies
Using Proxies
Uso de Proxis
Uso de Proxis
Utiliser des Proxies
Utiliser des Proxies
Proxies and Their Limits
+ I Proxy e i loro limiti
I governi malizionsi spesso spiano i loro cittadini per punire il dissenso o le attività di difesa dei diritti umani. Solitamente, o gestiscono loro stessi gli ISP locali oppure li obbligano a rivelare informazioni mostrando tutti gli indirizzi IP visitati da ciascun utente. - Layered proxies are designed to defeat this infringement of privacy by encrypting the traffic from a userâs device and routing it through multiple servers on the internet - before sending it on to the final destination. - This means that no individual ISP, server, or website, can know both the IP address of the userâs device and the IP address of the final web server. - Malicious governments and the ISPs they control cannot tell which web servers a user is accessing, although they can tell that the user is using a layered proxy service. - In some parts of the world, using proxies could be construed as an evidence of illegal behavior (âIf you didnât have anything to hide you wouldnât be encrypting your trafficâ) - and users could be punished because governments assume they are doing something that is prohibited. Thus, proxies can be helpful, but they arenât a panacea.
+ I proxy a strati sono progettati per sconfiggere questa violazione di privacy crittografando il traffico dal dispositivo dell'utente e instradandolo attraverso server multipli su internet + prima di inviarlo alla destinazione finale. + Questo significa che nessun ISP individuale, server, o sito web, + può conoscere sia l'indirizzo IP del dispositivo dell'utente che l'indirizzo IP del web server finale. + I governi maliziosi e gli ISP che controllano, non possono conoscere i web server ai quali l'utente sta accedendo, sebbene sappiano che l'utente sta utilizzando un servizio di proxy a strati. + In alcune parti del mondo l'utilizzo di proxy può essere consideraro come evidenza di un comportamento illegale (âSe non hai nulla da nascondere non crittograferesti il tuo trafficoâ) + e gli utenti potrebbero essere perseguiti perchè il loro governo potrebbe assumere che stiano facendo qualcosa di proibito. + Per questo motivo i proxy possono essere utili ma non sono la soluzione di tutti i mali.Quando un utente si connette a un web server, il server può vedere l'indirizzo IP dell'utente. Nonostante non sia una scienza esatta, è possibile convertire l'IP in indirizzi fisici con discreta accuratezza. - Small web servers typically rely on IP addresses to identify the location of the users visiting their site. Proxies are a good solution to mask the userâs location from these servers. + I piccoli web servers solitamente si basano sull'indirizzo IP per identificare la posizione degli utenti che accedono al loro sito. + I Proxy sono una buona soluzione per mascherare la posizione dell'utente a questi server. Le mega corporations proprietarie di social media e agenzie pubblicitarie utilizzano però un intero profilo di informazioni con lo scopo di tracciare gli utenti sui dispositivi e sgli indirizzi IP. Questi profili utilizzano molte tecniche diverse per l'identificazione degli utenti, tra cui JavaScript, cookie, ID traccianti, e impronta digitale dei browser. @@ -60,26 +63,27 @@
Viene tracciato ogni sito visitato, ogni acquisto effettuato, ogni carta di credito utilizzata, ogni indirizzo di spedizione, i metadati GPS di ogni immagine che viene caricata su internet. Viene costruito il profilo per età , sesso, stato civile, indirizzo, appartenenza politica, religione, situazione familiare, animali domestici, e tutto ciò su cui possono mettere le mani. Le corporations acquistano anche i database delle transazioni con carta di credito effettuate nei negozi, per poter tracciare anche le abitudini di acquisto off-line degli utenti nei loro profili. - Because they already have much more accurate address information about a user than an IP address discloses, proxies provides no real privacy protection against mega corporations.
+ Poichè hanno già informazioni molto più accurate sull'utente rispetto a quelle fornite dall'indirizzo IP, i proxy non forniscono alcuna vera protezione della privacy contro le mega corporations.La miglior protezione per la privacy contro le mega corporations è quella di navigare con JavaScript disabilitato, seguita dal bloccare gli annunci pubblicitari, disabilitare i cookie e il DOM storage, e utilizzare un browser di cui è difficile avere l'impronta digitale.
-Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p - have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. - Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
+Nonostante i loro limiti, i proxy possono essere utili in alcune circostanze. + Tor e I2P + hanno app per Android che facilitano l'utilizzo delle loro reti proxy. + Quando si abilita il proxy in Privacy Browser la barra dell'app bar avrà una colorazione dello sfondo azzurra, rispetto a quella grigia di default. + Dal momento che il traffico è instradato attraverso diversi nodi proxy, l'utilizzo di un proxy a strati è spesso molto più lento di una connessione diretta a internet.
When Orbot is operating in proxy mode, browsing the internet using Privacy Browser will be routed through the proxy, but file downloads will not. - This is because Privacy Browser uses Androidâs builtin download manager to download files, which doesnât have a proxy option. - Users who want to download files via Orbot need to enable its VPN mode. There is currently no way to download files through I2P.
+Quando Orbot sta funzionando in modalità proxy, la navigazione su internet con Privacy Browser è instradata attraverso il proxy, ma il download di file no. + Questo perchè Privacy Browser utilizza il download manager nativo di Android per lo scaricamento dei file, e questo non ha l'opzione proxy. + Gli utenti che vogliono scaricare i file via Orbot devono quindi abilitare la sua modalità VPN. Attualmente non c'è ancora la possibilità di scaricare file con I2P.
diff --git a/app/src/main/assets/it/guide_proxies_light.html b/app/src/main/assets/it/guide_proxies_light.html index 7a7598ac..3719b015 100644 --- a/app/src/main/assets/it/guide_proxies_light.html +++ b/app/src/main/assets/it/guide_proxies_light.html @@ -26,31 +26,34 @@ -Esistono due categorie generali di cattivi soggetti che vogliono violare la privacy del web: governi maliziosi con accesso agli ISP (Internet Service Providers) e mega corporations che gestiscono social network e agenzie pubblicitarie. - Proxies like TOR (The Onion Router) and I2P (the Invisible Internet Project) are useful in protecting privacy from malicious governments (which spy on traffic in transit) - but not from mega corporations (which embed malicious code on web servers).
+ Proxy come TOR (The Onion Router) e I2P (Invisible Internet Project) sono utili per la protezione della privacy da governi maliziosi (che spiano il traffico in transito) + ma non dalle mega corporations (che inseriscono codice malizioso sui web server).I governi malizionsi spesso spiano i loro cittadini per punire il dissenso o le attività di difesa dei diritti umani. Solitamente, o gestiscono loro stessi gli ISP locali oppure li obbligano a rivelare informazioni mostrando tutti gli indirizzi IP visitati da ciascun utente. - Layered proxies are designed to defeat this infringement of privacy by encrypting the traffic from a userâs device and routing it through multiple servers on the internet - before sending it on to the final destination. - This means that no individual ISP, server, or website, can know both the IP address of the userâs device and the IP address of the final web server. - Malicious governments and the ISPs they control cannot tell which web servers a user is accessing, although they can tell that the user is using a layered proxy service. - In some parts of the world, using proxies could be construed as an evidence of illegal behavior (âIf you didnât have anything to hide you wouldnât be encrypting your trafficâ) - and users could be punished because governments assume they are doing something that is prohibited. Thus, proxies can be helpful, but they arenât a panacea.
+ I proxy a strati sono progettati per sconfiggere questa violazione di privacy crittografando il traffico dal dispositivo dell'utente e instradandolo attraverso server multipli su internet + prima di inviarlo alla destinazione finale. + Questo significa che nessun ISP individuale, server, o sito web, + può conoscere sia l'indirizzo IP del dispositivo dell'utente che l'indirizzo IP del web server finale. + I governi maliziosi e gli ISP che controllano, non possono conoscere i web server ai quali l'utente sta accedendo, sebbene sappiano che l'utente sta utilizzando un servizio di proxy a strati. + In alcune parti del mondo l'utilizzo di proxy può essere consideraro come evidenza di un comportamento illegale (âSe non hai nulla da nascondere non crittograferesti il tuo trafficoâ) + e gli utenti potrebbero essere perseguiti perchè il loro governo potrebbe assumere che stiano facendo qualcosa di proibito. + Per questo motivo i proxy possono essere utili ma non sono la soluzione di tutti i mali.Quando un utente si connette a un web server, il server può vedere l'indirizzo IP dell'utente. Nonostante non sia una scienza esatta, è possibile convertire l'IP in indirizzi fisici con discreta accuratezza. - Small web servers typically rely on IP addresses to identify the location of the users visiting their site. Proxies are a good solution to mask the userâs location from these servers. + I piccoli web servers solitamente si basano sull'indirizzo IP per identificare la posizione degli utenti che accedono al loro sito. + I Proxy sono una buona soluzione per mascherare la posizione dell'utente a questi server. Le mega corporations proprietarie di social media e agenzie pubblicitarie utilizzano però un intero profilo di informazioni con lo scopo di tracciare gli utenti sui dispositivi e sgli indirizzi IP. Questi profili utilizzano molte tecniche diverse per l'identificazione degli utenti, tra cui JavaScript, cookie, ID traccianti, e impronta digitale dei browser. @@ -60,26 +63,27 @@
Viene tracciato ogni sito visitato, ogni acquisto effettuato, ogni carta di credito utilizzata, ogni indirizzo di spedizione, i metadati GPS di ogni immagine che viene caricata su internet. Viene costruito il profilo per età , sesso, stato civile, indirizzo, appartenenza politica, religione, situazione familiare, animali domestici, e tutto ciò su cui possono mettere le mani. Le corporations acquistano anche i database delle transazioni con carta di credito effettuate nei negozi, per poter tracciare anche le abitudini di acquisto off-line degli utenti nei loro profili. - Because they already have much more accurate address information about a user than an IP address discloses, proxies provides no real privacy protection against mega corporations.
+ Poichè hanno già informazioni molto più accurate sull'utente rispetto a quelle fornite dall'indirizzo IP, i proxy non forniscono alcuna vera protezione della privacy contro le mega corporations.La miglior protezione per la privacy contro le mega corporations è quella di navigare con JavaScript disabilitato, seguita dal bloccare gli annunci pubblicitari, disabilitare i cookie e il DOM storage, e utilizzare un browser di cui è difficile avere l'impronta digitale.
-Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p - have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. - Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
+Nonostante i loro limiti, i proxy possono essere utili in alcune circostanze. + Tor e I2P + hanno app per Android che facilitano l'utilizzo delle loro reti proxy. + Quando si abilita il proxy in Privacy Browser la barra dell'app bar avrà una colorazione dello sfondo azzurra, rispetto a quella grigia di default. + Dal momento che il traffico è instradato attraverso diversi nodi proxy, l'utilizzo di un proxy a strati è spesso molto più lento di una connessione diretta a internet.
When Orbot is operating in proxy mode, browsing the internet using Privacy Browser will be routed through the proxy, but file downloads will not. - This is because Privacy Browser uses Androidâs builtin download manager to download files, which doesnât have a proxy option. - Users who want to download files via Orbot need to enable its VPN mode. There is currently no way to download files through I2P.
+Quando Orbot sta funzionando in modalità proxy, la navigazione su internet con Privacy Browser è instradata attraverso il proxy, ma il download di file no. + Questo perchè Privacy Browser utilizza il download manager nativo di Android per lo scaricamento dei file, e questo non ha l'opzione proxy. + Gli utenti che vogliono scaricare i file via Orbot devono quindi abilitare la sua modalità VPN. Attualmente non c'è ancora la possibilità di scaricare file con I2P.
diff --git a/app/src/main/assets/ru/guide_proxies_dark.html b/app/src/main/assets/ru/guide_proxies_dark.html index 94067ab7..9141f5f3 100644 --- a/app/src/main/assets/ru/guide_proxies_dark.html +++ b/app/src/main/assets/ru/guide_proxies_dark.html @@ -69,7 +69,7 @@Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p + Tor and I2P have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
diff --git a/app/src/main/assets/ru/guide_proxies_light.html b/app/src/main/assets/ru/guide_proxies_light.html index 0e3946f4..15f97aa6 100644 --- a/app/src/main/assets/ru/guide_proxies_light.html +++ b/app/src/main/assets/ru/guide_proxies_light.html @@ -69,7 +69,7 @@Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p + Tor and I2P have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
diff --git a/app/src/main/assets/tr/guide_proxies_dark.html b/app/src/main/assets/tr/guide_proxies_dark.html index 049ed008..49d5b898 100644 --- a/app/src/main/assets/tr/guide_proxies_dark.html +++ b/app/src/main/assets/tr/guide_proxies_dark.html @@ -68,7 +68,7 @@Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p + Tor and I2P have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
diff --git a/app/src/main/assets/tr/guide_proxies_light.html b/app/src/main/assets/tr/guide_proxies_light.html index e4915281..d7205739 100644 --- a/app/src/main/assets/tr/guide_proxies_light.html +++ b/app/src/main/assets/tr/guide_proxies_light.html @@ -68,7 +68,7 @@Despite their limitations, proxies can be useful in some circumstances. - Tor and I2p + Tor and I2P have Android apps that make it easy to use their proxy networks. When proxying is turned on in Privacy Browser, the app bar will have a light blue background instead of the default light grey. Because traffic is being routed through several proxy nodes, using a layered proxy is often much slower than connecting directly to the internet.
diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.java index 1c328c4d..ca4703af 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.java @@ -117,7 +117,7 @@ public class ImportExportActivity extends AppCompatActivity implements StoragePe // Set the content view. setContentView(R.layout.import_export_coordinatorlayout); - // Use the `SupportActionBar` from `android.support.v7.app.ActionBar` until the minimum API is >= 21. + // Set the support action bar. Toolbar toolbar = findViewById(R.id.import_export_toolbar); setSupportActionBar(toolbar); @@ -130,7 +130,7 @@ public class ImportExportActivity extends AppCompatActivity implements StoragePe // Display the home arrow on the support action bar. actionBar.setDisplayHomeAsUpEnabled(true); - // Find out if we are running KitKat + // Find out if the system is running KitKat boolean runningKitKat = (Build.VERSION.SDK_INT == 19); // Find out if OpenKeychain is installed. @@ -519,7 +519,7 @@ public class ImportExportActivity extends AppCompatActivity implements StoragePe // Check if the user has previously denied the storage permission. if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. // Instantiate the storage permission alert dialog. - DialogFragment storagePermissionDialogFragment = new StoragePermissionDialog(); + DialogFragment storagePermissionDialogFragment = StoragePermissionDialog.displayDialog(0); // Show the storage permission alert dialog. The permission will be requested when the dialog is closed. storagePermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.storage_permission)); @@ -532,7 +532,7 @@ public class ImportExportActivity extends AppCompatActivity implements StoragePe } @Override - public void onCloseStoragePermissionDialog() { + public void onCloseStoragePermissionDialog(int type) { // Request the write external storage permission. The import/export will be run when it finishes. ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java index 754874d8..c38181a6 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.java @@ -235,7 +235,7 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo // Check if the user has previously denied the storage permission. if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. // Instantiate the storage permission alert dialog. - DialogFragment storagePermissionDialogFragment = new StoragePermissionDialog(); + DialogFragment storagePermissionDialogFragment = StoragePermissionDialog.displayDialog(0); // Show the storage permission alert dialog. The permission will be requested when the dialog is closed. storagePermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.storage_permission)); @@ -249,7 +249,7 @@ public class LogcatActivity extends AppCompatActivity implements SaveLogcatDialo } @Override - public void onCloseStoragePermissionDialog() { + public void onCloseStoragePermissionDialog(int type) { // Request the write external storage permission. The logcat will be saved when it finishes. ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 568a316f..efa66ac9 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -133,7 +133,7 @@ import com.stoutner.privacybrowser.dialogs.FontSizeDialog; import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog; import com.stoutner.privacybrowser.dialogs.ProxyNotInstalledDialog; import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog; -import com.stoutner.privacybrowser.dialogs.SaveWebpageImageDialog; +import com.stoutner.privacybrowser.dialogs.SaveWebpageDialog; import com.stoutner.privacybrowser.dialogs.SslCertificateErrorDialog; import com.stoutner.privacybrowser.dialogs.StoragePermissionDialog; import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog; @@ -170,8 +170,9 @@ import java.util.Set; // AppCompatActivity from android.support.v7.app.AppCompatActivity must be used to have access to the SupportActionBar until the minimum API is >= 21. public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener, DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener, - EditBookmarkFolderDialog.EditBookmarkFolderListener, FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener, PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageImageDialog.SaveWebpageImageListener, - StoragePermissionDialog.StoragePermissionDialogListener, UrlHistoryDialog.NavigateHistoryListener, WebViewTabFragment.NewTabListener { + EditBookmarkFolderDialog.EditBookmarkFolderListener, FontSizeDialog.UpdateFontSizeListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener, + PopulateBlocklists.PopulateBlocklistsListener, SaveWebpageDialog.SaveWebpageListener, StoragePermissionDialog.StoragePermissionDialogListener, UrlHistoryDialog.NavigateHistoryListener, + WebViewTabFragment.NewTabListener { // `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxy()`. public static String orbotStatus = "unknown"; @@ -200,7 +201,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Start activity for result request codes. private final int FILE_UPLOAD_REQUEST_CODE = 0; - public final static int BROWSE_SAVE_WEBPAGE_IMAGE_REQUEST_CODE = 1; + public final static int BROWSE_SAVE_WEBPAGE_REQUEST_CODE = 1; // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, @@ -311,13 +312,14 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `downloadImageUrl` is used in `onCreateContextMenu()` and `onRequestPermissionResult()`. private String downloadImageUrl; - // The save website image file path string is used in `onSaveWebpageImage()` and `onRequestPermissionResult()` - private String saveWebsiteImageFilePath; + // The save webpage file path string is used in `onSaveWebpageImage()` and `onRequestPermissionResult()` + private String saveWebpageFilePath; // The permission result request codes are used in `onCreateContextMenu()`, `onCloseDownloadLocationPermissionDialog()`, `onRequestPermissionResult()`, `onSaveWebpageImage()`, // `onCloseStoragePermissionDialog()`, and `initializeWebView()`. - private final int DOWNLOAD_FILE_REQUEST_CODE = 1; - private final int DOWNLOAD_IMAGE_REQUEST_CODE = 2; + private final int DOWNLOAD_FILE_REQUEST_CODE = 0; + private final int DOWNLOAD_IMAGE_REQUEST_CODE = 1; + private final int SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE = 2; private final int SAVE_WEBPAGE_IMAGE_REQUEST_CODE = 3; @Override @@ -1698,12 +1700,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Consume the event. return true; + case R.id.save_as_archive: + // Instantiate the save webpage archive dialog. + DialogFragment saveWebpageArchiveDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.ARCHIVE); + + // Show the save webpage archive dialog. + saveWebpageArchiveDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_webpage)); + + // Consume the event. + return true; + case R.id.save_as_image: // Instantiate the save webpage image dialog. - DialogFragment saveWebpageImageDialogFragment = new SaveWebpageImageDialog(); + DialogFragment saveWebpageImageDialogFragment = SaveWebpageDialog.saveWebpage(SaveWebpageDialog.IMAGE); // Show the save webpage image dialog. - saveWebpageImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_as_image)); + saveWebpageImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.save_webpage)); // Consume the event. return true; @@ -2680,18 +2692,32 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook downloadImageUrl = ""; break; + case SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE: + // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty. + if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted. + // Save the webpage archive. + currentWebView.saveWebArchive(saveWebpageFilePath); + } else { + // Display an error snackbar. + Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show(); + } + + // Reset the save webpage file path. + saveWebpageFilePath = ""; + break; + case SAVE_WEBPAGE_IMAGE_REQUEST_CODE: - // Check to see if the storage permission was granted. If the dialog was canceled the grant result will be empty. + // Check to see if the storage permission was granted. If the dialog was canceled the grant results will be empty. if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) { // The storage permission was granted. // Save the webpage image. - new SaveWebpageImage(this, currentWebView).execute(saveWebsiteImageFilePath); + new SaveWebpageImage(this, currentWebView).execute(saveWebpageFilePath); } else { // The storage permission was not granted. // Display an error snackbar. Snackbar.make(currentWebView, getString(R.string.cannot_use_location), Snackbar.LENGTH_LONG).show(); } - // Reset the save website image file path. - saveWebsiteImageFilePath = ""; + // Reset the save webpage file path. + saveWebpageFilePath = ""; break; } } @@ -2954,22 +2980,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } break; - case BROWSE_SAVE_WEBPAGE_IMAGE_REQUEST_CODE: + case BROWSE_SAVE_WEBPAGE_REQUEST_CODE: // Don't do anything if the user pressed back from the file picker. if (resultCode == Activity.RESULT_OK) { // Get a handle for the save dialog fragment. - DialogFragment saveWebpageImageDialogFragment= (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.save_as_image)); + DialogFragment saveWebpageDialogFragment= (DialogFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.save_webpage)); // Only update the file name if the dialog still exists. - if (saveWebpageImageDialogFragment != null) { - // Get a handle for the save webpage image dialog. - Dialog saveWebpageImageDialog = saveWebpageImageDialogFragment.getDialog(); + if (saveWebpageDialogFragment != null) { + // Get a handle for the save webpage dialog. + Dialog saveWebpageDialog = saveWebpageDialogFragment.getDialog(); // Remove the incorrect lint warning below that the dialog might be null. - assert saveWebpageImageDialog != null; + assert saveWebpageDialog != null; // Get a handle for the file name edit text. - EditText fileNameEditText = saveWebpageImageDialog.findViewById(R.id.file_name_edittext); + EditText fileNameEditText = saveWebpageDialog.findViewById(R.id.file_name_edittext); // Instantiate the file name helper. FileNameHelper fileNameHelper = new FileNameHelper(); @@ -3135,7 +3161,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onSaveWebpageImage(DialogFragment dialogFragment) { + public void onSaveWebpage(int saveType, DialogFragment dialogFragment) { // Get the dialog. Dialog dialog = dialogFragment.getDialog(); @@ -3146,12 +3172,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook EditText fileNameEditText = dialog.findViewById(R.id.file_name_edittext); // Get the file path string. - saveWebsiteImageFilePath = fileNameEditText.getText().toString(); + saveWebpageFilePath = fileNameEditText.getText().toString(); // Check to see if the storage permission is needed. if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted. - // Save the webpage image. - new SaveWebpageImage(this, currentWebView).execute(saveWebsiteImageFilePath); + //Save the webpage according to the save type. + switch (saveType) { + case SaveWebpageDialog.ARCHIVE: + // Save the webpage archive. + currentWebView.saveWebArchive(saveWebpageFilePath); + break; + + case SaveWebpageDialog.IMAGE: + // Save the webpage image. + new SaveWebpageImage(this, currentWebView).execute(saveWebpageFilePath); + break; + } } else { // The storage permission has not been granted. // Get the external private directory `File`. File externalPrivateDirectoryFile = getExternalFilesDir(null); @@ -3163,29 +3199,57 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook String externalPrivateDirectory = externalPrivateDirectoryFile.toString(); // Check to see if the file path is in the external private directory. - if (saveWebsiteImageFilePath.startsWith(externalPrivateDirectory)) { // The file path is in the external private directory. - // Save the webpage image. - new SaveWebpageImage(this, currentWebView).execute(saveWebsiteImageFilePath); + if (saveWebpageFilePath.startsWith(externalPrivateDirectory)) { // The file path is in the external private directory. + //Save the webpage according to the save type. + switch (saveType) { + case SaveWebpageDialog.ARCHIVE: + // Save the webpage archive. + currentWebView.saveWebArchive(saveWebpageFilePath); + break; + + case SaveWebpageDialog.IMAGE: + // Save the webpage image. + new SaveWebpageImage(this, currentWebView).execute(saveWebpageFilePath); + break; + } } else { // The file path is in a public directory. // Check if the user has previously denied the storage permission. if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first. // Instantiate the storage permission alert dialog. - DialogFragment storagePermissionDialogFragment = new StoragePermissionDialog(); + DialogFragment storagePermissionDialogFragment = StoragePermissionDialog.displayDialog(saveType); // Show the storage permission alert dialog. The permission will be requested when the dialog is closed. storagePermissionDialogFragment.show(getSupportFragmentManager(), getString(R.string.storage_permission)); } else { // Show the permission request directly. - // Request the write external storage permission. The webpage image will be saved when it finishes. - ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_IMAGE_REQUEST_CODE); + switch (saveType) { + case SaveWebpageDialog.ARCHIVE: + // Request the write external storage permission. The webpage archive will be saved when it finishes. + ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE); + break; + + case SaveWebpageDialog.IMAGE: + // Request the write external storage permission. The webpage image will be saved when it finishes. + ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_IMAGE_REQUEST_CODE); + break; + } } } } } @Override - public void onCloseStoragePermissionDialog() { - // Request the write external storage permission. The webpage image will be saved when it finishes. - ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_IMAGE_REQUEST_CODE); + public void onCloseStoragePermissionDialog(int saveType) { + switch (saveType) { + case SaveWebpageDialog.ARCHIVE: + // Request the write external storage permission. The webpage archive will be saved when it finishes. + ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_ARCHIVE_REQUEST_CODE); + break; + + case SaveWebpageDialog.IMAGE: + // Request the write external storage permission. The webpage image will be saved when it finishes. + ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, SAVE_WEBPAGE_IMAGE_REQUEST_CODE); + break; + } } private void applyAppSettings() { diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageImageDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageDialog.java similarity index 68% rename from app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageImageDialog.java rename to app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageDialog.java index a9277d9c..1c24e0be 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageImageDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SaveWebpageDialog.java @@ -49,13 +49,17 @@ import androidx.preference.PreferenceManager; import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; -public class SaveWebpageImageDialog extends DialogFragment { - // Define the save webpage image listener. - private SaveWebpageImageListener saveWebpageImageListener; +public class SaveWebpageDialog extends DialogFragment { + // Define the save type constants. + public static final int ARCHIVE = 0; + public static final int IMAGE = 1; + + // Define the save webpage listener. + private SaveWebpageListener saveWebpageListener; // The public interface is used to send information back to the parent activity. - public interface SaveWebpageImageListener { - void onSaveWebpageImage(DialogFragment dialogFragment); + public interface SaveWebpageListener { + void onSaveWebpage(int saveType, DialogFragment dialogFragment); } @Override @@ -63,8 +67,25 @@ public class SaveWebpageImageDialog extends DialogFragment { // Run the default commands. super.onAttach(context); - // Get a handle for the save webpage image listener from the launching context. - saveWebpageImageListener = (SaveWebpageImageListener) context; + // Get a handle for the save webpage listener from the launching context. + saveWebpageListener = (SaveWebpageListener) context; + } + + public static SaveWebpageDialog saveWebpage(int saveType) { + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); + + // Store the save type in the bundle. + argumentsBundle.putInt("save_type", saveType); + + // Create a new instance of the save webpage dialog. + SaveWebpageDialog saveWebpageDialog = new SaveWebpageDialog(); + + // Add the arguments bundle to the new dialog. + saveWebpageDialog.setArguments(argumentsBundle); + + // Return the new dialog. + return saveWebpageDialog; } // `@SuppressLing("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog. @@ -72,6 +93,15 @@ public class SaveWebpageImageDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { + // Get a handle for the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning that the arguments might be null. + assert arguments != null; + + // Get the save type. + int saveType = arguments.getInt("save_type"); + // Get a handle for the activity and the context. Activity activity = getActivity(); Context context = getContext(); @@ -92,15 +122,45 @@ public class SaveWebpageImageDialog extends DialogFragment { // Set the style and icon according to the theme. if (darkTheme) { + // Set the style. dialogBuilder = new AlertDialog.Builder(activity, R.style.PrivacyBrowserAlertDialogDark); - dialogBuilder.setIcon(R.drawable.images_enabled_dark); + + // Set the icon according to the save type. + switch (saveType) { + case ARCHIVE: + dialogBuilder.setIcon(R.drawable.dom_storage_cleared_dark); + break; + + case IMAGE: + dialogBuilder.setIcon(R.drawable.images_enabled_dark); + break; + } } else { + // Set the style. dialogBuilder = new AlertDialog.Builder(activity, R.style.PrivacyBrowserAlertDialogLight); - dialogBuilder.setIcon(R.drawable.images_enabled_light); + + // Set the icon according to the save type. + switch (saveType) { + case ARCHIVE: + dialogBuilder.setIcon(R.drawable.dom_storage_cleared_light); + break; + + case IMAGE: + dialogBuilder.setIcon(R.drawable.images_enabled_light); + break; + } } - // Set the title. - dialogBuilder.setTitle(R.string.save_image); + // Set the title according to the type. + switch (saveType) { + case ARCHIVE: + dialogBuilder.setTitle(R.string.save_archive); + break; + + case IMAGE: + dialogBuilder.setTitle(R.string.save_image); + break; + } // Set the view. The parent view is null because it will be assigned by the alert dialog. dialogBuilder.setView(activity.getLayoutInflater().inflate(R.layout.save_dialog, null)); @@ -111,7 +171,7 @@ public class SaveWebpageImageDialog extends DialogFragment { // Set the save button listener. dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> { // Return the dialog fragment to the parent activity. - saveWebpageImageListener.onSaveWebpageImage(this); + saveWebpageListener.onSaveWebpage(saveType, this); }); // Create an alert dialog from the builder. @@ -134,16 +194,30 @@ public class SaveWebpageImageDialog extends DialogFragment { TextView storagePermissionTextView = alertDialog.findViewById(R.id.storage_permission_textview); Button saveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + // Create a default file name string. + String defaultFileName = ""; + + // Set the default file name according to the type. + switch (saveType) { + case ARCHIVE: + defaultFileName = getString(R.string.webpage_mht); + break; + + case IMAGE: + defaultFileName = getString(R.string.webpage_png); + break; + } + // Create a string for the default file path. String defaultFilePath; // Set the default file path according to the storage permission state. if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted. // Set the default file path to use the external public directory. - defaultFilePath = Environment.getExternalStorageDirectory() + "/" + getString(R.string.webpage_png); + defaultFilePath = Environment.getExternalStorageDirectory() + "/" + defaultFileName; } else { // The storage permission has not been granted. // Set the default file path to use the external private directory. - defaultFilePath = context.getExternalFilesDir(null) + "/" + getString(R.string.webpage_png); + defaultFilePath = context.getExternalFilesDir(null) + "/" + defaultFileName; } // Display the default file path. @@ -176,8 +250,16 @@ public class SaveWebpageImageDialog extends DialogFragment { // Set the intent MIME type to include all files so that everything is visible. browseIntent.setType("*/*"); - // Set the initial file name. - browseIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.webpage_png)); + // Set the initial file name according to the type. + switch (saveType) { + case ARCHIVE: + browseIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.webpage_mht)); + break; + + case IMAGE: + browseIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.webpage_png)); + break; + } // Set the initial directory if the minimum API >= 26. if (Build.VERSION.SDK_INT >= 26) { @@ -188,7 +270,7 @@ public class SaveWebpageImageDialog extends DialogFragment { browseIntent.addCategory(Intent.CATEGORY_OPENABLE); // Start the file picker. This must be started under `activity` so that the request code is returned correctly. - activity.startActivityForResult(browseIntent, MainWebViewActivity.BROWSE_SAVE_WEBPAGE_IMAGE_REQUEST_CODE); + activity.startActivityForResult(browseIntent, MainWebViewActivity.BROWSE_SAVE_WEBPAGE_REQUEST_CODE); }); // Hide the storage permission text view on API < 23 as permissions on older devices are automatically granted. diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/StoragePermissionDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/StoragePermissionDialog.java index 198eb509..1ee03b8f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/StoragePermissionDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/StoragePermissionDialog.java @@ -39,7 +39,7 @@ public class StoragePermissionDialog extends DialogFragment { // The public interface is used to send information back to the parent activity. public interface StoragePermissionDialogListener { - void onCloseStoragePermissionDialog(); + void onCloseStoragePermissionDialog(int saveType); } @Override @@ -51,11 +51,34 @@ public class StoragePermissionDialog extends DialogFragment { storagePermissionDialogListener = (StoragePermissionDialogListener) context; } + public static StoragePermissionDialog displayDialog(int saveType) { + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); + + // Store the save type in the bundle. + argumentsBundle.putInt("save_type", saveType); + + // Create a new instance of the storage permission dialog. + StoragePermissionDialog storagePermissionDialog = new StoragePermissionDialog(); + + // Add the arguments bundle to the new dialog. + storagePermissionDialog.setArguments(argumentsBundle); + + // Return the new dialog. + return storagePermissionDialog; + } + @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - // Use a builder to create the alert dialog. - AlertDialog.Builder dialogBuilder; + // Get a handle for the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning that the arguments might be null. + assert arguments != null; + + // Get the save type. + int saveType = arguments.getInt("save_type"); // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); @@ -64,6 +87,9 @@ public class StoragePermissionDialog extends DialogFragment { boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false); boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false); + // Use a builder to create the alert dialog. + AlertDialog.Builder dialogBuilder; + // Set the style and the icon according to the theme. if (darkTheme) { dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark); @@ -79,10 +105,10 @@ public class StoragePermissionDialog extends DialogFragment { // Set the text. dialogBuilder.setMessage(R.string.storage_permission_message); - // Set an `onClick` listener on the negative button. + // Set an listener on the OK button. dialogBuilder.setNegativeButton(R.string.ok, (DialogInterface dialog, int which) -> { // Inform the parent activity that the dialog was closed. - storagePermissionDialogListener.onCloseStoragePermissionDialog(); + storagePermissionDialogListener.onCloseStoragePermissionDialog(saveType); }); // Create an alert dialog from the builder. @@ -97,7 +123,7 @@ public class StoragePermissionDialog extends DialogFragment { alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); } - // `onCreateDialog()` requires the return of an `AlertDialog`. + // Return the alert dialog. return alertDialog; } } \ No newline at end of file diff --git a/app/src/main/res/drawable/import_export_dark.xml b/app/src/main/res/drawable/import_export_dark.xml index 21cdea86..1847f4fc 100644 --- a/app/src/main/res/drawable/import_export_dark.xml +++ b/app/src/main/res/drawable/import_export_dark.xml @@ -1,4 +1,4 @@ - +