Add password encrypted export.
authorSoren Stoutner <soren@stoutner.com>
Tue, 20 Nov 2018 19:02:39 +0000 (12:02 -0700)
committerSoren Stoutner <soren@stoutner.com>
Tue, 20 Nov 2018 19:02:39 +0000 (12:02 -0700)
58 files changed:
.idea/dictionaries/soren.xml
app/src/main/assets/it/guide_bookmarks_dark.html
app/src/main/assets/it/guide_bookmarks_light.html
app/src/main/assets/it/guide_javascript_dark.html
app/src/main/assets/it/guide_javascript_light.html
app/src/main/assets/it/guide_local_storage_dark.html
app/src/main/assets/it/guide_local_storage_light.html
app/src/main/assets/ru/guide_bookmarks_dark.html
app/src/main/assets/ru/guide_bookmarks_light.html
app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/RequestsActivity.java
app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java
app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java
app/src/main/java/com/stoutner/privacybrowser/dialogs/ImportExportStoragePermissionDialog.java
app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java
app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
app/src/main/res/color/appbar_spinner_color_selector_dark.xml [new file with mode: 0644]
app/src/main/res/color/appbar_spinner_color_selector_light.xml [new file with mode: 0644]
app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml [deleted file]
app/src/main/res/color/bookmarks_spinner_color_selector_light.xml [deleted file]
app/src/main/res/color/button_background_color_selector_dark.xml [new file with mode: 0644]
app/src/main/res/color/button_background_color_selector_light.xml [new file with mode: 0644]
app/src/main/res/color/button_text_color_selector_dark.xml [new file with mode: 0644]
app/src/main/res/color/button_text_color_selector_light.xml [new file with mode: 0644]
app/src/main/res/color/edit_bookmark_spinner_color_selector_dark.xml [deleted file]
app/src/main/res/color/edit_bookmark_spinner_color_selector_light.xml [deleted file]
app/src/main/res/color/requests_spinner_color_selector_dark.xml [deleted file]
app/src/main/res/color/requests_spinner_color_selector_light.xml [deleted file]
app/src/main/res/color/spinner_color_selector_dark.xml [new file with mode: 0644]
app/src/main/res/color/spinner_color_selector_light.xml [new file with mode: 0644]
app/src/main/res/layout/appbar_spinner_dropdown_item.xml [new file with mode: 0644]
app/src/main/res/layout/appbar_spinner_item.xml [new file with mode: 0644]
app/src/main/res/layout/bookmarks_databaseview_spinner.xml [deleted file]
app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml [deleted file]
app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml [deleted file]
app/src/main/res/layout/domain_settings_fragment.xml
app/src/main/res/layout/domain_settings_spinner_item.xml [deleted file]
app/src/main/res/layout/edit_bookmark_databaseview_dialog.xml
app/src/main/res/layout/edit_bookmark_databaseview_spinner_dropdown_item.xml [deleted file]
app/src/main/res/layout/edit_bookmark_databaseview_spinner_item.xml [deleted file]
app/src/main/res/layout/edit_bookmark_folder_databaseview_dialog.xml
app/src/main/res/layout/import_export_coordinatorlayout.xml
app/src/main/res/layout/requests_spinner.xml [deleted file]
app/src/main/res/layout/requests_spinner_dropdown_item.xml [deleted file]
app/src/main/res/layout/requests_spinner_item.xml [deleted file]
app/src/main/res/layout/spinner.xml [new file with mode: 0644]
app/src/main/res/layout/spinner_dropdown_items.xml [new file with mode: 0644]
app/src/main/res/layout/spinner_item.xml [new file with mode: 0644]
app/src/main/res/values-es/strings.xml
app/src/main/res/values-it/strings.xml
app/src/main/res/values-ru/strings.xml
app/src/main/res/values-v21/styles.xml
app/src/main/res/values/attrs.xml
app/src/main/res/values/colors.xml
app/src/main/res/values/strings.xml
app/src/main/res/values/styles.xml

index 55f7313912a20f341f1c5641e74c4ffc8efdae1a..c96e514b485384f8a788e9de8e9167d47d2e3b99 100644 (file)
@@ -30,6 +30,7 @@
       <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>
index 9604beb0ee9cbb66e1b30581f0e7165d3dd4d3f4..1aa6f346ea32fd94ad23336846853e1a0b580579 100644 (file)
@@ -32,8 +32,8 @@
 
         <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
