<w>checkedtextview</w>
<w>chromebooks</w>
<w>chromeversion</w>
+ <w>ciphertext</w>
<w>cname</w>
<w>commitdiff</w>
<w>coordinatorlayout</w>
<w>mozilla</w>
<w>navigationview</w>
<w>nightmode</w>
+ <w>nist</w>
<w>nojs</w>
<w>oname</w>
+ <w>openpgp</w>
<w>orbot</w>
<w>panopticlick</w>
<w>parameterized</w>
<w>tablayout</w>
<w>techrepublic</w>
<w>textarea</w>
+ <w>textinputlayout</w>
<w>textview</w>
<w>theverge</w>
<w>torproject</w>
<img class="center" src="images/bookmarks.png">
- <p>Tapping the top floating action button loads the bookmarks activity, which has advanced options like moving and deleting bookmarks.
- From the bookmarks activity, there is an option to load the bookmarks database view.
- This shows the bookmarks as they exist in the SQLite database, which can be useful for troubleshooting problems with importing and exporting bookmarks.</p>
+ <p>Toccando il pulsante flottante più in alto viene caricata la scheda dei segnalibri, nella quale sono disponibili opzioni avanzate come lo spostamento o l'eliminazione dei segnalibri stessi.
+ Nella scheda dei segnalibri è anche disponibile un'opzione per caricare la vista del database.
+ In questo modo è possibile visualizzare i segnalibri come sono salvati nel database SQLite, molto utile nel caso di problemi durante l'importazione o esportazione degli stessi.</p>
</body>
</html>
\ No newline at end of file
<img class="center" src="images/bookmarks.png">
- <p>Tapping the top floating action button loads the bookmarks activity, which has advanced options like moving and deleting bookmarks.
- From the bookmarks activity, there is an option to load the bookmarks database view.
- This shows the bookmarks as they exist in the SQLite database, which can be useful for troubleshooting problems with importing and exporting bookmarks.</p>
+ <p>Toccando il pulsante flottante più in alto viene caricata la scheda dei segnalibri, nella quale sono disponibili opzioni avanzate come lo spostamento o l'eliminazione dei segnalibri stessi.
+ Nella scheda dei segnalibri è anche disponibile un'opzione per caricare la vista del database.
+ In questo modo è possibile visualizzare i segnalibri come sono salvati nel database SQLite, molto utile nel caso di problemi durante l'importazione o esportazione degli stessi.</p>
</body>
</html>
\ No newline at end of file
<img class="inline" src="../shared_images/javascript_enabled.png"> (JavaScript abilitato).
Se si osservano le varie informazioni che <a href="http://webkay.robinlinus.com">webkay</a> può raccogliere con JavaScript abilitato o disabilitato si possono scoprire cose molto interessanti.</p>
- <p>Browsing the internet with JavaScript disabled, and only enabling it if needed, goes a long way toward protecting privacy.
- In addition, JavaScript is used to load much of the annoying advertisements and extra cruft that comes along with most modern websites.
- With it disabled, websites will load faster, consume less network traffic, and use less CPU power, which leads to longer battery life.</p>
+ <p>Navigare su internet con JavaScript disabilitato, abilitandolo solo quando necessario, è quindi un passo molto importante per la protezione della propria privacy.
+ Inoltre JavaScript è utilizzato anche per caricare la maggior parte degli annunci pubblicitari e altra robaccia aggiuntiva presente nei moderni siti web.
+ Se Javascript viene disabilitato, i siti web saranno caricati più velocemente, riducendo così il traffico sulla rete, e l'utilizzo della CPU sarà ridotto,
+ risultando così in una maggiore durata della batteria.</p>
</body>
</html>
\ No newline at end of file
<img class="inline" src="../shared_images/javascript_enabled.png"> (JavaScript abilitato).
Se si osservano le varie informazioni che <a href="http://webkay.robinlinus.com">webkay</a> può raccogliere con JavaScript abilitato o disabilitato si possono scoprire cose molto interessanti.</p>
- <p>Browsing the internet with JavaScript disabled, and only enabling it if needed, goes a long way toward protecting privacy.
- In addition, JavaScript is used to load much of the annoying advertisements and extra cruft that comes along with most modern websites.
- With it disabled, websites will load faster, consume less network traffic, and use less CPU power, which leads to longer battery life.</p>
+ <p>Navigare su internet con JavaScript disabilitato, abilitandolo solo quando necessario, è quindi un passo molto importante per la protezione della propria privacy.
+ Inoltre JavaScript è utilizzato anche per caricare la maggior parte degli annunci pubblicitari e altra robaccia aggiuntiva presente nei moderni siti web.
+ Se Javascript viene disabilitato, i siti web saranno caricati più velocemente, riducendo così il traffico sulla rete, e l'utilizzo della CPU sarà ridotto,
+ risultando così in una maggiore durata della batteria.</p>
+
</body>
</html>
\ No newline at end of file
<p>I cookies proprietari sono definiti dal sito web nella barra della URL all'inizio della pagina.</p>
- <p>From the early days of the internet, it became obvious that it would be advantageous for websites to be able to store information on a computer for future access.
- For example, a website that displays weather information could ask the user for a zip code, and then store it in a cookie.
- The next time the user visited the website, weather information would automatically load for that zip code, without the user having to enter it again.</p>
+ <p>Fin dagli albori di internet divenne ovvio che sarebbe stato molto utile per i siti web essere in grado di salvare informazioni sui computer per eventuali accessi successivi.
+ Ad esempio, un sito web che fornisca informazioni meteo potrebbe chiedere all'utente la sua posizione geografica e salvarla in un cookie.
+ Nel caso di un accesso successivo al sito web da parte dell'utente, le informazioni meteo sarebbero quindi caricate in automatico per quella posizione geografica,
+ senza che si renda necessario per l'utente indicarla nuovamente.</p>
- <p>Like everything else on the web, clever people figured out all types of ways to abuse cookies to do things that users would not approve of if they knew they were happening.
- For example, a website can set a cookie with a unique serial number on a device.
- Then, every time a user visits the website on that device, it can be linked to a unique profile the server maintains for that serial number,
- even if the device connects from different IP addresses.</p>
+ <p>Come per quasi ogni cosa sul web, persone intelligenti hanno ideato moltissimi modi per abusare dei cookies e usarli per finalità che gli utenti non approverebbero,
+ se solo sapessero cosa sta succedendo. Ad esempio, un sito web può salvare su un dispositivo un cookie con un numero seriale univoco.
+ In questo modo, ogni volta che l'utente visiterà il sito da quel dispositivo, sarà collegato ad un profilo unico mantenuto sul server per quel particolare numero seriale,
+ anche se il dispositivo si connette con indirizzo IP diverso.</p>
- <p>Almost all websites with logins require first-party cookies to be enabled for a user to log in.
- That is how they make sure it is still you as you move from page to page on the site, and is, in my opinion, one of the few legitimate uses for cookies.</p>
+ <p>Quasi tutti i che richiedono login hanno bisogno che i cookies proprietari siano abilitati per permettere ad un utente di accedere.
+ Questo è il modo in cui essi sono sicuri che l'utente sia sempre lui nella navigazione da una pagina all'altra del sito, ed è, a nostro parere, uno dei pochi utilizzi legittimi dei cookies.</p>
<p>Se sono stati abilitati i cookies proprietari ma è stato disabilitato JavaScript,
l'icona della privacy sarà gialla <img class="inline" src="../shared_images/warning.png"> con lo scopo di avvertire l'utente.</p>
Nel corso del tempo le aziende come Facebook (che gestisce anche una rete di annunci) hanno costruito un numero enorme di profili dettagliati di persone che
<a href="http://www.theverge.com/2016/5/27/11795248/facebook-ad-network-non-users-cookies-plug-ins">non hanno nemmeno mai creato un account sul loro sito</a>.</p>
- <p>There is no good reason to ever enable third-party cookies. On devices with Android KitKat or older (version <= 4.4.4 or API <= 20), WebView does not
- <a href="https://developer.android.com/reference/android/webkit/CookieManager.html#setAcceptThirdPartyCookies(android.webkit.WebView, boolean)">differentiate
- between first-party and third-party cookies</a>. Thus, enabling first-party cookies will also enable third-party cookies.</p>
+ <p>Non esiste nessuna buona ragione di abilitare i cookie di terze parti. Su dispositivi con Android KitKat o precedente (versione <= 4.4.4 o API <= 20), WebView non
+ <a href="https://developer.android.com/reference/android/webkit/CookieManager.html#setAcceptThirdPartyCookies(android.webkit.WebView, boolean)">fa distinzione
+ tra cookie proprietari e cookie di terze parti.</a>. Per questo motivo l'abilitazione dei primi permette anche la creazione dei secondi.</p>
<h3><img class="title" src="../shared_images/web_blue_dark.png"> DOM Storage</h3>
- <p>Document Object Model storage, also known as web storage, is like cookies on steroids.
- Whereas the maximum combined storage size for all cookies from a single URL is 4 kilobytes,
- DOM storage can hold <a href="https://en.wikipedia.org/wiki/Web_storage#Storage_size">megabytes per site</a>.
- Because DOM storage uses JavaScript to read and write data, it cannot be enabled unless JavaScript is also enabled.</p>
+ <p>Il Document Object Model storage, conosciuto anche come web storage, è come l'utilizzo di cookie potenziati.
+ Mentre per tutti i cookie di una singola URL il massimo spazio di memoria occupata è di circa 4 kilobyte,
+ il DOM storage può occupare alcuni <a href="https://en.wikipedia.org/wiki/Web_storage#Storage_size">megabyte per sito</a>.
+ Siccome il DOM storage utilizza JavaScript per leggere e scrivere dati, non può essere abilitato se non viene abilitato anche JavaScript.</p>
<h3><img class="title" src="../shared_images/subtitles_blue_dark.png"> Dati dei moduli</h3>
- <p>Form data contains information typed into web forms, like user names, addresses, phone numbers, etc., and lists them in a drop-down box on future visits.
- Unlike the other forms of local storage, form data is not sent to the web server without specific user interaction.
- Beginning in Android Oreo (8.0), WebView’s form data was replaced by the <a href="https://medium.com/@bherbst/getting-androids-autofill-to-work-for-you-21435debea1">Autofill service</a>.
- As such, controls for form data no longer appear on newer Android devices.</p>
+ <p>I dati dei moduli contengono le informazioni che vengono digitate nei web form, come user name, indirizzi, numeri di telefono, ecc.
+ per poterli elencare in menù a tendina in caso di visite successive.
+ A differenza delle altre modalità di memorizzazione locale delle informazioni, i dati dei moduli non vengono inviati ai web server senza una interazione con l'utente.
+ A partire da Android Oreo (8.0), i dati dei moduli di WebView’s sono stati sostituiti dal
+ <a href="https://medium.com/@bherbst/getting-androids-autofill-to-work-for-you-21435debea1">Servizio di Riempimento Automatico</a>.
+ Per questo motivo i controlli per i dati dei moduli non sono più disponibili nei dispositivi Android più recenti.</p>
</body>
</html>
\ No newline at end of file
<p>I cookies proprietari sono definiti dal sito web nella barra della URL all'inizio della pagina.</p>
- <p>From the early days of the internet, it became obvious that it would be advantageous for websites to be able to store information on a computer for future access.
- For example, a website that displays weather information could ask the user for a zip code, and then store it in a cookie.
- The next time the user visited the website, weather information would automatically load for that zip code, without the user having to enter it again.</p>
+ <p>Fin dagli albori di internet divenne ovvio che sarebbe stato molto utile per i siti web essere in grado di salvare informazioni sui computer per eventuali accessi successivi.
+ Ad esempio, un sito web che fornisca informazioni meteo potrebbe chiedere all'utente la sua posizione geografica e salvarla in un cookie.
+ Nel caso di un accesso successivo al sito web da parte dell'utente, le informazioni meteo sarebbero quindi caricate in automatico per quella posizione geografica,
+ senza che si renda necessario per l'utente indicarla nuovamente.</p>
- <p>Like everything else on the web, clever people figured out all types of ways to abuse cookies to do things that users would not approve of if they knew they were happening.
- For example, a website can set a cookie with a unique serial number on a device.
- Then, every time a user visits the website on that device, it can be linked to a unique profile the server maintains for that serial number,
- even if the device connects from different IP addresses.</p>
+ <p>Come per quasi ogni cosa sul web, persone intelligenti hanno ideato moltissimi modi per abusare dei cookies e usarli per finalità che gli utenti non approverebbero,
+ se solo sapessero cosa sta succedendo. Ad esempio, un sito web può salvare su un dispositivo un cookie con un numero seriale univoco.
+ In questo modo, ogni volta che l'utente visiterà il sito da quel dispositivo, sarà collegato ad un profilo unico mantenuto sul server per quel particolare numero seriale,
+ anche se il dispositivo si connette con indirizzo IP diverso.</p>
- <p>Almost all websites with logins require first-party cookies to be enabled for a user to log in.
- That is how they make sure it is still you as you move from page to page on the site, and is, in my opinion, one of the few legitimate uses for cookies.</p>
+ <p>Quasi tutti i che richiedono login hanno bisogno che i cookies proprietari siano abilitati per permettere ad un utente di accedere.
+ Questo è il modo in cui essi sono sicuri che l'utente sia sempre lui nella navigazione da una pagina all'altra del sito, ed è, a nostro parere, uno dei pochi utilizzi legittimi dei cookies.</p>
<p>Se sono stati abilitati i cookies proprietari ma è stato disabilitato JavaScript,
l'icona della privacy sarà gialla <img class="inline" src="../shared_images/warning.png"> con lo scopo di avvertire l'utente.</p>
Nel corso del tempo le aziende come Facebook (che gestisce anche una rete di annunci) hanno costruito un numero enorme di profili dettagliati di persone che
<a href="http://www.theverge.com/2016/5/27/11795248/facebook-ad-network-non-users-cookies-plug-ins">non hanno nemmeno mai creato un account sul loro sito</a>.</p>
- <p>There is no good reason to ever enable third-party cookies. On devices with Android KitKat or older (version <= 4.4.4 or API <= 20), WebView does not
- <a href="https://developer.android.com/reference/android/webkit/CookieManager.html#setAcceptThirdPartyCookies(android.webkit.WebView, boolean)">differentiate
- between first-party and third-party cookies</a>. Thus, enabling first-party cookies will also enable third-party cookies.</p>
+ <p>Non esiste nessuna buona ragione di abilitare i cookie di terze parti. Su dispositivi con Android KitKat o precedente (versione <= 4.4.4 o API <= 20), WebView non
+ <a href="https://developer.android.com/reference/android/webkit/CookieManager.html#setAcceptThirdPartyCookies(android.webkit.WebView, boolean)">fa distinzione
+ tra cookie proprietari e cookie di terze parti.</a>. Per questo motivo l'abilitazione dei primi permette anche la creazione dei secondi.</p>
<h3><img class="title" src="../shared_images/web_blue_light.png"> DOM Storage</h3>
- <p>Document Object Model storage, also known as web storage, is like cookies on steroids.
- Whereas the maximum combined storage size for all cookies from a single URL is 4 kilobytes,
- DOM storage can hold <a href="https://en.wikipedia.org/wiki/Web_storage#Storage_size">megabytes per site</a>.
- Because DOM storage uses JavaScript to read and write data, it cannot be enabled unless JavaScript is also enabled.</p>
+ <p>Il Document Object Model storage, conosciuto anche come web storage, è come l'utilizzo di cookie potenziati.
+ Mentre per tutti i cookie di una singola URL il massimo spazio di memoria occupata è di circa 4 kilobyte,
+ il DOM storage può occupare alcuni <a href="https://en.wikipedia.org/wiki/Web_storage#Storage_size">megabyte per sito</a>.
+ Siccome il DOM storage utilizza JavaScript per leggere e scrivere dati, non può essere abilitato se non viene abilitato anche JavaScript.</p>
<h3><img class="title" src="../shared_images/subtitles_blue_light.png"> Dati dei moduli</h3>
- <p>Form data contains information typed into web forms, like user names, addresses, phone numbers, etc., and lists them in a drop-down box on future visits.
- Unlike the other forms of local storage, form data is not sent to the web server without specific user interaction.
- Beginning in Android Oreo (8.0), WebView’s form data was replaced by the <a href="https://medium.com/@bherbst/getting-androids-autofill-to-work-for-you-21435debea1">Autofill service</a>.
- As such, controls for form data no longer appear on newer Android devices.</p>
+ <p>I dati dei moduli contengono le informazioni che vengono digitate nei web form, come user name, indirizzi, numeri di telefono, ecc.
+ per poterli elencare in menù a tendina in caso di visite successive.
+ A differenza delle altre modalità di memorizzazione locale delle informazioni, i dati dei moduli non vengono inviati ai web server senza una interazione con l'utente.
+ A partire da Android Oreo (8.0), i dati dei moduli di WebView’s sono stati sostituiti dal
+ <a href="https://medium.com/@bherbst/getting-androids-autofill-to-work-for-you-21435debea1">Servizio di Riempimento Automatico</a>.
+ Per questo motivo i controlli per i dati dei moduli non sono più disponibili nei dispositivi Android più recenti.</p>
</body>
</html>
\ No newline at end of file
<img class="center" src="images/bookmarks.png">
- <p>Tapping the top floating action button loads the bookmarks activity, which has advanced options like moving and deleting bookmarks.
- From the bookmarks activity, there is an option to load the bookmarks database view.
- This shows the bookmarks as they exist in the SQLite database, which can be useful for troubleshooting problems with importing and exporting bookmarks.</p>
+ <p>Нажатие верхней всплывающей кнопки позволит совершать над закладками такие действия, как перемещение и удаление. Также из этого меню есть возможность загрузить представление базы данных закладок.
+ Это отобразит закладки так, как они существуют в базе данных SQLite, что может быть полезным для устранения проблем с импортом и экспортом закладок.</p>
</body>
</html>
\ No newline at end of file
<img class="center" src="images/bookmarks.png">
- <p>Tapping the top floating action button loads the bookmarks activity, which has advanced options like moving and deleting bookmarks.
- From the bookmarks activity, there is an option to load the bookmarks database view.
- This shows the bookmarks as they exist in the SQLite database, which can be useful for troubleshooting problems with importing and exporting bookmarks.</p>
+ <p>Нажатие верхней всплывающей кнопки позволит совершать над закладками такие действия, как перемещение и удаление. Также из этого меню есть возможность загрузить представление базы данных закладок.
+ Это отобразит закладки так, как они существуют в базе данных SQLite, что может быть полезным для устранения проблем с импортом и экспортом закладок.</p>
</body>
</html>
\ No newline at end of file
assert appBar != null;
// Display the spinner and the back arrow in the app bar.
- appBar.setCustomView(R.layout.bookmarks_databaseview_spinner);
+ appBar.setCustomView(R.layout.spinner);
appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP);
// Initialize the database handler. `this` specifies the context. The two `null`s do not specify the database name or a `CursorFactory`. The `0` is to specify a database version, but that is set instead using a constant in `BookmarksDatabaseHelper`.
MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor});
// Create a resource cursor adapter for the spinner.
- ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(this, R.layout.bookmarks_databaseview_spinner_item, foldersMergeCursor, 0) {
+ ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(this, R.layout.appbar_spinner_item, foldersMergeCursor, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Get a handle for the spinner item text view.
};
// Set the resource cursor adapter drop drown view resource.
- foldersCursorAdapter.setDropDownViewResource(R.layout.bookmarks_databaseview_spinner_dropdown_item);
+ foldersCursorAdapter.setDropDownViewResource(R.layout.appbar_spinner_dropdown_item);
// Get a handle for the folder spinner and set the adapter.
- Spinner folderSpinner = findViewById(R.id.bookmarks_databaseview_spinner);
+ Spinner folderSpinner = findViewById(R.id.spinner);
folderSpinner.setAdapter(foldersCursorAdapter);
// Handle clicks on the spinner dropdown.
import android.provider.DocumentsContract;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
+import android.support.design.widget.TextInputLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
+import android.widget.Spinner;
import android.widget.TextView;
import com.stoutner.privacybrowser.R;
import com.stoutner.privacybrowser.helpers.ImportExportDatabaseHelper;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
public class ImportExportActivity extends AppCompatActivity implements ImportExportStoragePermissionDialog.ImportExportStoragePermissionDialogListener {
- private final static int EXPORT_FILE_PICKER_REQUEST_CODE = 1;
- private final static int IMPORT_FILE_PICKER_REQUEST_CODE = 2;
- private final static int EXPORT_REQUEST_CODE = 3;
- private final static int IMPORT_REQUEST_CODE = 4;
+ // Create the encryption constants.
+ private final int NO_ENCRYPTION = 0;
+ private final int PASSWORD_ENCRYPTION = 1;
+ private final int GPG_ENCRYPTION = 2;
+
+ // Create the action constants.
+ private final int IMPORT = 0;
+ private final int EXPORT = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
appBar.setDisplayHomeAsUpEnabled(true);
// Get handles for the views that need to be modified.
- EditText exportFileEditText = findViewById(R.id.export_file_edittext);
- Button exportButton = findViewById(R.id.export_button);
- EditText importFileEditText = findViewById(R.id.import_file_edittext);
- Button importButton = findViewById(R.id.import_button);
+ Spinner encryptionSpinner = findViewById(R.id.encryption_spinner);
+ TextInputLayout passwordEncryptionTextInputLayout = findViewById(R.id.password_encryption_textinputlayout);
+ EditText encryptionPasswordEditText = findViewById(R.id.password_encryption_edittext);
+ Spinner importExportSpinner = findViewById(R.id.import_export_spinner);
+ EditText fileNameEditText = findViewById(R.id.file_name_edittext);
+ Button importExportButton = findViewById(R.id.import_export_button);
TextView storagePermissionTextView = findViewById(R.id.import_export_storage_permission_textview);
- // Initially disable the buttons.
- exportButton.setEnabled(false);
- importButton.setEnabled(false);
+ // Create array adapters for the spinners.
+ ArrayAdapter<CharSequence> encryptionArrayAdapter = ArrayAdapter.createFromResource(this, R.array.encryption_type, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> importExportArrayAdapter = ArrayAdapter.createFromResource(this, R.array.import_export_spinner, R.layout.spinner_item);
+
+ // Set the drop down view resource on the spinners.
+ encryptionArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_items);
+ importExportArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_items);
+
+ // Set the array adapters for the spinners.
+ encryptionSpinner.setAdapter(encryptionArrayAdapter);
+ importExportSpinner.setAdapter(importExportArrayAdapter);
+
+ // Initially hide the encryption layout items.
+ passwordEncryptionTextInputLayout.setVisibility(View.GONE);
+
+ // Create strings for the default file paths.
+ String defaultFilePath;
+ String defaultPasswordEncryptionFilePath;
+ String defaultGpgEncryptionFilePath;
+
+ // Set the default file paths according to the storage permission status.
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted.
+ // Set the default file paths to use the external public directory.
+ defaultFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + getString(R.string.privacy_browser_settings);
+ defaultPasswordEncryptionFilePath = defaultFilePath + ".aes";
+ defaultGpgEncryptionFilePath = defaultFilePath + ".gpg";
+ } else { // The storage permission has not been granted.
+ // Set the default file paths to use the external private directory.
+ defaultFilePath = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/" + getString(R.string.privacy_browser_settings);
+ defaultPasswordEncryptionFilePath = defaultFilePath + ".aes";
+ defaultGpgEncryptionFilePath = defaultFilePath + ".gpg";
+ }
- // Enable the export button when the export file EditText isn't empty.
- exportFileEditText.addTextChangedListener(new TextWatcher() {
+ // Set the default file path.
+ fileNameEditText.setText(defaultFilePath);
+
+ // Display the encryption information when the spinner changes.
+ encryptionSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ switch (position) {
+ case NO_ENCRYPTION:
+ // Hide the encryption layout items.
+ passwordEncryptionTextInputLayout.setVisibility(View.GONE);
+
+ // Reset the default file path.
+ fileNameEditText.setText(defaultFilePath);
+
+ // Enable the import/export button if a file name exists.
+ importExportButton.setEnabled(!fileNameEditText.getText().toString().isEmpty());
+ break;
+
+ case PASSWORD_ENCRYPTION:
+ // Show the password encryption layout items.
+ passwordEncryptionTextInputLayout.setVisibility(View.VISIBLE);
+
+ // Update the default file path.
+ fileNameEditText.setText(defaultPasswordEncryptionFilePath);
+
+ // Enable the import/export button if a file name and password exists.
+ importExportButton.setEnabled(!fileNameEditText.getText().toString().isEmpty() && !encryptionPasswordEditText.getText().toString().isEmpty());
+ break;
+
+ case GPG_ENCRYPTION:
+ // Hide the password encryption layout items.
+ passwordEncryptionTextInputLayout.setVisibility(View.GONE);
+
+ // Update the default file path.
+ fileNameEditText.setText(defaultGpgEncryptionFilePath);
+ break;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ });
+
+ // Update the import/export button when the spinner changes.
+ importExportSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ switch (position) {
+ case IMPORT:
+ importExportButton.setText(R.string.import_button);
+ break;
+
+ case EXPORT:
+ importExportButton.setText(R.string.export);
+ break;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+
+ }
+ });
+
+ // Update the status of the import/export button when the password changes.
+ encryptionPasswordEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing.
@Override
public void afterTextChanged(Editable s) {
- exportButton.setEnabled(!exportFileEditText.getText().toString().isEmpty());
+ // Enable the import/export button if a file name and password exists.
+ importExportButton.setEnabled(!fileNameEditText.getText().toString().isEmpty() && !encryptionPasswordEditText.getText().toString().isEmpty());
}
});
- // Enable the import button when the export file EditText isn't empty.
- importFileEditText.addTextChangedListener(new TextWatcher() {
+ // Update the status of the import/export button when the file name EditText changes.
+ fileNameEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing.
@Override
public void afterTextChanged(Editable s) {
- importButton.setEnabled(!importFileEditText.getText().toString().isEmpty());
+ // Adjust the export button according to the encryption spinner position.
+ switch (encryptionSpinner.getSelectedItemPosition()) {
+ case NO_ENCRYPTION:
+ // Enable the import/export button if a file name exists.
+ importExportButton.setEnabled(!fileNameEditText.getText().toString().isEmpty());
+ break;
+
+ case PASSWORD_ENCRYPTION:
+ // Enable the import/export button if a file name and password exists.
+ importExportButton.setEnabled(!fileNameEditText.getText().toString().isEmpty() && !encryptionPasswordEditText.getText().toString().isEmpty());
+ break;
+
+ case GPG_ENCRYPTION:
+ break;
+ }
}
});
- // Set the initial file paths.
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // The storage permission has been granted.
- // Create a string for the external public path.
- String EXTERNAL_PUBLIC_PATH = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + getString(R.string.privacy_browser_settings);
-
- // Set the default path.
- exportFileEditText.setText(EXTERNAL_PUBLIC_PATH);
- importFileEditText.setText(EXTERNAL_PUBLIC_PATH);
- } else { // The storage permission has not been granted.
- // Create a string for the external private path.
- String EXTERNAL_PRIVATE_PATH = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) + "/" + getString(R.string.privacy_browser_settings);
-
- // Set the default path.
- exportFileEditText.setText(EXTERNAL_PRIVATE_PATH);
- importFileEditText.setText(EXTERNAL_PRIVATE_PATH);
- }
-
// Hide the storage permissions TextView on API < 23 as permissions on older devices are automatically granted.
if (Build.VERSION.SDK_INT < 23) {
storagePermissionTextView.setVisibility(View.GONE);
}
}
- public void exportBrowse(View view) {
- // Create the file picker intent.
- Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
+ public void browse(View view) {
+ // Get a handle for the import/export spinner.
+ Spinner importExportSpinner = findViewById(R.id.import_export_spinner);
- // Set the intent MIME type to include all files.
- intent.setType("*/*");
+ // Check to see if import or export is selected.
+ if (importExportSpinner.getSelectedItemPosition() == IMPORT) { // Import is selected.
+ // Create the file picker intent.
+ Intent importIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
- // Set the initial export file name.
- intent.putExtra(Intent.EXTRA_TITLE, getString(R.string.privacy_browser_settings));
+ // Set the intent MIME type to include all files.
+ importIntent.setType("*/*");
- // Set the initial directory if API >= 26.
- if (Build.VERSION.SDK_INT >= 26) {
- intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.getExternalStorageDirectory());
- }
+ // Set the initial directory if API >= 26.
+ if (Build.VERSION.SDK_INT >= 26) {
+ importIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.getExternalStorageDirectory());
+ }
+
+ // Specify that a file that can be opened is requested.
+ importIntent.addCategory(Intent.CATEGORY_OPENABLE);
- // Specify that a file that can be opened is requested.
- intent.addCategory(Intent.CATEGORY_OPENABLE);
+ // Launch the file picker.
+ startActivityForResult(importIntent, 0);
+ } else { // Export is selected
+ // Create the file picker intent.
+ Intent exportIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
- // Launch the file picker.
- startActivityForResult(intent, EXPORT_FILE_PICKER_REQUEST_CODE);
+ // Set the intent MIME type to include all files.
+ exportIntent.setType("*/*");
+
+ // Set the initial export file name.
+ exportIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.privacy_browser_settings));
+
+ // Set the initial directory if API >= 26.
+ if (Build.VERSION.SDK_INT >= 26) {
+ exportIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.getExternalStorageDirectory());
+ }
+
+ // Specify that a file that can be opened is requested.
+ exportIntent.addCategory(Intent.CATEGORY_OPENABLE);
+
+ // Launch the file picker.
+ startActivityForResult(exportIntent, 0);
+ }
}
- public void onClickExport(View view) {
+ public void importExport(View view) {
+ // Get a handle for the import/export spinner.
+ Spinner importExportSpinner = findViewById(R.id.import_export_spinner);
+
// Check to see if the storage permission has been granted.
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // Storage permission granted.
- // Export the settings.
- exportSettings();
+ // Check to see if import or export is selected.
+ if (importExportSpinner.getSelectedItemPosition() == IMPORT) { // Import is selected.
+ // Import the settings.
+ importSettings();
+ } else { // Export is selected.
+ // Export the settings.
+ exportSettings();
+ }
} else { // Storage permission not granted.
- // Get a handle for the export file EditText.
- EditText exportFileEditText = findViewById(R.id.export_file_edittext);
+ // Get a handle for the file name EditText.
+ EditText fileNameEditText = findViewById(R.id.file_name_edittext);
- // Get the export file string.
- String exportFileString = exportFileEditText.getText().toString();
+ // Get the file name string.
+ String fileNameString = fileNameEditText.getText().toString();
// Get the external private directory `File`.
File externalPrivateDirectoryFile = getApplicationContext().getExternalFilesDir(null);
// Get the external private directory string.
String externalPrivateDirectory = externalPrivateDirectoryFile.toString();
- // Check to see if the export file path is in the external private directory.
- if (exportFileString.startsWith(externalPrivateDirectory)) { // The export path is in the external private directory.
- // Export the settings.
- exportSettings();
- } else { // The export path is in a public directory.
+ // Check to see if the file path is in the external private directory.
+ if (fileNameString.startsWith(externalPrivateDirectory)) { // The file path is in the external private directory.
+ // Check to see if import or export is selected.
+ if (importExportSpinner.getSelectedItemPosition() == IMPORT) { // Import is selected.
+ // Import the settings.
+ importSettings();
+ } else { // Export is selected.
+ // Export the settings.
+ exportSettings();
+ }
+ } 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 and set the type to EXPORT_SETTINGS.
- DialogFragment importExportStoragePermissionDialogFragment = ImportExportStoragePermissionDialog.type(ImportExportStoragePermissionDialog.EXPORT_SETTINGS);
+ // Instantiate the storage permission alert dialog.
+ DialogFragment importExportStoragePermissionDialogFragment = new ImportExportStoragePermissionDialog();
// Show the storage permission alert dialog. The permission will be requested when the dialog is closed.
importExportStoragePermissionDialogFragment.show(getFragmentManager(), getString(R.string.storage_permission));
} else { // Show the permission request directly.
// Request the storage permission. The export will be run when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXPORT_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}
}
}
}
- public void importBrowse(View view) {
- // Create the file picker intent.
- Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
-
- // Set the intent MIME type to include all files.
- intent.setType("*/*");
-
- // Set the initial directory if API >= 26.
- if (Build.VERSION.SDK_INT >= 26) {
- intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment.getExternalStorageDirectory());
- }
-
- // Specify that a file that can be opened is requested.
- intent.addCategory(Intent.CATEGORY_OPENABLE);
-
- // Launch the file picker.
- startActivityForResult(intent, IMPORT_FILE_PICKER_REQUEST_CODE);
+ @Override
+ public void onCloseImportExportStoragePermissionDialog() {
+ // 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);
}
- public void onClickImport(View view) {
- // Check to see if the storage permission has been granted.
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { // Storage permission granted.
- // Import the settings.
- importSettings();
- } else { // Storage permission not granted.
- // Get a handle for the import file EditText.
- EditText importFileEditText = findViewById(R.id.import_file_edittext);
-
- // Get the import file string.
- String importFileString = importFileEditText.getText().toString();
-
- // Get the external private directory `File`.
- File externalPrivateDirectoryFile = getApplicationContext().getExternalFilesDir(null);
-
- // Remove the lint error below that `File` might be null.
- assert externalPrivateDirectoryFile != null;
-
- // Get the external private directory string.
- String externalPrivateDirectory = externalPrivateDirectoryFile.toString();
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ // Get a handle for the import/export spinner.
+ Spinner importExportSpinner = findViewById(R.id.import_export_spinner);
- // Check to see if the import file path is in the external private directory.
- if (importFileString.startsWith(externalPrivateDirectory)) { // The import path is in the external private directory.
+ // Check to see if import or export is selected.
+ if (importExportSpinner.getSelectedItemPosition() == IMPORT) { // Import is selected.
+ // 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.
// Import the settings.
importSettings();
- } else { // The import path is in a public directory.
- // Check if the user has previously denied the storage permission.
- if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { // Show a dialog explaining the request first.
- // Instantiate the storage permission alert dialog and set the type to IMPORT_SETTINGS.
- DialogFragment importExportStoragePermissionDialogFragment = ImportExportStoragePermissionDialog.type(ImportExportStoragePermissionDialog.IMPORT_SETTINGS);
-
- // Show the storage permission alert dialog. The permission will be requested when the dialog is closed.
- importExportStoragePermissionDialogFragment.show(getFragmentManager(), getString(R.string.storage_permission));
- } else { // Show the permission request directly.
- // Request the storage permission. The export will be run when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, IMPORT_REQUEST_CODE);
- }
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(importExportSpinner, getString(R.string.cannot_import), Snackbar.LENGTH_LONG).show();
+ }
+ } else { // Export is selected.
+ // 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.
+ // Export the settings.
+ exportSettings();
+ } else { // The storage permission was not granted.
+ // Display an error snackbar.
+ Snackbar.make(importExportSpinner, getString(R.string.cannot_export), Snackbar.LENGTH_LONG).show();
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Don't do anything if the user pressed back from the file picker.
if (resultCode == Activity.RESULT_OK) {
- // Run the commands for the specific request code.
- switch (requestCode) {
- case EXPORT_FILE_PICKER_REQUEST_CODE:
- // Get a handle for the export file EditText.
- EditText exportFileEditText = findViewById(R.id.export_file_edittext);
-
- // Get the selected export file.
- Uri exportUri = data.getData();
-
- // Remove the lint warning that the export URI might be null.
- assert exportUri != null;
-
- // Get the raw export path.
- String rawExportPath = exportUri.getPath();
-
- // Remove the warning that the raw export path might be null.
- assert rawExportPath != null;
-
- // Check to see if the rawExportPath includes a valid storage location.
- if (rawExportPath.contains(":")) { // The path is valid.
- // Split the path into the initial content uri and the path information.
- String exportContentPath = rawExportPath.substring(0, rawExportPath.indexOf(":"));
- String exportFilePath = rawExportPath.substring(rawExportPath.indexOf(":") + 1);
-
- // Create the export path string.
- String exportPath;
-
- // Construct the export path.
- switch (exportContentPath) {
- // The documents home has a special content path.
- case "/document/home":
- exportPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + exportFilePath;
- break;
-
- // Everything else for the primary user should be in `/document/primary`.
- case "/document/primary":
- exportPath = Environment.getExternalStorageDirectory() + "/" + exportFilePath;
- break;
-
- // Just in case, catch everything else and place it in the external storage directory.
- default:
- exportPath = Environment.getExternalStorageDirectory() + "/" + exportFilePath;
- break;
- }
-
- // Set the export file URI as the text for the export file EditText.
- exportFileEditText.setText(exportPath);
- } else { // The path is invalid.
- Snackbar.make(exportFileEditText, rawExportPath + " + " + getString(R.string.invalid_location), Snackbar.LENGTH_INDEFINITE).show();
- }
- break;
-
- case IMPORT_FILE_PICKER_REQUEST_CODE:
- // Get a handle for the import file EditText.
- EditText importFileEditText = findViewById(R.id.import_file_edittext);
-
- // Get the selected import file.
- Uri importUri = data.getData();
-
- // Remove the lint warning that the import URI might be null.
- assert importUri != null;
-
- // Get the raw import path.
- String rawImportPath = importUri.getPath();
-
- // Remove the warning that the raw import path might be null.
- assert rawImportPath != null;
-
- // Check to see if the rawExportPath includes a valid storage location.
- if (rawImportPath.contains(":")) { // The path is valid.
- // Split the path into the initial content uri and the path information.
- String importContentPath = rawImportPath.substring(0, rawImportPath.indexOf(":"));
- String importFilePath = rawImportPath.substring(rawImportPath.indexOf(":") + 1);
-
- // Create the export path string.
- String importPath;
-
- // Construct the export path.
- switch (importContentPath) {
- // The documents folder has a special content path.
- case "/document/home":
- importPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + importFilePath;
- break;
-
- // Everything else for the primary user should be in `/document/primary`.
- case "/document/primary":
- importPath = Environment.getExternalStorageDirectory() + "/" + importFilePath;
- break;
-
- // Just in case, catch everything else and place it in the external storage directory.
- default:
- importPath = Environment.getExternalStorageDirectory() + "/" + importFilePath;
- break;
- }
-
- // Set the export file URI as the text for the export file EditText.
- importFileEditText.setText(importPath);
- } else { // The path is invalid.
- Snackbar.make(importFileEditText, rawImportPath + " + " + getString(R.string.invalid_location), Snackbar.LENGTH_INDEFINITE).show();
- }
- break;
+ // Get a handle for the file name EditText.
+ EditText fileNameEditText = findViewById(R.id.file_name_edittext);
+
+ // Get the file name URI.
+ Uri fileNameUri = data.getData();
+
+ // Remove the lint warning that the file name URI might be null.
+ assert fileNameUri != null;
+
+ // Get the raw file name path.
+ String rawFileNamePath = fileNameUri.getPath();
+
+ // Remove the warning that the file name path might be null.
+ assert rawFileNamePath != null;
+
+ // Check to see if the file name Path includes a valid storage location.
+ if (rawFileNamePath.contains(":")) { // The path is valid.
+ // Split the path into the initial content uri and the final path information.
+ String fileNameContentPath = rawFileNamePath.substring(0, rawFileNamePath.indexOf(":"));
+ String fileNameFinalPath = rawFileNamePath.substring(rawFileNamePath.indexOf(":") + 1);
+
+ // Create the file name path string.
+ String fileNamePath;
+
+ // Construct the file name path.
+ switch (fileNameContentPath) {
+ // The documents home has a special content path.
+ case "/document/home":
+ fileNamePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/" + fileNameFinalPath;
+ break;
+
+ // Everything else for the primary user should be in `/document/primary`.
+ case "/document/primary":
+ fileNamePath = Environment.getExternalStorageDirectory() + "/" + fileNameFinalPath;
+ break;
+
+ // Just in case, catch everything else and place it in the external storage directory.
+ default:
+ fileNamePath = Environment.getExternalStorageDirectory() + "/" + fileNameFinalPath;
+ break;
+ }
+
+ // Set the file name path as the text of the file name EditText.
+ fileNameEditText.setText(fileNamePath);
+ } else { // The path is invalid.
+ Snackbar.make(fileNameEditText, rawFileNamePath + " + " + getString(R.string.invalid_location), Snackbar.LENGTH_INDEFINITE).show();
}
}
}
- @Override
- public void onCloseImportExportStoragePermissionDialog(int type) {
- // Request the storage permission based on the button that was pressed.
- switch (type) {
- case ImportExportStoragePermissionDialog.EXPORT_SETTINGS:
- // Request the storage permission. The export will be run when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXPORT_REQUEST_CODE);
- break;
+ private void exportSettings() {
+ // Get a handle for the views.
+ Spinner encryptionSpinner = findViewById(R.id.encryption_spinner);
+ EditText fileNameEditText = findViewById(R.id.file_name_edittext);
- case ImportExportStoragePermissionDialog.IMPORT_SETTINGS:
- // Request the storage permission. The import will be run when it finishes.
- ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, IMPORT_REQUEST_CODE);
- break;
- }
- }
+ // Instantiate the import export database helper.
+ ImportExportDatabaseHelper importExportDatabaseHelper = new ImportExportDatabaseHelper();
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- switch (requestCode) {
- case EXPORT_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.
- // Export the settings.
- exportSettings();
- } else { // The storage permission was not granted.
- // Get a handle for the export file EditText.
- EditText exportFileEditText = findViewById(R.id.export_file_edittext);
+ // Get the export file.
+ File exportFile = new File(fileNameEditText.getText().toString());
- // Display an error snackbar.
- Snackbar.make(exportFileEditText, getString(R.string.cannot_export), Snackbar.LENGTH_LONG).show();
- }
+ // Initialize the export status string.
+ String exportStatus = "";
+
+ // Export according to the encryption type.
+ switch (encryptionSpinner.getSelectedItemPosition()) {
+ case NO_ENCRYPTION:
+ // Export the unencrypted file.
+ exportStatus = importExportDatabaseHelper.exportUnencrypted(exportFile, this);
break;
- case IMPORT_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.
- // Import the settings.
- importSettings();
- } else { // The storage permission was not granted.
- // Get a handle for the import file EditText.
- EditText importFileEditText = findViewById(R.id.import_file_edittext);
+ case PASSWORD_ENCRYPTION:
+ // Use a private temporary export location.
+ File temporaryUnencryptedExportFile = new File(getApplicationContext().getCacheDir() + "/export.temp");
- // Display an error snackbar.
- Snackbar.make(importFileEditText, getString(R.string.cannot_import), Snackbar.LENGTH_LONG).show();
- }
- break;
- }
- }
+ // Create an unencrypted export in the private location.
+ exportStatus = importExportDatabaseHelper.exportUnencrypted(temporaryUnencryptedExportFile, this);
- private void exportSettings() {
- // Get a handle for the export file EditText.
- EditText exportFileEditText = findViewById(R.id.export_file_edittext);
+ try {
+ // Create an unencrypted export file input stream.
+ FileInputStream unencryptedExportFileInputStream = new FileInputStream(temporaryUnencryptedExportFile);
- // Get the export file string.
- String exportFileString = exportFileEditText.getText().toString();
+ // Delete the encrypted export file if it exists.
+ if (exportFile.exists()) {
+ //noinspection ResultOfMethodCallIgnored
+ exportFile.delete();
+ }
- // Set the export file.
- File exportFile = new File(exportFileString);
+ // Create an encrypted export file output stream.
+ FileOutputStream encryptedExportFileOutputStream = new FileOutputStream(exportFile);
- // Instantiate the import export database helper.
- ImportExportDatabaseHelper importExportDatabaseHelper = new ImportExportDatabaseHelper();
+ // Get a handle for the encryption password EditText.
+ EditText encryptionPasswordEditText = findViewById(R.id.password_encryption_edittext);
+
+ // Get the encryption password.
+ String encryptionPasswordString = encryptionPasswordEditText.getText().toString();
+
+ // Initialize a secure random number generator.
+ SecureRandom secureRandom = new SecureRandom();
+
+ // Get a 256 bit (32 byte) random salt.
+ byte[] saltByteArray = new byte[32];
+ secureRandom.nextBytes(saltByteArray);
+
+ // Convert the encryption password to a byte array.
+ byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes("UTF-8");
+
+ // Append the salt to the encryption password byte array. This protects against rainbow table attacks.
+ byte[] encryptionPasswordWithSaltByteArray = new byte[encryptionPasswordByteArray.length + saltByteArray.length];
+ System.arraycopy(encryptionPasswordByteArray, 0, encryptionPasswordWithSaltByteArray, 0, encryptionPasswordByteArray.length);
+ System.arraycopy(saltByteArray, 0, encryptionPasswordWithSaltByteArray, encryptionPasswordByteArray.length, saltByteArray.length);
+
+ // Get a SHA-512 message digest.
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
+
+ // Hash the salted encryption password. Otherwise, any characters after the 32nd character in the password are ignored.
+ byte[] hashedEncryptionPasswordWithSaltByteArray = messageDigest.digest(encryptionPasswordWithSaltByteArray);
+
+ // Truncate the encryption password byte array to 256 bits (32 bytes).
+ byte[] truncatedHashedEncryptionPasswordWithSaltByteArray = Arrays.copyOf(hashedEncryptionPasswordWithSaltByteArray, 32);
+
+ // Create an AES secret key from the encryption password byte array.
+ SecretKeySpec secretKey = new SecretKeySpec(truncatedHashedEncryptionPasswordWithSaltByteArray, "AES");
+
+ // Generate a random 12 byte initialization vector. According to NIST, a 12 byte initialization vector is more secure than a 16 byte one.
+ byte[] initializationVector = new byte[12];
+ secureRandom.nextBytes(initializationVector);
+
+ // Get a Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding.
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+ // Set the GCM tag length to be 128 bits (the maximum) and apply the initialization vector.
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initializationVector);
+
+ // Initialize the cipher.
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
+
+ // Add the salt and the initialization vector to the export file.
+ encryptedExportFileOutputStream.write(saltByteArray);
+ encryptedExportFileOutputStream.write(initializationVector);
- // Export the unencrypted file.
- String exportStatus = importExportDatabaseHelper.exportUnencrypted(exportFile, getApplicationContext());
+ // Create a cipher output stream.
+ CipherOutputStream cipherOutputStream = new CipherOutputStream(encryptedExportFileOutputStream, cipher);
+
+ // Initialize variables to store data as it is moved from the unencrypted export file input stream to the cipher output stream. Move 128 bits (16 bytes) at a time.
+ int numberOfBytesRead;
+ byte[] encryptedBytes = new byte[16];
+
+ // Read up to 128 bits (16 bytes) of data from the unencrypted export file stream. `-1` will be returned when the end of the file is reached.
+ while ((numberOfBytesRead = unencryptedExportFileInputStream.read(encryptedBytes)) != -1) {
+ // Write the data to the cipher output stream.
+ cipherOutputStream.write(encryptedBytes, 0, numberOfBytesRead);
+ }
+
+ // Close the streams.
+ cipherOutputStream.flush();
+ cipherOutputStream.close();
+ encryptedExportFileOutputStream.close();
+ unencryptedExportFileInputStream.close();
+
+ // Wipe the encryption data from memory.
+ //noinspection UnusedAssignment
+ encryptionPasswordString = "";
+ Arrays.fill(saltByteArray, (byte) 0);
+ Arrays.fill(encryptionPasswordByteArray, (byte) 0);
+ Arrays.fill(encryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(hashedEncryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(truncatedHashedEncryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(initializationVector, (byte) 0);
+ Arrays.fill(encryptedBytes, (byte) 0);
+
+ // Delete the temporary unencrypted export file.
+ //noinspection ResultOfMethodCallIgnored
+ temporaryUnencryptedExportFile.delete();
+ } catch (Exception exception) {
+ exportStatus = exception.toString();
+ }
+ break;
+
+ case GPG_ENCRYPTION:
+
+ break;
+ }
// Show a disposition snackbar.
if (exportStatus.equals(ImportExportDatabaseHelper.EXPORT_SUCCESSFUL)) {
- Snackbar.make(exportFileEditText, getString(R.string.export_successful), Snackbar.LENGTH_SHORT).show();
+ Snackbar.make(fileNameEditText, getString(R.string.export_successful), Snackbar.LENGTH_SHORT).show();
} else {
- Snackbar.make(exportFileEditText, getString(R.string.export_failed) + " " + exportStatus, Snackbar.LENGTH_INDEFINITE).show();
+ Snackbar.make(fileNameEditText, getString(R.string.export_failed) + " " + exportStatus, Snackbar.LENGTH_INDEFINITE).show();
}
}
private void importSettings() {
- // Get a handle for the import file EditText.
- EditText importFileEditText = findViewById(R.id.import_file_edittext);
-
- // Get the import file string.
- String importFileString = importFileEditText.getText().toString();
-
- // Set the import file.
- File importFile = new File(importFileString);
+ // Get a handle for the views.
+ Spinner encryptionSpinner = findViewById(R.id.encryption_spinner);
+ EditText fileNameEditText = findViewById(R.id.file_name_edittext);
// Instantiate the import export database helper.
ImportExportDatabaseHelper importExportDatabaseHelper = new ImportExportDatabaseHelper();
- // Import the unencrypted file.
- String importStatus = importExportDatabaseHelper.importUnencrypted(importFile, getApplicationContext());
+ // Get the import file.
+ File importFile = new File(fileNameEditText.getText().toString());
+
+ // Initialize the import status string
+ String importStatus = "";
+
+ // Import according to the encryption type.
+ switch (encryptionSpinner.getSelectedItemPosition()) {
+ case NO_ENCRYPTION:
+ // Import the unencrypted file.
+ importStatus = importExportDatabaseHelper.importUnencrypted(importFile, this);
+ break;
+
+ case PASSWORD_ENCRYPTION:
+ // Use a private temporary import location.
+ File temporaryUnencryptedImportFile = new File(getApplicationContext().getCacheDir() + "/import.temp");
+
+ try {
+ // Create an encrypted import file input stream.
+ FileInputStream encryptedImportFileInputStream = new FileInputStream(importFile);
+
+ // Delete the temporary import file if it exists.
+ if (temporaryUnencryptedImportFile.exists()) {
+ //noinspection ResultOfMethodCallIgnored
+ temporaryUnencryptedImportFile.delete();
+ }
+
+ // Create an unencrypted import file output stream.
+ FileOutputStream unencryptedImportFileOutputStream = new FileOutputStream(temporaryUnencryptedImportFile);
+
+ // Get a handle for the encryption password EditText.
+ EditText encryptionPasswordEditText = findViewById(R.id.password_encryption_edittext);
+
+ // Get the encryption password.
+ String encryptionPasswordString = encryptionPasswordEditText.getText().toString();
+
+ // Get the salt from the beginning of the import file.
+ byte[] saltByteArray = new byte[32];
+ //noinspection ResultOfMethodCallIgnored
+ encryptedImportFileInputStream.read(saltByteArray);
+
+ // Get the initialization vector from the import file.
+ byte[] initializationVector = new byte[12];
+ //noinspection ResultOfMethodCallIgnored
+ encryptedImportFileInputStream.read(initializationVector);
+
+ // Convert the encryption password to a byte array.
+ byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes("UTF-8");
+
+ // Append the salt to the encryption password byte array. This protects against rainbow table attacks.
+ byte[] encryptionPasswordWithSaltByteArray = new byte[encryptionPasswordByteArray.length + saltByteArray.length];
+ System.arraycopy(encryptionPasswordByteArray, 0, encryptionPasswordWithSaltByteArray, 0, encryptionPasswordByteArray.length);
+ System.arraycopy(saltByteArray, 0, encryptionPasswordWithSaltByteArray, encryptionPasswordByteArray.length, saltByteArray.length);
+
+ // Get a SHA-512 message digest.
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
+
+ // Hash the salted encryption password. Otherwise, any characters after the 32nd character in the password are ignored.
+ byte[] hashedEncryptionPasswordWithSaltByteArray = messageDigest.digest(encryptionPasswordWithSaltByteArray);
+
+ // Truncate the encryption password byte array to 256 bits (32 bytes).
+ byte[] truncatedHashedEncryptionPasswordWithSaltByteArray = Arrays.copyOf(hashedEncryptionPasswordWithSaltByteArray, 32);
+
+ // Create an AES secret key from the encryption password byte array.
+ SecretKeySpec secretKey = new SecretKeySpec(truncatedHashedEncryptionPasswordWithSaltByteArray, "AES");
+
+ // Get a Advanced Encryption Standard, Galois/Counter Mode, No Padding cipher instance. Galois/Counter mode protects against modification of the ciphertext. It doesn't use padding.
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+ // Set the GCM tag length to be 128 bits (the maximum) and apply the initialization vector.
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, initializationVector);
+
+ // Initialize the cipher.
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
+
+ // Create a cipher input stream.
+ CipherInputStream cipherInputStream = new CipherInputStream(encryptedImportFileInputStream, cipher);
+
+ // Initialize variables to store data as it is moved from the cipher input stream to the unencrypted import file output stream. Move 128 bits (16 bytes) at a time.
+ int numberOfBytesRead;
+ byte[] decryptedBytes = new byte[16];
+
+ // Read up to 128 bits (16 bytes) of data from the cipher input stream. `-1` will be returned when the end fo the file is reached.
+ while ((numberOfBytesRead = cipherInputStream.read(decryptedBytes)) != -1) {
+ // Write the data to the unencrypted import file output stream.
+ unencryptedImportFileOutputStream.write(decryptedBytes, 0, numberOfBytesRead);
+ }
+
+ // Close the streams.
+ unencryptedImportFileOutputStream.flush();
+ unencryptedImportFileOutputStream.close();
+ cipherInputStream.close();
+ encryptedImportFileInputStream.close();
+
+ // Wipe the encryption data from memory.
+ //noinspection UnusedAssignment
+ encryptionPasswordString = "";
+ Arrays.fill(saltByteArray, (byte) 0);
+ Arrays.fill(initializationVector, (byte) 0);
+ Arrays.fill(encryptionPasswordByteArray, (byte) 0);
+ Arrays.fill(encryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(hashedEncryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(truncatedHashedEncryptionPasswordWithSaltByteArray, (byte) 0);
+ Arrays.fill(decryptedBytes, (byte) 0);
+
+ // Import the unencrypted database from the private location.
+ importStatus = importExportDatabaseHelper.importUnencrypted(temporaryUnencryptedImportFile, this);
+
+ // Delete the temporary unencrypted import file.
+ //noinspection ResultOfMethodCallIgnored
+ temporaryUnencryptedImportFile.delete();
+ } catch (Exception exception) {
+ importStatus = exception.toString();
+ }
+ break;
+
+ case GPG_ENCRYPTION:
+
+ break;
+ }
// Respond to the import disposition.
if (importStatus.equals(ImportExportDatabaseHelper.IMPORT_SUCCESSFUL)) { // The import was successful.
startActivity(restartIntent);
} else { // The import was not successful.
// Display a snack bar with the import error.
- Snackbar.make(importFileEditText, getString(R.string.import_failed) + " " + importStatus, Snackbar.LENGTH_INDEFINITE).show();
+ Snackbar.make(fileNameEditText, getString(R.string.import_failed) + " " + importStatus, Snackbar.LENGTH_INDEFINITE).show();
}
}
}
\ No newline at end of file
}
// Initialize the user agent array adapter and string array.
- userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
+ userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item);
userAgentDataArray = getResources().getStringArray(R.array.user_agent_data);
// Apply the app settings from the shared preferences.
assert appBar != null;
// Display the spinner and the back arrow in the app bar.
- appBar.setCustomView(R.layout.requests_spinner);
+ appBar.setCustomView(R.layout.spinner);
appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP);
// Initialize the resource array lists. A list is needed for all the resource requests, or the activity can crash if `MainWebViewActivity.resourceRequests` is modified after the activity loads.
spinnerCursor.addRow(new Object[]{4, getString(R.string.blocked_plural) + " - " + blockedResourceRequests.size()});
// Create a resource cursor adapter for the spinner.
- ResourceCursorAdapter spinnerCursorAdapter = new ResourceCursorAdapter(this, R.layout.requests_spinner_item, spinnerCursor, 0) {
+ ResourceCursorAdapter spinnerCursorAdapter = new ResourceCursorAdapter(this, R.layout.appbar_spinner_item, spinnerCursor, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Get a handle for the spinner item text view.
};
// Set the resource cursor adapter drop down view resource.
- spinnerCursorAdapter.setDropDownViewResource(R.layout.requests_spinner_dropdown_item);
+ spinnerCursorAdapter.setDropDownViewResource(R.layout.appbar_spinner_dropdown_item);
// Get a handle for the app bar spinner and set the adapter.
- Spinner appBarSpinner = findViewById(R.id.requests_spinner);
+ Spinner appBarSpinner = findViewById(R.id.spinner);
appBarSpinner.setAdapter(spinnerCursorAdapter);
// Handle clicks on the spinner dropdown.
assert getContext() != null;
// Create a `ResourceCursorAdapter` for the `Spinner`. `0` specifies no flags.;
- ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.edit_bookmark_databaseview_spinner_item, foldersMergeCursor, 0) {
+ ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.spinner_item, foldersMergeCursor, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Get a handle for the `Spinner` item `TextView`.
};
// Set the `ResourceCursorAdapter` drop drown view resource.
- foldersCursorAdapter.setDropDownViewResource(R.layout.edit_bookmark_databaseview_spinner_dropdown_item);
+ foldersCursorAdapter.setDropDownViewResource(R.layout.spinner_dropdown_items);
// Set the adapter for the folder `Spinner`.
folderSpinner.setAdapter(foldersCursorAdapter);
assert getContext() != null;
// Create a `ResourceCursorAdapter` for the `Spinner`. `0` specifies no flags.;
- ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.edit_bookmark_databaseview_spinner_item, foldersMergeCursor, 0) {
+ ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.spinner_item, foldersMergeCursor, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
// Get a handle for the `Spinner` item `TextView`.
};
// Set the `ResourceCursorAdapter` drop drown view resource.
- foldersCursorAdapter.setDropDownViewResource(R.layout.edit_bookmark_databaseview_spinner_dropdown_item);
+ foldersCursorAdapter.setDropDownViewResource(R.layout.spinner_dropdown_items);
// Set the adapter for the folder `Spinner`.
folderSpinner.setAdapter(foldersCursorAdapter);
import com.stoutner.privacybrowser.activities.MainWebViewActivity;
public class ImportExportStoragePermissionDialog extends DialogFragment {
- // The constants are used to differentiate between the two commands.
- public static final int EXPORT_SETTINGS = 1;
- public static final int IMPORT_SETTINGS = 2;
-
// The listener is used in `onAttach()` and `onCreateDialog()`.
private ImportExportStoragePermissionDialogListener importExportStoragePermissionDialogListener;
// The public interface is used to send information back to the parent activity.
public interface ImportExportStoragePermissionDialogListener {
- void onCloseImportExportStoragePermissionDialog(int type);
+ void onCloseImportExportStoragePermissionDialog();
}
@Override
importExportStoragePermissionDialogListener = (ImportExportStoragePermissionDialogListener) context;
}
- public static ImportExportStoragePermissionDialog type(int type) {
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
-
- // Store the download type in the bundle.
- argumentsBundle.putInt("type", type);
-
- // Add the arguments bundle to this instance of the dialog.
- ImportExportStoragePermissionDialog thisImportExportStoragePermissionDialog = new ImportExportStoragePermissionDialog();
- thisImportExportStoragePermissionDialog.setArguments(argumentsBundle);
- return thisImportExportStoragePermissionDialog;
- }
-
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Store the download type in a local variable.
- int type = getArguments().getInt("type");
-
// Use a builder to create the alert dialog.
AlertDialog.Builder dialogBuilder;
// Set an `onClick` listener on the negative button.
dialogBuilder.setNegativeButton(R.string.ok, (DialogInterface dialog, int which) -> {
// Inform the parent activity that the dialog was closed.
- importExportStoragePermissionDialogListener.onCloseImportExportStoragePermissionDialog(type);
+ importExportStoragePermissionDialogListener.onCloseImportExportStoragePermissionDialog();
});
// Create an alert dialog from the builder.
savedSslCertificateEndDate = new Date(domainCursor.getLong(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
}
- // Create `ArrayAdapters` for the `Spinners`and their `entry values`.
- ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.domain_settings_spinner_item);
- ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.domain_settings_spinner_item);
- ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.domain_settings_spinner_item);
- ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.domain_settings_spinner_item);
- ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.domain_settings_spinner_item);
- ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.domain_settings_spinner_item);
-
- // Set the `DropDownViewResource` on the `Spinners`.
+ // Create array adapters for the spinners.
+ ArrayAdapter<CharSequence> translatedUserAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.translated_domain_settings_user_agent_names, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> swipeToRefreshArrayAdapter = ArrayAdapter.createFromResource(context, R.array.swipe_to_refresh_array, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item);
+ ArrayAdapter<CharSequence> displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item);
+
+ // Set the drop down view resource on the spinners.
translatedUserAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
swipeToRefreshArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_items);
- // Set the `ArrayAdapters` for the `Spinners`.
+ // Set the array adapters for the spinners.
userAgentSpinner.setAdapter(translatedUserAgentArrayAdapter);
fontSizeSpinner.setAdapter(fontSizeArrayAdapter);
swipeToRefreshSpinner.setAdapter(swipeToRefreshArrayAdapter);
nightModeSpinner.setAdapter(nightModeArrayAdapter);
displayWebpageImagesSpinner.setAdapter(displayImagesArrayAdapter);
- // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
+ // Create a spannable string builder for each TextView that needs multiple colors of text.
SpannableStringBuilder savedSslCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + savedSslCertificateIssuedToCNameString);
SpannableStringBuilder savedSslCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedToONameString);
SpannableStringBuilder savedSslCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedToUNameString);
final String webViewDefaultUserAgentString = bareWebView.getSettings().getUserAgentString();
// Get a handle for the user agent array adapter. This array does not contain the `System default` entry.
- ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
+ ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
// Get the positions of the user agent and the default user agent.
int userAgentArrayPosition = userAgentNamesArray.getPosition(currentUserAgentName);
final WebView bareWebView = bareWebViewLayout.findViewById(R.id.bare_webview);
// Get the user agent arrays.
- ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.domain_settings_spinner_item);
+ ArrayAdapter<CharSequence> userAgentNamesArray = ArrayAdapter.createFromResource(context, R.array.user_agent_names, R.layout.spinner_item);
String[] translatedUserAgentNamesArray = getResources().getStringArray(R.array.translated_user_agent_names);
String[] userAgentDataArray = getResources().getStringArray(R.array.user_agent_data);
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- Highlight the selected item when the spinner is open. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_checked="true" android:color="@color/gray_300" />
+ <item android:color="@color/blue_300" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- Highlight the selected item when the spinner is open. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_checked="true" android:color="@color/white" />
+ <item android:color="@color/blue_100" />
+</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Highlight the selected item when the spinner is open. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="true" android:color="@color/gray_300" />
- <item android:color="@color/blue_300" />
-</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Highlight the selected item when the spinner is open. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="true" android:color="@color/white" />
- <item android:color="@color/blue_100" />
-</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true" android:color="@color/blue_600" />
+ <item android:color="@color/gray_750" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true" android:color="@color/blue_600" />
+ <item android:color="@color/gray_300" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true" android:color="@color/gray_300" />
+ <item android:color="@color/gray_500" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_enabled="true" android:color="@color/white" />
+ <item android:color="@color/gray_400" />
+</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Change the dark theme enabled text from white to gray. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="false" android:color="@color/gray_500" />
- <item android:color="@color/gray_300" />
-</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Change the dark theme enabled text from white to gray.-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="false" android:color="@color/gray_600" />
- <item android:color="@color/black" />
-</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Highlight the selected item when the spinner is open. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="true" android:color="@color/gray_300" />
- <item android:color="@color/blue_300" />
-</selector>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- Highlight the selected item when the spinner is open. -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_checked="true" android:color="@color/white" />
- <item android:color="@color/blue_100" />
-</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- Change the dark theme enabled text from white to gray. -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_checked="false" android:color="@color/gray_500" />
+ <item android:color="@color/gray_300" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- Change the dark theme enabled text from white to gray.-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item android:state_checked="false" android:color="@color/gray_600" />
+ <item android:color="@color/black" />
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- A checked text view allows the color of the text to be changed when it is selected (checked). -->
+<CheckedTextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner_item_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:textSize="18sp"
+ android:textColor="?attr/appbarSpinnerTextColorSelector"
+ android:background="?attr/spinnerBackground" />
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner_item_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:textSize="18sp"
+ android:textColor="?attr/spinnerHeaderTextColor" />
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<Spinner
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/bookmarks_databaseview_spinner"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- A checked text view allows the color of the text to be changed when it is selected (checked). -->
-<CheckedTextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:ellipsize="end"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textSize="18sp"
- android:textColor="?attr/bookmarksSpinnerTextColorSelector"
- android:background="?attr/bookmarksSpinnerBackground" />
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:ellipsize="end"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:textSize="18sp"
- android:textColor="?attr/bookmarksSpinnerHeaderTextColor" />
\ No newline at end of file
android:layout_marginEnd="36dp"
android:textSize="13sp" />
- <!-- `android:autofillHints` only applies to API >= 26. `tools:ignore="UnusedAttribute"` removes the lint warning. -->
<EditText
android:id="@+id/domain_settings_custom_user_agent_edittext"
android:layout_height="wrap_content"
android:layout_marginEnd="60dp"
android:inputType="textUri"
android:hint="@string/custom_user_agent"
- android:autofillHints=""
- tools:ignore="UnusedAttribute" />
+ android:importantForAutofill="no"
+ tools:targetApi="26" />
</LinearLayout>
<!-- Font Size. -->
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:ellipsize="end"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:textSize="18sp"
- android:textColor="?android:textColorPrimary" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
android:layout_marginEnd="4dp" >
<!-- `android:imeOptions="actionGo"` sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the `EditText`. -->
- <EditText
+ <android.support.design.widget.TextInputEditText
android:id="@+id/edit_bookmark_url_edittext"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:imeOptions="actionGo"
android:inputType="number"
- android:selectAllOnFocus="true" />
+ android:selectAllOnFocus="true"
+ android:importantForAutofill="no"
+ tools:targetApi="26" />
</LinearLayout>
</LinearLayout>
</ScrollView>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- A `CheckedTextView` allows the color of the text to be changed when it is selected (checked). -->
-<CheckedTextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:ellipsize="end"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textSize="18sp"
- android:textColor="?attr/editBookmarkSpinnerTextColorSelector" />
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:ellipsize="end"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:textSize="18sp"
- android:textColor="?android:textColorPrimary" />
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
android:layout_width="match_parent"
android:imeOptions="actionGo"
android:inputType="number"
- android:selectAllOnFocus="true" />
+ android:selectAllOnFocus="true"
+ android:importantForAutofill="no"
+ tools:targetApi="26" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:orientation="vertical" >
- <!-- The export card. -->
+ <!-- The encryption card. -->
<android.support.v7.widget.CardView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="6dp"
- android:text="@string/export_settings"
+ android:text="@string/encryption"
android:textSize="25sp"
android:textStyle="bold"
- android:textColor="?android:textColorPrimary" />
+ android:textColor="?colorAccent" />
- <!-- Align the export EditText and the select file button horizontally. -->
- <LinearLayout
+ <Spinner
+ android:id="@+id/encryption_spinner"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal" />
+
+ <!-- The encryption password. -->
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/password_encryption_textinputlayout"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:orientation="horizontal" >
+ app:passwordToggleEnabled="true" >
- <!-- `android.support.design.widget.TextInputLayout` makes the `android:hint` float above the `EditText`. -->
- <android.support.design.widget.TextInputLayout
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/password_encryption_edittext"
android:layout_height="wrap_content"
- android:layout_width="0dp"
- android:layout_weight="1" >
-
- <!-- `android:inputType="textUri" disables spell check and places an `/` on the main keyboard. -->
- <android.support.design.widget.TextInputEditText
- android:id="@+id/export_file_edittext"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:hint="@string/export_file_name"
- android:inputType="textMultiLine|textUri" />
- </android.support.design.widget.TextInputLayout>
-
- <Button
- android:id="@+id/select_export_file"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_vertical"
- android:text="@string/browse"
- android:onClick="exportBrowse" />
- </LinearLayout>
-
- <Button
- android:id="@+id/export_button"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_gravity="center_horizontal"
- android:text="@string/export"
- android:textSize="18sp"
- android:onClick="onClickExport" />
+ android:layout_width="match_parent"
+ android:hint="@string/password"
+ android:inputType="textPassword"/>
+ </android.support.design.widget.TextInputLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
- <!-- The import card. -->
+ <!-- The file location card. -->
<android.support.v7.widget.CardView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="5dp"
- android:layout_marginBottom="10dp"
+ android:layout_marginBottom="5dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" >
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="6dp"
- android:text="@string/import_settings"
+ android:text="@string/file_location"
android:textSize="25sp"
android:textStyle="bold"
- android:textColor="?android:textColorPrimary" />
+ android:textColor="?colorAccent" />
+
+ <Spinner
+ android:id="@+id/import_export_spinner"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center_horizontal" />
- <!-- Align the import EditText and the select file button horizontally. -->
+ <!-- Align the EditText and the select file button horizontally. -->
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:layout_marginTop="10dp">
<!-- `android.support.design.widget.TextInputLayout` makes the `android:hint` float above the `EditText`. -->
<android.support.design.widget.TextInputLayout
<!-- `android:inputType="textUri" disables spell check and places an `/` on the main keyboard. -->
<android.support.design.widget.TextInputEditText
- android:id="@+id/import_file_edittext"
+ android:id="@+id/file_name_edittext"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:hint="@string/import_file_name"
+ android:hint="@string/file_name"
android:inputType="textMultiLine|textUri" />
</android.support.design.widget.TextInputLayout>
<Button
- android:id="@+id/select_import_file"
+ android:id="@+id/browser_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/browse"
- android:onClick="importBrowse" />
+ android:onClick="browse" />
</LinearLayout>
- <!-- `import` is a reserved word and cannot be used for the `onClick` name. -->
<Button
- android:id="@+id/import_button"
+ android:id="@+id/import_export_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/import_button"
android:textSize="18sp"
- android:onClick="onClickImport" />
+ android:onClick="importExport"
+ app:backgroundTint="?attr/buttonBackgroundColorSelector"
+ android:textColor="?attr/buttonTextColorSelector" />
</LinearLayout>
</android.support.v7.widget.CardView>
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<Spinner
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/requests_spinner"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<!-- A checked text view allows the color of the text to be changed when it is selected (checked). -->
-<CheckedTextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:paddingStart="20dp"
- android:paddingEnd="20dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:textSize="18sp"
- android:textColor="?attr/requestsSpinnerTextColorSelector"
- android:background="?attr/requestsSpinnerBackground" />
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spinner_item_textview"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:maxLines="1"
- android:paddingStart="10dp"
- android:paddingEnd="10dp"
- android:textSize="18sp"
- android:textColor="?attr/requestsSpinnerHeaderTextColor" />
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<Spinner
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- A `CheckedTextView` allows the color of the text to be changed when it is selected (checked). -->
+<CheckedTextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner_item_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:paddingStart="20dp"
+ android:paddingEnd="20dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:textSize="18sp"
+ android:textColor="?attr/spinnerTextColorSelector" />
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/spinner_item_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:maxLines="1"
+ android:ellipsize="end"
+ android:paddingStart="10dp"
+ android:paddingEnd="10dp"
+ android:textSize="18sp"
+ android:textColor="?android:textColorPrimary" />
\ No newline at end of file
<string name="load_an_encrypted_website">Cargar una página web cifrada antes de abrir la configuración de dominio para rellenar el certificado SSL de la página web actual.</string>
<!-- Import/Export. -->
+ <string-array name="import_export_spinner">
+ <item>Importar</item>
+ <item>Exportar</item>
+ </string-array>
<string name="browse">Navegar</string>
- <string name="export_settings">Exportar los ajustes</string>
- <string name="import_settings">Importar los ajustes</string>
- <string name="export_file_name">Nombre de archivo a exportar</string>
- <string name="import_file_name">Nombre de archivo a importar</string>
<string name="export">Exportar</string>
<string name="import_button">Importar</string> <!-- `import` is a reserved word and cannot be used as the name -->
<string name="export_successful">Exportación exitosa.</string>
<string name="load_an_encrypted_website">Carica un sito Web criptato prima di aprire le impostazioni dei domini per popolare il certificato SSL del sito attuale.</string>
<!-- Import/Export. -->
+ <string-array name="import_export_spinner">
+ <item>Importa</item>
+ <item>Esporta</item>
+ </string-array>
<string name="browse">Sfoglia</string>
- <string name="export_settings">Esporta Impostazioni</string>
- <string name="import_settings">Importa Impostazioni</string>
- <string name="export_file_name">Nome del file di esportazione</string>
- <string name="import_file_name">Nome del file di importazione</string>
<string name="export">Esporta</string>
<string name="import_button">Importa</string> <!-- `import` is a reserved word and cannot be used as the name -->
<string name="export_successful">Esportazione riuscita</string>
<string name="load_an_encrypted_website">Откройте зашифрованный сайт перед настройкой домена, чтобы заполнить текущий сертификат SSL веб-сайта.</string>
<!-- Import/Export. -->
+ <string-array name="import_export_spinner">
+ <item>Импорт</item>
+ <item>Экспорт</item>
+ </string-array>
<string name="browse">Обзор</string>
- <string name="export_settings">Экспорт настроек</string>
- <string name="import_settings">Импорт настроек</string>
- <string name="export_file_name">Имя файла экспорта</string>
- <string name="import_file_name">Имя файла импорта</string>
<string name="export">Экспорт</string>
<string name="import_button">Импорт</string> <!-- `import` is a reserved word and cannot be used as the name -->
<string name="export_successful">Экспорт выполнен.</string>
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2015-2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<item name="android:statusBarColor">@color/blue_900</item>
<item name="android:textColorHighlight">@color/blue_200</item>
<item name="android:actionModeBackground">@color/blue_700</item>
- <item name="bookmarksSpinnerHeaderTextColor">@color/white</item>
- <item name="bookmarksSpinnerTextColorSelector">@color/bookmarks_spinner_color_selector_light</item>
- <item name="bookmarksSpinnerBackground">@color/blue_750</item>
- <item name="editBookmarkSpinnerTextColorSelector">@color/edit_bookmark_spinner_color_selector_light</item>
- <item name="requestsSpinnerHeaderTextColor">@color/white</item>
- <item name="requestsSpinnerTextColorSelector">@color/requests_spinner_color_selector_light</item>
- <item name="requestsSpinnerBackground">@color/blue_750</item>
+ <item name="spinnerHeaderTextColor">@color/white</item>
+ <item name="spinnerBackground">@color/blue_750</item>
+ <item name="spinnerTextColorSelector">@color/spinner_color_selector_light</item>
+ <item name="appbarSpinnerTextColorSelector">@color/appbar_spinner_color_selector_light</item>
+ <item name="buttonBackgroundColorSelector">@color/button_background_color_selector_light</item>
+ <item name="buttonTextColorSelector">@color/button_text_color_selector_light</item>
<item name="listSelectorDrawable">@drawable/list_selector_light</item>
<item name="aboutTitle">@color/blue_900</item>
<item name="aboutText">@color/blue_700</item>
<item name="colorPrimaryDark">@color/blue_800</item>
<item name="android:statusBarColor">@color/blue_900</item>
<item name="android:actionModeBackground">@color/blue_800</item>
- <item name="bookmarksSpinnerHeaderTextColor">@color/gray_300</item>
- <item name="bookmarksSpinnerTextColorSelector">@color/bookmarks_spinner_color_selector_dark</item>
- <item name="bookmarksSpinnerBackground">@color/blue_830</item>
- <item name="editBookmarkSpinnerTextColorSelector">@color/edit_bookmark_spinner_color_selector_dark</item>
- <item name="requestsSpinnerHeaderTextColor">@color/gray_300</item>
- <item name="requestsSpinnerTextColorSelector">@color/requests_spinner_color_selector_dark</item>
- <item name="requestsSpinnerBackground">@color/blue_830</item>
+ <item name="spinnerHeaderTextColor">@color/gray_300</item>
+ <item name="spinnerBackground">@color/blue_830</item>
+ <item name="spinnerTextColorSelector">@color/spinner_color_selector_dark</item>
+ <item name="appbarSpinnerTextColorSelector">@color/appbar_spinner_color_selector_dark</item>
+ <item name="buttonTextColorSelector">@color/button_text_color_selector_dark</item>
+ <item name="buttonBackgroundColorSelector">@color/button_background_color_selector_dark</item>
<item name="aboutTitle">@color/blue_600</item>
<item name="aboutText">@color/blue_400</item>
<item name="aboutBackground">@color/gray_850</item>
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<attr name="sslTitle" format="reference" />
<attr name="sslHeader" format="reference" />
<attr name="urlHistoryText" format="reference" />
- <attr name="bookmarksSpinnerHeaderTextColor" format="reference" />
- <attr name="bookmarksSpinnerTextColorSelector" format="reference" />
- <attr name="bookmarksSpinnerBackground" format="reference" />
- <attr name="requestsSpinnerHeaderTextColor" format="reference" />
- <attr name="requestsSpinnerTextColorSelector" format="reference" />
- <attr name="requestsSpinnerBackground" format="reference" />
- <attr name="editBookmarkSpinnerTextColorSelector" format="reference" />
+ <attr name="spinnerHeaderTextColor" format="reference" />
+ <attr name="spinnerBackground" format="reference" />
+ <attr name="spinnerTextColorSelector" format="reference" />
+ <attr name="appbarSpinnerTextColorSelector" format="reference" />
+ <attr name="buttonTextColorSelector" format="reference" />
+ <attr name="buttonBackgroundColorSelector" format="reference" />
<attr name="redText" format="reference" />
<attr name="navigationHeaderBackground" format="reference" />
<color name="gray_500">#FF9E9E9E</color>
<color name="gray_600">#FF757575</color>
<color name="gray_700">#FF616161</color>
+ <color name="gray_750">#FF515151</color>
<color name="gray_800">#FF424242</color>
<color name="gray_850">#FF313131</color>
<color name="gray_900">#FF212121</color>
<string name="load_an_encrypted_website">Load an encrypted website before opening Domain Settings to populate the current website SSL certificate.</string>
<!-- Import/Export. -->
+ <string name="encryption">Encryption</string>
+ <string-array name="encryption_type">
+ <item>None</item>
+ <item>Password</item>
+ <item>GPG</item>
+ </string-array>
+ <string name="file_location">File Location</string>
+ <string-array name="import_export_spinner">
+ <item>Import</item>
+ <item>Export</item>
+ </string-array>
<string name="browse">Browse</string>
- <string name="export_settings">Export Settings</string>
- <string name="import_settings">Import Settings</string>
- <string name="export_file_name">Export file name</string>
- <string name="import_file_name">Import file name</string>
<string name="export">Export</string>
<string name="import_button">Import</string> <!-- `import` is a reserved word and cannot be used as the name -->
<string name="export_successful">Export successful.</string>
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2015-2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<item name="colorPrimaryDark">@color/blue_700</item>
<item name="android:textColorHighlight">@color/blue_200</item>
<item name="android:actionModeBackground">@color/blue_700</item>
- <item name="bookmarksSpinnerHeaderTextColor">@color/white</item>
- <item name="bookmarksSpinnerTextColorSelector">@color/bookmarks_spinner_color_selector_light</item>
- <item name="bookmarksSpinnerBackground">@color/blue_750</item>
- <item name="editBookmarkSpinnerTextColorSelector">@color/edit_bookmark_spinner_color_selector_light</item>
- <item name="requestsSpinnerHeaderTextColor">@color/white</item>
- <item name="requestsSpinnerTextColorSelector">@color/requests_spinner_color_selector_light</item>
- <item name="requestsSpinnerBackground">@color/blue_750</item>
+ <item name="spinnerHeaderTextColor">@color/white</item>
+ <item name="spinnerBackground">@color/blue_750</item>
+ <item name="spinnerTextColorSelector">@color/spinner_color_selector_light</item>
+ <item name="appbarSpinnerTextColorSelector">@color/appbar_spinner_color_selector_light</item>
+ <item name="buttonTextColorSelector">@color/button_text_color_selector_light</item>
+ <item name="buttonBackgroundColorSelector">@color/button_background_color_selector_light</item>
<item name="listSelectorDrawable">@drawable/list_selector_light</item>
<item name="aboutTitle">@color/blue_900</item>
<item name="aboutText">@color/blue_700</item>
<item name="windowActionModeOverlay">true</item>
<item name="colorPrimaryDark">@color/blue_900</item>
<item name="android:actionModeBackground">@color/blue_800</item>
- <item name="bookmarksSpinnerHeaderTextColor">@color/gray_300</item>
- <item name="bookmarksSpinnerTextColorSelector">@color/bookmarks_spinner_color_selector_dark</item>
- <item name="bookmarksSpinnerBackground">@color/blue_830</item>
- <item name="editBookmarkSpinnerTextColorSelector">@color/edit_bookmark_spinner_color_selector_dark</item>
- <item name="requestsSpinnerHeaderTextColor">@color/gray_300</item>
- <item name="requestsSpinnerTextColorSelector">@color/requests_spinner_color_selector_dark</item>
- <item name="requestsSpinnerBackground">@color/blue_830</item>
+ <item name="spinnerHeaderTextColor">@color/gray_300</item>
+ <item name="spinnerBackground">@color/blue_830</item>
+ <item name="spinnerTextColorSelector">@color/spinner_color_selector_dark</item>
+ <item name="appbarSpinnerTextColorSelector">@color/appbar_spinner_color_selector_dark</item>
+ <item name="buttonTextColorSelector">@color/button_text_color_selector_dark</item>
+ <item name="buttonBackgroundColorSelector">@color/button_background_color_selector_dark</item>
<item name="aboutTitle">@color/blue_600</item>
<item name="aboutText">@color/blue_400</item>
<item name="aboutBackground">@color/gray_850</item>