index 4bd767a7fec233021af8bf81cc7a07de4dc31a94..29ed4dfd34d1796bacd04447b9ec610e97817d69 100644 (file)
@@ -32,8 +32,8 @@
 
         <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
index ababdeed6772a4296abddd9b4c571105c3c953eb..bc31859b414d383747e61b80f57fa2143be97baf 100644 (file)
@@ -53,8 +53,9 @@
             <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
index 2191caf3d1c58e38a85b65f25190980e1d4a2267..af9b8d9b251e5611190e33deaa59fd1ee610eca1 100644 (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
index 320b24a57b7f519689b2eed1df542dc8495f27c5..85dc0835d0cd2be4aa8255381de5c37c392532d0 100644 (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
index 9c7859e14740d47121a63a7d02fdfcd543d4d132..a8d9107847563e72ab0c9aaa747c450c88c49b20 100644 (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
index 51adecafb2f15a05906791092dad9a744a3518a3..5ace1b6d750580214256a71fff928453212f8e58 100644 (file)
@@ -30,8 +30,7 @@
 
         <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
index 9e3823461cef23e08ef181045208bec4a4c97763..3637b3fc1238194d5382c99d907df64ef2abac2b 100644 (file)
@@ -30,8 +30,7 @@
 
         <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
index 620715acd7d2741e6ad8c567d037ace6d6257a8c..d8a58972990dfcfa6169353f2942b56f10c3eeaf 100644 (file)
@@ -109,7 +109,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements
         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`.
@@ -128,7 +128,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements
         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.
@@ -140,10 +140,10 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements
         };
 
         // 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.
index 26f2e1bc11bd4858cdc0c88bf88fd13eb294b093..14f5789fe3a9b7fbfe3a8d0fc59f42bd8be71ba0 100644 (file)
@@ -31,6 +31,7 @@ import android.os.Environment;
 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;
@@ -40,8 +41,11 @@ import android.text.Editable;
 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;
@@ -49,12 +53,27 @@ import com.stoutner.privacybrowser.dialogs.ImportExportStoragePermissionDialog;
 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) {
@@ -86,18 +105,116 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
         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.
@@ -110,12 +227,13 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
 
             @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.
@@ -128,66 +246,95 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
 
             @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);
@@ -198,82 +345,61 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
             // 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();
             }
         }
     }
@@ -282,199 +408,326 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
     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.
@@ -491,7 +744,7 @@ public class ImportExportActivity extends AppCompatActivity implements ImportExp
             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
index 5e4a21d9b6200a6508511889831b93868b9bec1c..d3f0d016b281676db475fdff9d8035b669e39649 100644 (file)
@@ -1247,7 +1247,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         }
 
         // 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.
index a62708a3f70d144ba076192ee26147043f495aca..71ce3070ab557d01f92f037b3f7d493de3df9539 100644 (file)
@@ -79,7 +79,7 @@ public class RequestsActivity extends AppCompatActivity implements ViewRequestDi
         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.
@@ -137,7 +137,7 @@ public class RequestsActivity extends AppCompatActivity implements ViewRequestDi
         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.
@@ -149,10 +149,10 @@ public class RequestsActivity extends AppCompatActivity implements ViewRequestDi
         };
 
         // 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.
index e24c893bd5c4877818f2109fe6aafcf3b384e72f..272e471956633e0a4b0605daf07e4b369e6c8f83 100644 (file)
@@ -216,7 +216,7 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment {
         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`.
@@ -228,7 +228,7 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment {
         };
 
         // 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);
index 0fb537b8eb2a05b9dd411e8c59a2ff5be32d238f..c2d44cd0baeee147acc33916f728b0eea5e1c413 100644 (file)
@@ -219,7 +219,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen
         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`.
@@ -231,7 +231,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen
         };
 
         // 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);
index d5b93900fb2cc796c463309457665963826aef42..447b67e6815f319d0c9fc3914c22fe8cbf67a0a1 100644 (file)
@@ -31,16 +31,12 @@ import com.stoutner.privacybrowser.R;
 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
@@ -52,24 +48,8 @@ public class ImportExportStoragePermissionDialog extends DialogFragment {
         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;
 
@@ -91,7 +71,7 @@ public class ImportExportStoragePermissionDialog extends DialogFragment {
         // 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.
index bfa6da74d87e3b866aeed83b10334633ab1777d3..76dacba62a4edb4634e2de011e6ca7baedb11725 100644 (file)
@@ -218,29 +218,29 @@ public class DomainSettingsFragment extends Fragment {
             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);
@@ -648,7 +648,7 @@ public class DomainSettingsFragment extends Fragment {
         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);
index 7966ef7bdc15b1b8c8efde958bd98efc2c73a885..65b18bae6e6604c7360ad998de0b68f436cc6a4f 100644 (file)
@@ -141,7 +141,7 @@ public class SettingsFragment extends PreferenceFragment {
         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);
 
diff --git a/app/src/main/res/color/appbar_spinner_color_selector_dark.xml b/app/src/main/res/color/appbar_spinner_color_selector_dark.xml
new file mode 100644 (file)
index 0000000..f58c783
--- /dev/null
@@ -0,0 +1,25 @@
+<?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
diff --git a/app/src/main/res/color/appbar_spinner_color_selector_light.xml b/app/src/main/res/color/appbar_spinner_color_selector_light.xml
new file mode 100644 (file)
index 0000000..03ac9ea
--- /dev/null
@@ -0,0 +1,25 @@
+<?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
diff --git a/app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml b/app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml
deleted file mode 100644 (file)
index bec0b3a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/bookmarks_spinner_color_selector_light.xml b/app/src/main/res/color/bookmarks_spinner_color_selector_light.xml
deleted file mode 100644 (file)
index 3e8f830..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/button_background_color_selector_dark.xml b/app/src/main/res/color/button_background_color_selector_dark.xml
new file mode 100644 (file)
index 0000000..85b0423
--- /dev/null
@@ -0,0 +1,24 @@
+<?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
diff --git a/app/src/main/res/color/button_background_color_selector_light.xml b/app/src/main/res/color/button_background_color_selector_light.xml
new file mode 100644 (file)
index 0000000..8049c09
--- /dev/null
@@ -0,0 +1,24 @@
+<?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
diff --git a/app/src/main/res/color/button_text_color_selector_dark.xml b/app/src/main/res/color/button_text_color_selector_dark.xml
new file mode 100644 (file)
index 0000000..090ae06
--- /dev/null
@@ -0,0 +1,24 @@
+<?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
diff --git a/app/src/main/res/color/button_text_color_selector_light.xml b/app/src/main/res/color/button_text_color_selector_light.xml
new file mode 100644 (file)
index 0000000..74c6c5b
--- /dev/null
@@ -0,0 +1,24 @@
+<?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
diff --git a/app/src/main/res/color/edit_bookmark_spinner_color_selector_dark.xml b/app/src/main/res/color/edit_bookmark_spinner_color_selector_dark.xml
deleted file mode 100644 (file)
index 5175182..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/edit_bookmark_spinner_color_selector_light.xml b/app/src/main/res/color/edit_bookmark_spinner_color_selector_light.xml
deleted file mode 100644 (file)
index ef42d28..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/requests_spinner_color_selector_dark.xml b/app/src/main/res/color/requests_spinner_color_selector_dark.xml
deleted file mode 100644 (file)
index 06e0fa4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/requests_spinner_color_selector_light.xml b/app/src/main/res/color/requests_spinner_color_selector_light.xml
deleted file mode 100644 (file)
index 3e8f830..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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
diff --git a/app/src/main/res/color/spinner_color_selector_dark.xml b/app/src/main/res/color/spinner_color_selector_dark.xml
new file mode 100644 (file)
index 0000000..0a683db
--- /dev/null
@@ -0,0 +1,25 @@
+<?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
diff --git a/app/src/main/res/color/spinner_color_selector_light.xml b/app/src/main/res/color/spinner_color_selector_light.xml
new file mode 100644 (file)
index 0000000..8920423
--- /dev/null
@@ -0,0 +1,25 @@
+<?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
diff --git a/app/src/main/res/layout/appbar_spinner_dropdown_item.xml b/app/src/main/res/layout/appbar_spinner_dropdown_item.xml
new file mode 100644 (file)
index 0000000..d71b180
--- /dev/null
@@ -0,0 +1,35 @@
+<?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
diff --git a/app/src/main/res/layout/appbar_spinner_item.xml b/app/src/main/res/layout/appbar_spinner_item.xml
new file mode 100644 (file)
index 0000000..3e7cc3c
--- /dev/null
@@ -0,0 +1,31 @@
+<?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
diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner.xml
deleted file mode 100644 (file)
index 9750d59..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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" />
diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml
deleted file mode 100644 (file)
index 57860ee..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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
diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml
deleted file mode 100644 (file)
index 62cbb1d..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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
index d71868b2c9076e3d3f8c7e03d5a3d971e8c346ef..df08c91c19b9807ec357325383b1caba7167eca4 100644 (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. -->
diff --git a/app/src/main/res/layout/domain_settings_spinner_item.xml b/app/src/main/res/layout/domain_settings_spinner_item.xml
deleted file mode 100644 (file)
index 0896cff..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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
index fa7ee1de0d030cef51062c6535186003a463b521..f690f9c82640c7c133d716ea0644efc69c116f03 100644 (file)
@@ -1,7 +1,7 @@
 <?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>.
 
@@ -20,6 +20,7 @@
 
 <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
diff --git a/app/src/main/res/layout/edit_bookmark_databaseview_spinner_dropdown_item.xml b/app/src/main/res/layout/edit_bookmark_databaseview_spinner_dropdown_item.xml
deleted file mode 100644 (file)
index af46e36..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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
diff --git a/app/src/main/res/layout/edit_bookmark_databaseview_spinner_item.xml b/app/src/main/res/layout/edit_bookmark_databaseview_spinner_item.xml
deleted file mode 100644 (file)
index 0896cff..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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
index 6ea35eeba0fddbd1ee46e26812147702bcff1b59..4b9cec3d90dd79dd791db6fc0372f31e9ea63575 100644 (file)
@@ -1,7 +1,7 @@
 <?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>.
 
@@ -20,6 +20,7 @@
 
 <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
index 3ecc1aec9d99b589b1aab0652998028ba8164f7c..f3c7cefeb4b2cf9a2b81309f9e2cd87336ab19ef 100644 (file)
@@ -58,7 +58,7 @@
                 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>
 
diff --git a/app/src/main/res/layout/requests_spinner.xml b/app/src/main/res/layout/requests_spinner.xml
deleted file mode 100644 (file)
index 517f854..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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" />
diff --git a/app/src/main/res/layout/requests_spinner_dropdown_item.xml b/app/src/main/res/layout/requests_spinner_dropdown_item.xml
deleted file mode 100644 (file)
index eb6771b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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
diff --git a/app/src/main/res/layout/requests_spinner_item.xml b/app/src/main/res/layout/requests_spinner_item.xml
deleted file mode 100644 (file)
index 085c2a2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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
diff --git a/app/src/main/res/layout/spinner.xml b/app/src/main/res/layout/spinner.xml
new file mode 100644 (file)
index 0000000..5c92c65
--- /dev/null
@@ -0,0 +1,25 @@
+<?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" />
diff --git a/app/src/main/res/layout/spinner_dropdown_items.xml b/app/src/main/res/layout/spinner_dropdown_items.xml
new file mode 100644 (file)
index 0000000..7105179
--- /dev/null
@@ -0,0 +1,34 @@
+<?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
diff --git a/app/src/main/res/layout/spinner_item.xml b/app/src/main/res/layout/spinner_item.xml
new file mode 100644 (file)
index 0000000..5bc6f82
--- /dev/null
@@ -0,0 +1,31 @@
+<?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
index 533c70f237a86170a92e6f2cf2fd10c4a9df220f..1ccd90a48df4f4b1cc32678a3b497df2c52d2d93 100644 (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>
index 22393f876ea34d924e0388dd73bc9d0783ae6da8..028fb372f951e4c26b6c22e52f772317cc138289 100644 (file)
     <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>
index 17b40a540465890da3a13a018770820b51fa9434..a9025b1ca19b874ab718f93667284643edd3933e 100644 (file)
     <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>
index 6854a1060c88a27445e555fbaf4d4b4df2a5b1e7..26ea9349da21aa6ca6bef4e4d0dbf8e37a51b7f8 100644 (file)
@@ -1,7 +1,7 @@
 <?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>
index c04bceb587bfbf1c33a46a5819266d6a2276838e..c2b97dfb7ffed9aa136e9d4f788539013308e615 100644 (file)
@@ -1,7 +1,7 @@
 <?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" />
index d2ce68b7ceef94597bdfcc28bf53f0fec7ba252b..2d4448e12fb68b737fe98763ca552dced3ea601f 100644 (file)
@@ -57,6 +57,7 @@
     <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>
index 3c09f50ab88956e86d145c0e5991ebcb94e3e8f7..ad2c49c982ad1264450e7094bd5193d5e3d20c52 100644 (file)
     <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>
index da59ae58982a03afca027c10bd300f74e5e2555e..406dc52f615487b4ae0cd3a159bed7bd52e1c877 100644 (file)
@@ -1,7 +1,7 @@
 <?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>