Add a View Source activity. https://redmine.stoutner.com/issues/64
authorSoren Stoutner <soren@stoutner.com>
Wed, 10 Jan 2018 19:52:12 +0000 (12:52 -0700)
committerSoren Stoutner <soren@stoutner.com>
Wed, 10 Jan 2018 19:52:12 +0000 (12:52 -0700)
34 files changed:
.idea/dictionaries/soren.xml
COPYING
app/build.gradle
app/src/main/AndroidManifest.xml
app/src/main/assets/de/about_licenses_dark.html
app/src/main/assets/de/about_licenses_light.html
app/src/main/assets/en/about_licenses_dark.html
app/src/main/assets/en/about_licenses_light.html
app/src/main/assets/es/about_licenses_dark.html
app/src/main/assets/es/about_licenses_light.html
app/src/main/assets/it/about_licenses_dark.html
app/src/main/assets/it/about_licenses_light.html
app/src/main/java/com/stoutner/privacybrowser/activities/AboutActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java [new file with mode: 0644]
app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java
app/src/main/res/drawable/about.xml [deleted file]
app/src/main/res/drawable/about_dark.xml [new file with mode: 0644]
app/src/main/res/drawable/about_light.xml [new file with mode: 0644]
app/src/main/res/layout/domain_settings_fragment.xml
app/src/main/res/layout/main_drawerlayout.xml
app/src/main/res/layout/url_app_bar.xml
app/src/main/res/layout/view_source_app_bar.xml [new file with mode: 0644]
app/src/main/res/layout/view_source_coordinatorlayout.xml [new file with mode: 0644]
app/src/main/res/menu/bookmarks_options_menu.xml
app/src/main/res/menu/view_source_options_menu.xml [new file with mode: 0644]
app/src/main/res/menu/webview_navigation_menu.xml
app/src/main/res/menu/webview_options_menu.xml
app/src/main/res/values/attrs.xml
app/src/main/res/values/strings.xml
app/src/main/res/values/styles.xml
fastlane/metadata/android/en/images/phoneScreenshots/02-Full Screen-TranslucentBars.png [deleted file]
fastlane/metadata/android/en/images/phoneScreenshots/02-FullScreen-TranslucentBars.png [new file with mode: 0644]

index c6d78c7ebecb037bedfffbe14df270acbd8ebde0..b34ca1a2d4920a40c65934a2ab70e68eb8070a9f 100644 (file)
@@ -9,6 +9,7 @@
       <w>amoled</w>
       <w>androidversion</w>
       <w>anonymized</w>
+      <w>apng</w>
       <w>appbarlayout</w>
       <w>aren</w>
       <w>autoselected</w>
diff --git a/COPYING b/COPYING
index 94bb603c44f9f95124cd11297d1c6755f975c4c5..a0d349734776adf7489014e99f28a65deea7918f 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Privacy Browser copyright © 2015-2017 Soren Stoutner <soren@stoutner.com>.
+Privacy Browser copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>.
 
 This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
 
index 7525567505167d439cdf740fd883f802fb9c1662..8644364d5981838f81f4708b0967a2f20f65db11 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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>.
  *
@@ -67,7 +67,7 @@ dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
     implementation 'com.android.support:design:26.1.0'
     // Only compile `com.google.firebase:firebase-ads` for the free flavor.
-    freeImplementation 'com.google.firebase:firebase-ads:11.6.2'
+    freeImplementation 'com.google.firebase:firebase-ads:11.8.0'
 }
 
 // Google's documentation says the following line is required for `firebase-ads` but things work correctly without it.  I have no interest in applying the Google Mobile Services plugin in the standard flavor if I don't have to.
index ad0e530561914f5a3bf61d1b07bb8b5b4fd20dde..9f260e6e11d2c269362c3679b1a498fc2078bd71 100644 (file)
             android:screenOrientation="fullUser"
             android:persistableMode="persistNever"
             tools:ignore="UnusedAttribute" />
+
+        <!-- `android:configChanges="orientation|screenSize"` makes the activity not reload when the orientation changes.
+             `android:persistableMode="persistNever"` removes Privacy Browser from the recents screen on a device reboot.
+             `tools:ignore="unusedAttribute"` removes the lint warning that `persistableMode` does not apply to API < 21. -->
+        <activity
+            android:name=".activities.ViewSourceActivity"
+            android:label="@string/view_source"
+            android:parentActivityName=".activities.MainWebViewActivity"
+            android:configChanges="orientation|screenSize"
+            android:screenOrientation="fullUser"
+            android:persistableMode="persistNever"
+            tools:ignore="UnusedAttribute" />
     </application>
 </manifest>
index 9e15f881aa8ea804c17fdb0f42283a2371d25203..3565a5121f1d4a156bd848c3a8c5a296f1bdb26a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-  Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
 
   Translation 2016 Aaron Gerlach <aaron@gerlach.com>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
@@ -30,7 +30,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser ist copyright © 2015-2017 von <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser ist copyright © 2015-2018 von <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Lizenz</h3>
         <p>Privacy Browser ist veröffentlicht unter der <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ Lizenz</a>. The full text of the license is below.
@@ -39,6 +39,8 @@
         <h3>Attribute</h3>
         <p>The list of ad servers used by the ad blocker comes from <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Because a list of domain names is a list of facts, it <a href="https://www.copyright.gov/help/faq/faq-protect.html">cannot be copyrighted</a>.</p>
+        <p>Privacy Browser is built with the <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            which is released under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             are derived from ic_security and ic_language, which are part of the <a href="https://material.io/icons/">Android Material icon set</a> and are released under the <a href ="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.
             The full text of the license is below. Modifications copyright © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>. The resulting images are released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>.</p>
index 8d8851f8154fa70715fb059a208bda4303a30f91..00f0acb98b5a53b5b71015e0ca283153b7673f3a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-  Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
 
   Translation 2016 Aaron Gerlach <aaron@gerlach.com>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
@@ -30,7 +30,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser ist copyright © 2015-2017 von <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser ist copyright © 2015-2018 von <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Lizenz</h3>
         <p>Privacy Browser ist veröffentlicht unter der <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ Lizenz</a>. The full text of the license is below.
@@ -39,6 +39,8 @@
         <h3>Attribute</h3>
         <p>The list of ad servers used by the ad blocker comes from <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Because a list of domain names is a list of facts, it <a href="https://www.copyright.gov/help/faq/faq-protect.html">cannot be copyrighted</a>.</p>
+        <p>Privacy Browser is built with the <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            which is released under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             are derived from ic_security and ic_language, which are part of the <a href="https://material.io/icons/">Android Material icon set</a> and are released under the <a href ="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.
             The full text of the license is below. Modifications copyright © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>. The resulting images are released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>.</p>
index aa52ae2013d0cf8c2cdad9ce858f3d7e596ed77f..3474713e27cb74b363f3d484244064276551f055 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-  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>.
 
@@ -25,7 +25,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser copyright © 2015-2017 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser copyright © 2015-2018 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>License</h3>
         <p>Privacy Browser is released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>. The full text of the license is below.
@@ -34,6 +34,8 @@
         <h3>Attributions</h3>
         <p>The list of ad servers used by the ad blocker comes from <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Because a list of domain names is a list of facts, it <a href="https://www.copyright.gov/help/faq/faq-protect.html">cannot be copyrighted</a>.</p>
+        <p>Privacy Browser is built with the <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            which is released under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.</p>
         <p><img class="left" src="images/privacy_browser.png"> <img class="left" src="images/privacy_browser_free.png"> <img class="left" src="images/warning.png"> <img class="left" src="images/javascript_enabled.png">
             are derived from ic_security and ic_language, which are part of the <a href="https://material.io/icons/">Android Material icon set</a> and are released under the <a href ="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.
             The full text of the license is below. Modifications copyright © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>. The resulting images are released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>.</p>
index 1cebdb2c40e845984ce30872b4da5d13fb58bd3b..500cb33557cfbc54b13fbcb95639c0e0ab47808a 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-  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>.
 
@@ -25,7 +25,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser copyright © 2015-2017 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser copyright © 2015-2018 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>License</h3>
         <p>Privacy Browser is released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>. The full text of the license is below.
@@ -34,6 +34,8 @@
         <h3>Attributions</h3>
         <p>The list of ad servers used by the ad blocker comes from <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Because a list of domain names is a list of facts, it <a href="https://www.copyright.gov/help/faq/faq-protect.html">cannot be copyrighted</a>.</p>
+        <p>Privacy Browser is built with the <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            which is released under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.</p>
         <p><img class="left" src="images/privacy_browser.png"> <img class="left" src="images/privacy_browser_free.png"> <img class="left" src="images/warning.png"> <img class="left" src="images/javascript_enabled.png">
             are derived from ic_security and ic_language, which are part of the <a href="https://material.io/icons/">Android Material icon set</a> and are released under the <a href ="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</a>.
             The full text of the license is below. Modifications copyright © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>. The resulting images are released under the <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+ license</a>.</p>
index 4feb1e0b26e985baada5256e21daad8f5bf56321..24e38fcc766411923d97ef2244a4e89ed4f9fb6b 100644 (file)
@@ -1,7 +1,7 @@
 <!--
-  Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
 
-  Translation 2017 Jose A. León Becerra <emails@joseleon.me>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+  Translation 2017-2018 Jose A. León Becerra <emails@joseleon.me>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
   This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
 
@@ -27,7 +27,7 @@
 
     <body>
         <h3>Derechos de autor</h3>
-        <p>Navegador Privado tiene derechos de autor © 2015-2017 por <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Navegador Privado tiene derechos de autor © 2015-2018 por <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Licencia</h3>
         <p>Navegador Privado está liberado bajo la licencia <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+</a>. El texto completo de la licencia se encuentra en la parte inferior de este documento (se deja en el idioma original).
@@ -36,6 +36,8 @@
         <h3>Atribuciones</h3>
         <p>La lista de servidores publicitarios usados por el bloqueador de anuncios procede de <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Ya que una lista de nombres de dominio es una lista de hechos, no puede tener <a href="https://www.copyright.gov/help/faq/faq-protect.html">derechos de autor</a>.</p>
+        <p>Navegador privado está construido con la <a href="https://developer.android.com/topic/libraries/support-library/index.html">librería de soporte de android</a>,
+            que se libera bajo la <a href="https://www.apache.org/licenses/LICENSE-2.0">Licencia Apache 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             derivan de ic_security y de ic_language, que son parte del <a href="https://material.io/icons/">conjunto de iconos Android Material</a> y son liberados bajo la <a href ="https://www.apache.org/licenses/LICENSE-2.0">Licencia Apache 2.0</a>.
             El texto completo de la licencia se encuentra debajo. Copyright de modificaciones © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>. Las imágenes resultantes se liberan bajo la
index be90b67e7a0f546c4b1389c3909ee0fa2eb06a48..b5eaec784bfe2f9a7a32451fc5b0ab872a4cfb00 100644 (file)
@@ -1,7 +1,7 @@
 <!--
-  Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
 
-  Translation 2017 Jose A. León Becerra <emails@joseleon.me>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+  Translation 2017-2018 Jose A. León Becerra <emails@joseleon.me>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
   This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
 
@@ -27,7 +27,7 @@
 
     <body>
         <h3>Derechos de autor</h3>
-        <p>Navegador Privado tiene derechos de autor © 2015-2017 por <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Navegador Privado tiene derechos de autor © 2015-2018 por <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Licencia</h3>
         <p>Navegador Privado está liberado bajo la licencia <a href="https://www.gnu.org/licenses/gpl-3.0.html">GPLv3+</a>. El texto completo de la licencia se encuentra en la parte inferior de este documento (se deja en el idioma original).
@@ -36,6 +36,8 @@
         <h3>Atribuciones</h3>
         <p>La lista de servidores publicitarios usados por el bloqueador de anuncios procede de <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Ya que una lista de nombres de dominio es una lista de hechos, no puede tener <a href="https://www.copyright.gov/help/faq/faq-protect.html">derechos de autor</a>.</p>
+        <p>Navegador privado está construido con la <a href="https://developer.android.com/topic/libraries/support-library/index.html">librería de soporte de android</a>,
+            que se libera bajo la <a href="https://www.apache.org/licenses/LICENSE-2.0">Licencia Apache 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             derivan de ic_security y de ic_language, que son parte del <a href="https://material.io/icons/">conjunto de iconos Android Material</a> y son liberados bajo la <a href ="https://www.apache.org/licenses/LICENSE-2.0">Licencia Apache 2.0</a>.
             El texto completo de la licencia se encuentra debajo. Copyright de modificaciones © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.
index 7727f949e3bc7af5a9d4739a346e9234ba2d7679..ef941af199e20b2c45911c34c321487c673884ae 100644 (file)
@@ -1,7 +1,7 @@
 <!--
-  Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
 
-  Translation 2017 Francesco Buratti.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+  Translation 2017-2018 Francesco Buratti.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
   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
@@ -25,7 +25,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser copyright © 2015-2017: <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser copyright © 2015-2018: <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Licenza</h3>
         <p>Privacy Browser è rilasciato con <a href="https://www.gnu.org/licenses/gpl-3.0.html">Licenza GPLv3+ </a>.
@@ -40,6 +40,8 @@
         <h3>Attribuzioni</h3>
         <p>La lista dei server utilizzata dalla funzionalità di blocco degli annunci è tratta da <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Dal momento che si tratta di una lista di domini <a href="https://www.copyright.gov/help/faq/faq-protect.html">non può essere coperta da Copyright</a>.</p>
+        <p>Privacy Browser è sviluppato con la <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            che è rilasciata con <a href="https://www.apache.org/licenses/LICENSE-2.0">Licenza Apache 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             sono state derivate da ic_security e ic_language, che fanno parte dell'<a href="https://material.io/icons/">Android Material icon set</a> e sono state rilasciate sotto <a href ="https://www.apache.org/licenses/LICENSE-2.0">Licenza Apache 2.0</a>.
             Il testo completo della Licenza è riportato di seguito. Copyright delle modifiche © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.
index f93e858d09bd45ef8be6ea86f1b5ae01b856f724..6936277fc7ff5b3b50f10690bf9277b28165cb11 100644 (file)
@@ -1,7 +1,7 @@
 <!--
-  Copyright © 2017 Soren Stoutner <soren@stoutner.com>.
+  Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
 
-  Translation 2017 Francesco Buratti.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+  Translation 2017-2018 Francesco Buratti.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
   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
@@ -25,7 +25,7 @@
 
     <body>
         <h3>Copyright</h3>
-        <p>Privacy Browser copyright © 2015-2017: <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+        <p>Privacy Browser copyright © 2015-2018: <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
 
         <h3>Licenza</h3>
         <p>Privacy Browser è rilasciato con <a href="https://www.gnu.org/licenses/gpl-3.0.html">Licenza GPLv3+ </a>.
@@ -40,6 +40,8 @@
         <h3>Attribuzioni</h3>
         <p>La lista dei server utilizzata dalla funzionalità di blocco degli annunci è tratta da <a href="https://pgl.yoyo.org/adservers/">pgl.yoyo.org</a>.
             Dal momento che si tratta di una lista di domini <a href="https://www.copyright.gov/help/faq/faq-protect.html">non può essere coperta da Copyright</a>.</p>
+        <p>Privacy Browser è sviluppato con la <a href="https://developer.android.com/topic/libraries/support-library/index.html">Android Support Library</a>,
+            che è rilasciata con <a href="https://www.apache.org/licenses/LICENSE-2.0">Licenza Apache 2.0</a>.</p>
         <p><img class="left" src="../en/images/privacy_browser.png"> <img class="left" src="../en/images/privacy_browser_free.png"> <img class="left" src="../en/images/warning.png"> <img class="left" src="../en/images/javascript_enabled.png">
             sono state derivate da ic_security e ic_language, che fanno parte dell'<a href="https://material.io/icons/">Android Material icon set</a> e sono state rilasciate sotto <a href ="https://www.apache.org/licenses/LICENSE-2.0">Licenza Apache 2.0</a>.
             Il testo completo della Licenza è riportato di seguito. Copyright delle modifiche © 2016 <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.
index c20452151e9f5c010795593bdd577fdb07384eba..0f6df3dfad5b166ab4b2eddf699664039b0a964e 100644 (file)
@@ -48,21 +48,21 @@ public class AboutActivity extends AppCompatActivity {
         // Set the content view.
         setContentView(R.layout.about_coordinatorlayout);
 
-        // We need to use the SupportActionBar from android.support.v7.app.ActionBar until the minimum API is >= 21.
-        Toolbar aboutAppBar = (Toolbar) findViewById(R.id.about_toolbar);
+        // `SupportActionBar` from `android.support.v7.app.ActionBar` must be used until the minimum API is >= 21.
+        Toolbar aboutAppBar = findViewById(R.id.about_toolbar);
         setSupportActionBar(aboutAppBar);
 
-        // Display the home arrow on supportAppBar.
+        // Display the home arrow on `supportAppBar`.
         final ActionBar appBar = getSupportActionBar();
-        assert appBar != null;// This assert removes the incorrect warning in Android Studio on the following line that appBar might be null.
+        assert appBar != null;  // This assert removes the incorrect warning in Android Studio on the following line that appBar might be null.
         appBar.setDisplayHomeAsUpEnabled(true);
 
         //  Setup the ViewPager.
-        ViewPager aboutViewPager = (ViewPager) findViewById(R.id.about_viewpager);
+        ViewPager aboutViewPager = findViewById(R.id.about_viewpager);
         aboutViewPager.setAdapter(new aboutPagerAdapter(getSupportFragmentManager()));
 
         // Setup the TabLayout and connect it to the ViewPager.
-        TabLayout aboutTabLayout = (TabLayout) findViewById(R.id.about_tablayout);
+        TabLayout aboutTabLayout = findViewById(R.id.about_tablayout);
         aboutTabLayout.setupWithViewPager(aboutViewPager);
     }
 
index 63225a08f55b59253d1da33de4b92e803930f8b2..27d56930e9ce637ded4218b7548eaf83000bfc30 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2015-2017 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2015-2018 Soren Stoutner <soren@stoutner.com>.
  *
  * Download cookie code contributed 2017 Hendrik Knackstedt.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
  *
@@ -167,6 +167,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // `webViewTitle` is public static so it can be accessed from `CreateBookmarkDialog` and `CreateHomeScreenShortcutDialog`.  It is also used in `onCreate()`.
     public static String webViewTitle;
 
+    // `appliedUserAgentString` is public static so it can be accessed from `ViewSourceActivity`.  It is also used in `applyDomainSettings()`.
+    public static String appliedUserAgentString;
+
     // `displayWebpageImagesBoolean` is public static so it can be accessed from `DomainSettingsFragment`.  It is also used in `applyAppSettings()` and `applyDomainSettings()`.
     public static boolean displayWebpageImagesBoolean;
 
@@ -327,13 +330,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // `urlTextBox` is used in `onCreate()`, `onOptionsItemSelected()`, `loadUrlFromTextBox()`, `loadUrl()`, and `highlightUrlText()`.
     private EditText urlTextBox;
 
-    // `redColorSpan` is used in `onCreate()` and `highlightUrlText()`.
+    // The color spans are used in `onCreate()` and `highlightUrlText()`.
     private ForegroundColorSpan redColorSpan;
-
-    // `initialGrayColorSpan` is sued in `onCreate()` and `highlightUrlText()`.
     private ForegroundColorSpan initialGrayColorSpan;
-
-    // `finalGrayColorSpam` is used in `onCreate()` and `highlightUrlText()`.
     private ForegroundColorSpan finalGrayColorSpan;
 
     // `adView` is used in `onCreate()` and `onConfigurationChanged()`.
@@ -415,16 +414,16 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
         appBar.setCustomView(R.layout.url_app_bar);
         appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
 
-        // Initialize the `ForegroundColorSpans` and `StyleSpan` for highlighting `urlTextBox`.  We have to use the deprecated `getColor()` until API >= 23.
+        // Initialize the foreground color spans for highlighting the URLs.  We have to use the deprecated `getColor()` until API >= 23.
         redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
         initialGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500));
         finalGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500));
 
         // Get a handle for `urlTextBox`.
-        urlTextBox = appBar.getCustomView().findViewById(R.id.url_edittext);
+        urlTextBox = findViewById(R.id.url_edittext);
 
         // Remove the formatting from `urlTextBar` when the user is editing the text.
-        urlTextBox.setOnFocusChangeListener((v, hasFocus) -> {
+        urlTextBox.setOnFocusChangeListener((View v, boolean hasFocus) -> {
             if (hasFocus) {  // The user is editing `urlTextBox`.
                 // Remove the highlighting.
                 urlTextBox.getText().removeSpan(redColorSpan);
@@ -436,8 +435,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
             }
         });
 
-        // Set the `Go` button on the keyboard to load the URL in `urlTextBox`.
-        urlTextBox.setOnKeyListener((v, keyCode, event) -> {
+        // Set the go button on the keyboard to load the URL in `urlTextBox`.
+        urlTextBox.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
             // If the event is a key-down event on the `enter` button, load the URL.
             if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
                 // Load the URL into the mainWebView and consume the event.
@@ -812,8 +811,8 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
 
             // Close `bufferedReader`.
             bufferedReader.close();
-        } catch (IOException ioException) {
-            // We're pretty sure the asset exists, so we don't need to worry about the `IOException` ever being thrown.
+        } catch (IOException e) {
+            // The asset exists, so the `IOException` will never be thrown.
         }
 
         mainWebView.setWebViewClient(new WebViewClient() {
@@ -1127,7 +1126,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                             });
                 }
 
+                // Update the progress bar.
                 progressBar.setProgress(progress);
+
+                // Set the visibility of the progress bar.
                 if (progress < 100) {
                     // Show the progress bar.
                     progressBar.setVisibility(View.VISIBLE);
@@ -1221,7 +1223,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
         registerForContextMenu(mainWebView);
 
         // Allow the downloading of files.
-        mainWebView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
+        mainWebView.setDownloadListener((String url, String userAgent, String contentDisposition, String mimetype, long contentLength) -> {
             // Show the `DownloadFileDialog` `AlertDialog` and name this instance `@string/download`.
             AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
             downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
@@ -1578,7 +1580,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
         // Run all the other default commands.
         super.onPrepareOptionsMenu(menu);
 
-        // `return true` displays the menu.
+        // Display the menu.
         return true;
     }
 
@@ -1588,6 +1590,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     // removeAllCookies is deprecated, but it is required for API < 21.
     @SuppressWarnings("deprecation")
     public boolean onOptionsItemSelected(MenuItem menuItem) {
+        // Get the selected menu item ID.
         int menuItemId = menuItem.getItemId();
 
         // Set the commands that relate to the menu entries.
@@ -1915,6 +1918,12 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                 printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
                 return true;
 
+            case R.id.view_source:
+                // Launch the Vew Source activity.
+                Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
+                startActivity(viewSourceIntent);
+                return true;
+
             case R.id.add_to_homescreen:
                 // Show the `CreateHomeScreenShortcutDialog` `AlertDialog` and name this instance `R.string.create_shortcut`.
                 AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
@@ -2259,7 +2268,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                 });
 
                 // Add a `Download Image` entry.
-                menu.add(R.string.download_image).setOnMenuItemClickListener(item -> {
+                menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
                     // Show the `DownloadImageDialog` `AlertDialog` and name this instance `@string/download`.
                     AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
                     downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
@@ -2296,7 +2305,7 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                 });
 
                 // Add a `Download Image` entry.
-                menu.add(R.string.download_image).setOnMenuItemClickListener(item -> {
+                menu.add(R.string.download_image).setOnMenuItemClickListener((MenuItem item) -> {
                     // Show the `DownloadImageDialog` `AlertDialog` and name this instance `@string/download`.
                     AppCompatDialogFragment downloadImageDialogFragment = DownloadImageDialog.imageUrl(imageUrl);
                     downloadImageDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
@@ -2824,10 +2833,10 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     }
 
     private void applyAppSettings() {
-        // Get a handle for `sharedPreferences`.  `this` references the current context.
+        // Get a handle for the shared preferences.
         SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 
-        // Store the values from `sharedPreferences` in variables.
+        // Store the values from the shared preferences in variables.
         String homepageString = sharedPreferences.getString("homepage", "https://start.duckduckgo.com");
         String torHomepageString = sharedPreferences.getString("tor_homepage", "https://3g2upl4pq6kufc4m.onion");
         String torSearchString = sharedPreferences.getString("tor_search", "https://3g2upl4pq6kufc4m.onion/html/?q=");
@@ -3179,6 +3188,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                             // Use the selected user agent.
                             mainWebView.getSettings().setUserAgentString(userAgentString);
                     }
+
+                    // Store the applied user agent string.
+                    appliedUserAgentString = mainWebView.getSettings().getUserAgentString();
                 }
 
                 // Set a green background on `urlTextBox` to indicate that custom domain settings are being used.  We have to use the deprecated `.getDrawable()` until the minimum API >= 21.
@@ -3241,6 +3253,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
                             // Use the selected user agent.
                             mainWebView.getSettings().setUserAgentString(defaultUserAgentString);
                     }
+
+                    // Store the applied user agent string.
+                    appliedUserAgentString = mainWebView.getSettings().getUserAgentString();
                 }
 
                 // Set a transparent background on `urlTextBox`.  We have to use the deprecated `.getDrawable()` until the minimum API >= 21.
@@ -3347,9 +3362,9 @@ public class MainWebViewActivity extends AppCompatActivity implements AddDomainD
     private void highlightUrlText() {
         String urlString = urlTextBox.getText().toString();
 
-        if (urlString.startsWith("http://")) {  // Highlight connections that are not encrypted.
+        if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
             urlTextBox.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-        } else if (urlString.startsWith("https://")) {  // Highlight connections that are encrypted.
+        } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
             urlTextBox.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
         }
 
diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.java
new file mode 100644 (file)
index 0000000..583e3c6
--- /dev/null
@@ -0,0 +1,588 @@
+/*
+ * 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/>.
+ */
+
+package com.stoutner.privacybrowser.activities;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.graphics.Typeface;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.preference.PreferenceManager;
+import android.support.v4.app.NavUtils;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.text.style.StyleSpan;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.CookieManager;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.dialogs.AboutViewSourceDialog;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Locale;
+
+public class ViewSourceActivity extends AppCompatActivity {
+    // `activity` is used in `onCreate()` and `goBack()`.
+    Activity activity;
+
+    // The color spans are used in `onCreate()` and `highlightUrlText()`.
+    private ForegroundColorSpan redColorSpan;
+    private ForegroundColorSpan initialGrayColorSpan;
+    private ForegroundColorSpan finalGrayColorSpan;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        // Set the theme.
+        if (MainWebViewActivity.darkTheme) {
+            setTheme(R.style.PrivacyBrowserDark);
+        } else {
+            setTheme(R.style.PrivacyBrowserLight);
+        }
+
+        // Run the default commands.
+        super.onCreate(savedInstanceState);
+
+        // Store a handle for the current activity.
+        activity = this;
+
+        // Set the content view.
+        setContentView(R.layout.view_source_coordinatorlayout);
+
+        // `SupportActionBar` from `android.support.v7.app.ActionBar` must be used until the minimum API is >= 21.
+        Toolbar viewSourceAppBar = findViewById(R.id.view_source_toolbar);
+        setSupportActionBar(viewSourceAppBar);
+
+        // Setup the app bar.
+        final ActionBar appBar = getSupportActionBar();
+
+        // Remove the incorrect warning in Android Studio that appBar might be null.
+        assert appBar != null;
+
+        // Add the custom layout to the app bar.
+        appBar.setCustomView(R.layout.view_source_app_bar);
+        appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+
+        // Get a handle for the url text box.
+        EditText urlEditText = findViewById(R.id.url_edittext);
+
+        // Get the formatted URL string from the main activity.
+        String formattedUrlString = MainWebViewActivity.formattedUrlString;
+
+        // Populate the URL text box.
+        urlEditText.setText(formattedUrlString);
+
+        // Initialize the foreground color spans for highlighting the URLs.  We have to use the deprecated `getColor()` until API >= 23.
+        redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
+        initialGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500));
+        finalGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500));
+
+        // Apply text highlighting to the URL.
+        highlightUrlText();
+
+        // Get a handle for the input method manager, which is used to hide the keyboard.
+        InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+
+        // Let Android Studio know that we aren't worried about the input method manager being null.
+        assert inputMethodManager != null;
+
+        // Remove the formatting from the URL when the user is editing the text.
+        urlEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
+            if (hasFocus) {  // The user is editing `urlTextBox`.
+                // Remove the highlighting.
+                urlEditText.getText().removeSpan(redColorSpan);
+                urlEditText.getText().removeSpan(initialGrayColorSpan);
+                urlEditText.getText().removeSpan(finalGrayColorSpan);
+            } else {  // The user has stopped editing `urlTextBox`.
+                // Hide the soft keyboard.
+                inputMethodManager.hideSoftInputFromWindow(urlEditText.getWindowToken(), 0);
+
+                // Reapply the highlighting.
+                highlightUrlText();
+
+
+            }
+        });
+
+        // Set the go button on the keyboard to request new source data.
+        urlEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
+            // Request new source data if the enter key was pressed.
+            if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
+                // Hide the soft keyboard.
+                inputMethodManager.hideSoftInputFromWindow(urlEditText.getWindowToken(), 0);
+
+                // Remove the focus from the URL box.
+                urlEditText.clearFocus();
+
+                // Get new source data for the current URL.
+                new GetSource().execute(urlEditText.getText().toString());
+
+                // Consume the key press.
+                return true;
+            } else {
+                // Do not consume the key press.
+                return false;
+            }
+        });
+
+        // Get the source as an `AsyncTask`.
+        new GetSource().execute(formattedUrlString);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Inflate the menu; this adds items to the action bar if it is present.
+        getMenuInflater().inflate(R.menu.view_source_options_menu, menu);
+
+        // Display the menu.
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem menuItem) {
+        // Get a handle for the about alert dialog.
+        DialogFragment aboutDialogFragment = new AboutViewSourceDialog();
+
+        // Show the about alert dialog.
+        aboutDialogFragment.show(getFragmentManager(), getString(R.string.about));
+
+        // Consume the event.
+        return true;
+    }
+
+    public void goBack(View view) {
+        // Go home.
+        NavUtils.navigateUpFromSameTask(activity);
+    }
+
+    private void highlightUrlText() {
+        // Get a handle for the URL EditText.
+        EditText urlEditText = findViewById(R.id.url_edittext);
+
+        // Get the URL.
+        String urlString = urlEditText.getText().toString();
+
+        // Highlight the beginning of the URL.
+        if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
+            urlEditText.getText().setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
+            urlEditText.getText().setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        }
+
+        // Get the index of the `/` immediately after the domain name.
+        int endOfDomainName = urlString.indexOf("/", (urlString.indexOf("//") + 2));
+
+        // De-emphasize the text after the domain name.
+        if (endOfDomainName > 0) {
+            urlEditText.getText().setSpan(finalGrayColorSpan, endOfDomainName, urlString.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+        }
+    }
+
+    // The first `String` declares the parameters.  The `Void` does not declare progress units.  The last `String` contains the results.
+    // `StaticFieldLeaks` are suppressed so that Android Studio doesn't complain about running an AsyncTask in a non-static context.
+    @SuppressLint("StaticFieldLeak")
+    private class GetSource extends AsyncTask<String, Void, String> {
+        // The class variables pass information from `doInBackground()` to `onPostExecute()`.
+        SpannableStringBuilder responseMessageBuilder;
+        SpannableStringBuilder requestHeadersBuilder;
+        SpannableStringBuilder responseHeadersBuilder;
+
+        // `onPreExecute()` operates on the UI thread.
+        @Override
+        protected void onPreExecute() {
+            // Get a handle for the progress bar.
+            ProgressBar progressBar = findViewById(R.id.progress_bar);
+
+            // Make the progress bar visible.
+            progressBar.setVisibility(View.VISIBLE);
+
+            // Set the progress bar to be indeterminate.
+            progressBar.setIndeterminate(true);
+        }
+
+        @Override
+        protected String doInBackground(String... formattedUrlString) {
+            // Initialize the response body `String`.
+            String responseBodyString = "";
+
+            // Because everything relating to requesting data from a webserver can throw errors, the entire section must catch `IOExceptions`.
+            try {
+                // Get the current URL from the main activity.
+                URL url = new URL(formattedUrlString[0]);
+
+                // Open a connection to the URL.  No data is actually sent at this point.
+                HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
+
+                // Instantiate the variables necessary to build the request headers.
+                requestHeadersBuilder = new SpannableStringBuilder();
+                int oldRequestHeadersBuilderLength;
+                int newRequestHeadersBuilderLength;
+
+
+                // Set the `Host` header property.
+                httpUrlConnection.setRequestProperty("Host", url.getHost());
+
+                // Add the `Host` header to the string builder and format the text.
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Host", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Host");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  ");
+                requestHeadersBuilder.append(url.getHost());
+
+
+                // Set the `Connection` header property.
+                httpUrlConnection.setRequestProperty("Connection", "keep-alive");
+
+                // Add the `Connection` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Connection", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Connection");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  keep-alive");
+
+
+                // Get the current `User-Agent` string.
+                String userAgentString = MainWebViewActivity.appliedUserAgentString;
+
+                // Set the `User-Agent` header property.
+                httpUrlConnection.setRequestProperty("User-Agent", userAgentString);
+
+                // Add the `User-Agent` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("User-Agent", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("User-Agent");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  ");
+                requestHeadersBuilder.append(userAgentString);
+
+
+                // Set the `Upgrade-Insecure-Requests` header property.
+                httpUrlConnection.setRequestProperty("Upgrade-Insecure-Requests", "1");
+
+                // Add the `Upgrade-Insecure-Requests` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Upgrade-Insecure-Requests", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Upgrade-Insecure_Requests");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  1");
+
+
+                // Set the `x-requested-with` header property.
+                httpUrlConnection.setRequestProperty("x-requested-with", "");
+
+                // Add the `x-requested-with` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("x-requested-with", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("x-requested-with");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  ");
+
+
+                // Get a handle for the shared preferences.
+                SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+
+                // Only populate `Do Not Track` if it is enabled.
+                if (sharedPreferences.getBoolean("do_not_track", false)) {
+                    // Set the `dnt` header property.
+                    httpUrlConnection.setRequestProperty("dnt", "1");
+
+                    // Add the `dnt` header to the string builder and format the text.
+                    requestHeadersBuilder.append(System.getProperty("line.separator"));
+                    if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                        requestHeadersBuilder.append("dnt", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    } else {  // Older versions not so much.
+                        oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                        requestHeadersBuilder.append("dnt");
+                        newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                        requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
+                    requestHeadersBuilder.append(":  1");
+                }
+
+
+                // Set the `Accept` header property.
+                httpUrlConnection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
+
+                // Add the `Accept` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Accept", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Accept");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  ");
+                requestHeadersBuilder.append("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
+
+
+                // Instantiate a locale string.
+                String localeString;
+
+                // Populate the locale string.
+                if (Build.VERSION.SDK_INT >= 24) {  // SDK >= 24 has a list of locales.
+                    // Get the list of locales.
+                    LocaleList localeList = getResources().getConfiguration().getLocales();
+
+                    // Initialize a string builder to extract the locales from the list.
+                    StringBuilder localesStringBuilder = new StringBuilder();
+
+                    // Initialize a `q` value, which is used by `WebView` to indicate the order of importance of the languages.
+                    int q = 10;
+
+                    // Populate the string builder with the contents of the locales list.
+                    for (int i = 0; i < localeList.size(); i++) {
+                        // Append a comma if there is already an item in the string builder.
+                        if (i > 0) {
+                            localesStringBuilder.append(",");
+                        }
+
+                        // Get the indicated locale from the list.
+                        localesStringBuilder.append(localeList.get(i));
+
+                        // If not the first locale, append `;q=0.i`, which drops by .1 for each removal from the main locale.
+                        if (q < 10) {
+                            localesStringBuilder.append(";q=0.");
+                            localesStringBuilder.append(q);
+                        }
+
+                        // Decrement `q`.
+                        q--;
+                    }
+
+                    // Store the populated string builder in the locale string.
+                    localeString = localesStringBuilder.toString();
+                } else {  // SDK < 24 only has a primary locale.
+                    // Store the locale in the locale string.
+                    localeString = Locale.getDefault().toString();
+                }
+
+                // Set the `Accept-Language` header property.
+                httpUrlConnection.setRequestProperty("Accept-Language", localeString);
+
+                // Add the `Accept-Language` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Accept-Language", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Accept-Language");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  ");
+                requestHeadersBuilder.append(localeString);
+
+
+                // Get the cookies for the current domain.
+                String cookiesString = CookieManager.getInstance().getCookie(url.toString());
+
+                // Only process the cookies if they are not null.
+                if (cookiesString != null) {
+                    // Set the `Cookie` header property.
+                    httpUrlConnection.setRequestProperty("Cookie", cookiesString);
+
+                    // Add the `Cookie` header to the string builder and format the text.
+                    requestHeadersBuilder.append(System.getProperty("line.separator"));
+                    if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                        requestHeadersBuilder.append("Cookie", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    } else {  // Older versions not so much.
+                        oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                        requestHeadersBuilder.append("Cookie");
+                        newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                        requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
+                    requestHeadersBuilder.append(":  ");
+                    requestHeadersBuilder.append(cookiesString);
+                }
+
+
+                // `HttpUrlConnection` sets `Accept-Encoding` to be `gzip` by default.  If the property is manually set, than `HttpUrlConnection` does not process the decoding.
+                // Add the `Accept-Encoding` header to the string builder and format the text.
+                requestHeadersBuilder.append(System.getProperty("line.separator"));
+                if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                    requestHeadersBuilder.append("Accept-Encoding", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                } else {  // Older versions not so much.
+                    oldRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.append("Accept-Encoding");
+                    newRequestHeadersBuilderLength = requestHeadersBuilder.length();
+                    requestHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldRequestHeadersBuilderLength + 1, newRequestHeadersBuilderLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                }
+                requestHeadersBuilder.append(":  gzip");
+
+
+                // The actual network request is in a `try` bracket so that `disconnect()` is run in the `finally` section even if an error is encountered in the main block.
+                try {
+                    // Initialize the string builders.
+                    responseMessageBuilder = new SpannableStringBuilder();
+                    responseHeadersBuilder = new SpannableStringBuilder();
+
+                    // Get the response code, which causes the connection to the server to be made.
+                    int responseCode = httpUrlConnection.getResponseCode();
+
+                    // Populate the response message string builder.
+                    if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                        responseMessageBuilder.append(String.valueOf(responseCode), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    } else {  // Older versions not so much.
+                        responseMessageBuilder.append(String.valueOf(responseCode));
+                        int newLength = responseMessageBuilder.length();
+                        responseMessageBuilder.setSpan(new StyleSpan(Typeface.BOLD), 0, newLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    }
+                    responseMessageBuilder.append(":  ");
+                    responseMessageBuilder.append(httpUrlConnection.getResponseMessage());
+
+                    // Initialize the iteration variable.
+                    int i = 0;
+
+                    // Iterate through the received header fields.
+                    while (httpUrlConnection.getHeaderField(i) != null) {
+                        // Add a new line if there is already information in the string builder.
+                        if (i > 0) {
+                            responseHeadersBuilder.append(System.getProperty("line.separator"));
+                        }
+
+                        // Add the header to the string builder and format the text.
+                        if (Build.VERSION.SDK_INT >= 21) {  // Newer versions of Android are so smart.
+                            responseHeadersBuilder.append(httpUrlConnection.getHeaderFieldKey(i), new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                        } else {  // Older versions not so much.
+                            int oldLength = responseHeadersBuilder.length();
+                            responseHeadersBuilder.append(httpUrlConnection.getHeaderFieldKey(i));
+                            int newLength = responseHeadersBuilder.length();
+                            responseHeadersBuilder.setSpan(new StyleSpan(Typeface.BOLD), oldLength + 1, newLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                        }
+                        responseHeadersBuilder.append(":  ");
+                        responseHeadersBuilder.append(httpUrlConnection.getHeaderField(i));
+
+                        // Increment the iteration variable.
+                        i++;
+                    }
+
+                    // Instantiate an input stream for the response body.
+                    InputStream inputStream;
+
+                    // Get the correct input stream based on the response code.
+                    if (responseCode == 404) {  // Get the error stream.
+                        inputStream = new BufferedInputStream(httpUrlConnection.getErrorStream());
+                    } else {  // Get the response body stream.
+                        inputStream = new BufferedInputStream(httpUrlConnection.getInputStream());
+                    }
+
+                    // Initialize the byte array output stream and the conversion buffer byte array.
+                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+                    byte[] conversionBufferByteArray = new byte[1024];
+
+                    // Instantiate the variable to track the buffer length.
+                    int bufferLength;
+
+                    try {
+                        // Attempt to read data from the input stream and store it in the conversion buffer byte array.  Also store the amount of data transferred in the buffer length variable.
+                        while ((bufferLength = inputStream.read(conversionBufferByteArray)) > 0) {  // Proceed while the amount of data stored in the buffer is > 0.
+                            // Write the contents of the conversion buffer to the byte array output stream.
+                            byteArrayOutputStream.write(conversionBufferByteArray, 0, bufferLength);
+                        }
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+
+                    // Close the input stream.
+                    inputStream.close();
+
+                    // Populate the response body string with the contents of the byte array output stream.
+                    responseBodyString = byteArrayOutputStream.toString();
+                } finally {
+                    // Disconnect `httpUrlConnection`.
+                    httpUrlConnection.disconnect();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+
+            // Return the response body string as the result.
+            return responseBodyString;
+        }
+
+        // `onPostExecute()` operates on the UI thread.
+        @Override
+        protected void onPostExecute(String responseBodyString){
+            // Get handles for the text views.
+            TextView requestHeadersTextView = findViewById(R.id.request_headers);
+            TextView responseMessageTextView = findViewById(R.id.response_message);
+            TextView responseHeadersTextView = findViewById(R.id.response_headers);
+            TextView responseBodyTextView = findViewById(R.id.response_body);
+            ProgressBar progressBar = findViewById(R.id.progress_bar);
+
+            // Populate the text views.
+            requestHeadersTextView.setText(requestHeadersBuilder);
+            responseMessageTextView.setText(responseMessageBuilder);
+            responseHeadersTextView.setText(responseHeadersBuilder);
+            responseBodyTextView.setText(responseBodyString);
+
+            // Hide the progress bar.
+            progressBar.setIndeterminate(false);
+            progressBar.setVisibility(View.GONE);
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewSourceDialog.java
new file mode 100644 (file)
index 0000000..4cd4e7f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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/>.
+ */
+
+package com.stoutner.privacybrowser.dialogs;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.os.Bundle;
+
+import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
+
+public class AboutViewSourceDialog extends DialogFragment {
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        // Use a builder to create the alert dialog.
+        AlertDialog.Builder dialogBuilder;
+
+        // Set the style and the icon according to the theme.
+        if (MainWebViewActivity.darkTheme) {
+            dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
+            dialogBuilder.setIcon(R.drawable.about_dark);
+        } else {
+            dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
+            dialogBuilder.setIcon(R.drawable.about_light);
+        }
+
+        // Set an `onClick` listener on the negative button.  Using `null` as the listener closes the dialog without doing anything else.
+        dialogBuilder.setNegativeButton(R.string.close, null);
+
+        // Set the title.
+        dialogBuilder.setTitle(R.string.about_view_source);
+
+        // Set the text.
+        dialogBuilder.setMessage(R.string.about_view_source_message);
+
+        // `onCreateDialog` requires the return of an `AlertDialog`.
+        return dialogBuilder.create();
+    }
+}
index 8decfca9bb7354b210dee5acd1c19f34db3092b3..6f9fa4d45ee07d41cbca23917802586b162e4272 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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>.
  *
@@ -51,7 +51,7 @@ public class ViewSslCertificateDialog extends DialogFragment {
         // Create a drawable version of the favorite icon.
         Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
 
-        // Use `AlertDialog.Builder` to create the `AlertDialog`.
+        // Use a builder to create the alert dialog.
         AlertDialog.Builder dialogBuilder;
 
         // Set the style according to the theme.
@@ -64,7 +64,7 @@ public class ViewSslCertificateDialog extends DialogFragment {
         // Set the icon.
         dialogBuilder.setIcon(favoriteIconDrawable);
 
-        // Set an `onClick` listener on the negative button.  Using `null` closes the dialog without doing anything else.
+        // Set an `onClick` listener on the negative button.  Using `null` as the listener closes the dialog without doing anything else.
         dialogBuilder.setNegativeButton(R.string.close, null);
 
         // Check to see if the website is encrypted.
@@ -75,14 +75,8 @@ public class ViewSslCertificateDialog extends DialogFragment {
             // Set the Layout.  The parent view is `null` because it will be assigned by `AlertDialog`.
             dialogBuilder.setView(layoutInflater.inflate(R.layout.unencrypted_website, null));
 
-            // Create an `AlertDialog` from the `AlertDialog.Builder`
-            final AlertDialog alertDialog = dialogBuilder.create();
-
-            // Show `alertDialog`.
-            alertDialog.show();
-
             // `onCreateDialog` requires the return of an `AlertDialog`.
-            return alertDialog;
+            return dialogBuilder.create();
 
         } else {  // Display the SSL certificate information
             // Set the title.
@@ -91,22 +85,22 @@ public class ViewSslCertificateDialog extends DialogFragment {
             // Set the layout.  The parent view is `null` because it will be assigned by `AlertDialog`.
             dialogBuilder.setView(layoutInflater.inflate(R.layout.view_ssl_certificate, null));
 
-            // Create an `AlertDialog` from the `AlertDialog.Builder`
+            // Create an alert dialog from the builder.
             final AlertDialog alertDialog = dialogBuilder.create();
 
-            // The `AlertDialog` must be shown before items in the layout can be modified.
+            // The alert dialog must be shown before items in the layout can be modified.
             alertDialog.show();
 
             // Get handles for the `TextViews`.
-            TextView domainTextView = (TextView) alertDialog.findViewById(R.id.domain);
-            TextView issuedToCNameTextView = (TextView) alertDialog.findViewById(R.id.issued_to_cname);
-            TextView issuedToONameTextView = (TextView) alertDialog.findViewById(R.id.issued_to_oname);
-            TextView issuedToUNameTextView = (TextView) alertDialog.findViewById(R.id.issued_to_uname);
-            TextView issuedByCNameTextView = (TextView) alertDialog.findViewById(R.id.issued_by_cname);
-            TextView issuedByONameTextView = (TextView) alertDialog.findViewById(R.id.issued_by_oname);
-            TextView issuedByUNameTextView = (TextView) alertDialog.findViewById(R.id.issued_by_uname);
-            TextView startDateTextView = (TextView) alertDialog.findViewById(R.id.start_date);
-            TextView endDateTextView = (TextView) alertDialog.findViewById(R.id.end_date);
+            TextView domainTextView = alertDialog.findViewById(R.id.domain);
+            TextView issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname);
+            TextView issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname);
+            TextView issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname);
+            TextView issuedByCNameTextView = alertDialog.findViewById(R.id.issued_by_cname);
+            TextView issuedByONameTextView = alertDialog.findViewById(R.id.issued_by_oname);
+            TextView issuedByUNameTextView = alertDialog.findViewById(R.id.issued_by_uname);
+            TextView startDateTextView = alertDialog.findViewById(R.id.start_date);
+            TextView endDateTextView = alertDialog.findViewById(R.id.end_date);
 
             // Setup the labels.
             String domainLabel = getString(R.string.domain_label) + "  ";
diff --git a/app/src/main/res/drawable/about.xml b/app/src/main/res/drawable/about.xml
deleted file mode 100644 (file)
index 8a20c67..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<!-- `about.xml` comes from the Android Material icon set, where it is called `ic_info_outline`.  It is released under the Apache License 2.0. -->
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:width="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0" >
-
-    <!-- We have to use a hard coded color until API >= 21.  Then we can use `@color`. -->
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z" />
-</vector>
diff --git a/app/src/main/res/drawable/about_dark.xml b/app/src/main/res/drawable/about_dark.xml
new file mode 100644 (file)
index 0000000..a1927d7
--- /dev/null
@@ -0,0 +1,13 @@
+<!-- `about_dark.xml` comes from the Android Material icon set, where it is called `ic_info_outline`.  It is released under the Apache License 2.0. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0" >
+
+    <!-- A hard coded color must be used until API >= 21.  Then `@color` may be used. -->
+    <path
+        android:fillColor="#FFE0E0E0"
+        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z" />
+</vector>
diff --git a/app/src/main/res/drawable/about_light.xml b/app/src/main/res/drawable/about_light.xml
new file mode 100644 (file)
index 0000000..1b8a7af
--- /dev/null
@@ -0,0 +1,13 @@
+<!-- `about_light.xml` comes from the Android Material icon set, where it is called `ic_info_outline`.  It is released under the Apache License 2.0. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0" >
+
+    <!-- A hard coded color must be used until API >= 21.  Then `@color` may be used. -->
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z" />
+</vector>
index b113ca727752267e5f4b49276db0123cacc8a207..40e7cc78afaea0a9bbf051984a6bbcb0b56d4692 100644 (file)
@@ -54,7 +54,7 @@
                     android:layout_marginBottom="12dp"
                     android:layout_gravity="bottom"
                     android:src="@drawable/domains"
-                    android:tint="?attr/iconTintColor"
+                    android:tint="?attr/domainSettingsIconTintColor"
                     tools:ignore="contentDescription" />
 
                 <!-- `android.support.design.widget.TextInputLayout` makes the `android:hint` float above the `EditText`. -->
                     android:layout_marginEnd="10dp"
                     android:layout_gravity="center_vertical"
                     android:src="@drawable/user_agent_light"
-                    android:tint="?attr/iconTintColor"
+                    android:tint="?attr/domainSettingsIconTintColor"
                     android:contentDescription="@string/user_agent" />
 
                 <Spinner
                     android:layout_marginEnd="10dp"
                     android:layout_gravity="center_vertical"
                     android:src="@drawable/font_size_light"
-                    android:tint="?attr/iconTintColor"
+                    android:tint="?attr/domainSettingsIconTintColor"
                     android:contentDescription="@string/font_size" />
 
                 <Spinner
index 6f1a839a81e2bb6b698119e1cb0bd825c5a16c74..f58017911a47975939a6ec17895ec044c017982b 100644 (file)
@@ -25,9 +25,8 @@
     android:layout_height="match_parent"
     android:layout_width="match_parent" >
 
-    <!-- `android:fitsSystemWindows="true"` moves `root_coordinatorlayout` below the system status bar.
-         When it is specified, the theme should include `<item name="android:windowTranslucentStatus">true</item>`.
-         Setting the layout root to be `focusableInTouchMode` prevents `urlTextBox` from stealing focus on launch and opening the keyboard. -->
+    <!-- `android:fitsSystemWindows="true"` moves `root_coordinatorlayout` below the system status bar. When it is specified, the theme should include `<item name="android:windowTranslucentStatus">true</item>`.
+         Setting the CoordinatorLayout to be `focusableInTouchMode` prevents the URL text box from stealing focus on launch and opening the keyboard. -->
     <android.support.design.widget.CoordinatorLayout
         android:id="@+id/root_coordinatorlayout"
         xmlns:tools="http://schemas.android.com/tools"
 
                     <!-- `android:max` changes the maximum `ProgressBar` value from 10000 to 100 to match progress percentage.
                         `android:layout_height="2dp"` works best for API >= 23, but `3dp` is required for visibility on API <= 22.
-                        `tools:ignore="UnusedAttribute"` removes the lint waring about `progressTint` and `progressBackgroundTint` not applying to API < 21. -->
+                        `tools:ignore="UnusedAttribute"` removes the lint warning about `progressTint` and `progressBackgroundTint` not applying to API < 21. -->
                     <ProgressBar
                         android:id="@+id/progress_bar"
                         style="?android:attr/progressBarStyleHorizontal"
-                        android:layout_width="fill_parent"
                         android:layout_height="3dp"
+                        android:layout_width="match_parent"
                         android:layout_gravity="bottom"
                         android:max="100"
                         android:progressTint="?attr/progressTintColor"
index 3a1dfc4eec2391f2fe7fc89ad518baeee13a5146..a7397c3508f09192a107cbca5127f121b659108f 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>.
 
@@ -27,8 +27,7 @@
     android:layout_width="match_parent"
     tools:context=".activities.MainWebViewActivity" >
 
-    <!-- Set `@drawable/world` as the initial `favoriteIcon`.
-        `layout_height` and `layout_width` of 26dp matches the `AppBar` icons. -->
+    <!-- Set `@drawable/world` as the initial as the initial favorite icon.  `layout_height` and `layout_width` of 26dp matches the `AppBar` icons. -->
     <ImageView
         android:id="@+id/favorite_icon"
         android:src="@drawable/world"
@@ -39,8 +38,7 @@
         android:onClick="viewSslCertificate"
         android:contentDescription="@string/favorite_icon" />
 
-    <!-- `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`. -->
+    <!-- `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:id="@+id/url_edittext"
         android:layout_height="wrap_content"
diff --git a/app/src/main/res/layout/view_source_app_bar.xml b/app/src/main/res/layout/view_source_app_bar.xml
new file mode 100644 (file)
index 0000000..4f957a3
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright © 2015-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/>. -->
+
+<!-- `RelativeLayout` is used instead of a `LinearLayout` because `supportAppBar` does not let `android:layout_weight="1"` cause `urlTextBox` to fill all the available space. -->
+<RelativeLayout
+    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"
+    tools:context=".activities.ViewSourceActivity" >
+
+    <ImageView
+        android:id="@+id/back_arrow"
+        android:src="@drawable/back"
+        android:tint="?attr/viewSourceIconTintColor"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginEnd="14dp"
+        android:contentDescription="@string/back"
+        android:onClick="goBack" />
+
+    <!-- `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:id="@+id/url_edittext"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_toEndOf="@id/back_arrow"
+        android:hint="@string/url"
+        android:imeOptions="actionGo"
+        android:inputType="textUri"
+        android:selectAllOnFocus="true" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_source_coordinatorlayout.xml b/app/src/main/res/layout/view_source_coordinatorlayout.xml
new file mode 100644 (file)
index 0000000..71a7667
--- /dev/null
@@ -0,0 +1,151 @@
+<?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/>. -->
+
+<!-- `android:fitsSystemWindows="true"` moves the AppBar below the status bar.  When it is specified the theme should include `<item name="android:windowTranslucentStatus">true</item>` to make the status bar a transparent, darkened overlay.
+    Setting the layout root to be `focusableInTouchMode` prevents the URL toolbar from stealing focus on launch and opening the keyboard. -->
+<android.support.design.widget.CoordinatorLayout
+    android:id="@+id/view_source_coordinatorlayout"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.stoutner.privacybrowser.activities.ViewSourceActivity"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:fitsSystemWindows="true"
+    android:focusable="true"
+    android:focusableInTouchMode="true" >
+
+    <!-- The `LinearLayout` with `orientation="vertical"` moves the content below the app bar layout. -->
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:orientation="vertical" >
+
+        <!-- The `AppBarLayout` theme has to be defined here because the activity uses a `NoActionBar` theme. -->
+        <android.support.design.widget.AppBarLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:theme="@style/PrivacyBrowserAppBarLight" >
+
+            <!-- The `FrameLayout` allows the toolbar and the progress bar to occupy the same space. -->
+            <FrameLayout
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent" >
+
+                <android.support.v7.widget.Toolbar
+                    android:id="@+id/view_source_toolbar"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent" />
+
+                <!-- Android automatically uses a different, skinnier drawable with padding for indeterminate horizontal progress bars in API >= 21.  They make this very difficult to override.  https://redmine.stoutner.com/issues/241
+                `tools:ignore="UnusedAttribute"` removes the lint warning about `progressTint` and `progressBackgroundTint` not applying to API < 21. -->
+                <ProgressBar
+                    android:id="@+id/progress_bar"
+                    style="?android:attr/progressBarStyleHorizontal"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:minHeight="3dp"
+                    android:layout_gravity="bottom"
+                    android:progressTint="?attr/progressTintColor"
+                    android:progressBackgroundTint="@color/transparent"
+                    android:visibility="gone"
+                    tools:ignore="UnusedAttribute" />
+            </FrameLayout>
+        </android.support.design.widget.AppBarLayout>
+
+        <ScrollView
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent" >
+
+            <LinearLayout
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:orientation="vertical"
+                android:layout_margin="10dp" >
+
+                <!-- Request headers. -->
+                <TextView
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:text="@string/request_headers"
+                    android:textAlignment="center"
+                    android:textSize="18sp"
+                    android:textColor="@color/blue_600"
+                    android:textStyle="bold" />
+
+                <TextView
+                    android:id="@+id/request_headers"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:textIsSelectable="true"
+                    android:layout_marginBottom="8dp" />
+
+                <!-- Response message. -->
+                <TextView
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:text="@string/response_message"
+                    android:textAlignment="center"
+                    android:textSize="18sp"
+                    android:textColor="@color/blue_600"
+                    android:textStyle="bold" />
+
+                <TextView
+                    android:id="@+id/response_message"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:textIsSelectable="true"
+                    android:layout_marginBottom="8dp" />
+
+                <!-- Response headers. -->
+                <TextView
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:text="@string/response_headers"
+                    android:textAlignment="center"
+                    android:textSize="18sp"
+                    android:textColor="@color/blue_600"
+                    android:textStyle="bold" />
+
+                <TextView
+                    android:id="@+id/response_headers"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:textIsSelectable="true"
+                    android:layout_marginBottom="8dp" />
+
+                <!-- Response body. -->
+                <TextView
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:text="@string/response_body"
+                    android:textAlignment="center"
+                    android:textSize="18sp"
+                    android:textColor="@color/blue_600"
+                    android:textStyle="bold" />
+
+                <TextView
+                    android:id="@+id/response_body"
+                    android:layout_height="wrap_content"
+                    android:layout_width="match_parent"
+                    android:textIsSelectable="true" />
+            </LinearLayout>
+        </ScrollView>
+    </LinearLayout>
+</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
index e5bf25cfb91daf43e4a2bb60b6b0fa259cb2cf29..176c1bcc231cbefba5c301f3b1dc142bccdd9cda 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>.
 
@@ -22,6 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
+    <!-- `android:iconTint` can be used once API >= 26 instead of including a separate drawable for each theme. -->
     <item
         android:id="@+id/options_menu_select_all_bookmarks"
         android:title="@string/select_all"
diff --git a/app/src/main/res/menu/view_source_options_menu.xml b/app/src/main/res/menu/view_source_options_menu.xml
new file mode 100644 (file)
index 0000000..ec50f16
--- /dev/null
@@ -0,0 +1,32 @@
+<?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/>. -->
+
+<menu
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <!-- `android:iconTint` can be used once API >= 26 instead of including a separate drawable for each theme. -->
+    <item
+        android:id="@+id/about_view_source"
+        android:title="@string/about"
+        android:orderInCategory="10"
+        android:icon="?attr/aboutIcon"
+        app:showAsAction="ifRoom" />
+</menu>
\ No newline at end of file
index 4063ba2c563c1b2f19bd4ff9d0c59d7a7f0d56ad..eb30116cd4b0287f9ff7a29663fa83533bf9a0fa 100644 (file)
@@ -79,7 +79,7 @@
         <item
             android:id="@+id/about"
             android:title="@string/about"
-            android:icon="@drawable/about"
+            android:icon="@drawable/about_light"
             android:orderInCategory="90" />
     </group>
 
index 2761db63311a974255169c1dc31d9ee163d0c29a..a468a001224e8c321476332d987d560e9cbe99a9 100644 (file)
         android:orderInCategory="120"
         app:showAsAction="never" />
 
+    <item
+        android:id="@+id/view_source"
+        android:title="@string/view_source"
+        android:orderInCategory="130"
+        app:showAsAction="never" />
+
     <item
         android:id="@+id/add_to_homescreen"
         android:title="@string/add_to_home_screen"
-        android:orderInCategory="130"
+        android:orderInCategory="140"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/refresh"
         android:title="@string/refresh"
-        android:orderInCategory="140"
+        android:orderInCategory="150"
         app:showAsAction="never" />
 </menu>
\ No newline at end of file
index e6544ce10884cc2532e4b34aaeacf8540a0dd1cf..dd6710b41c78b2d8bf568b9304f6e08e356c2b31 100644 (file)
 
     <attr name="progressTintColor" format="reference" />
     <attr name="navigationIconTintColor" format="reference" />
-
     <attr name="findOnPageIconTintColor" format="reference" />
+    <attr name="domainSettingsIconTintColor" format="reference" />
+    <attr name="viewSourceIconTintColor" format="reference" />
 
     <attr name="listSelectorDrawable" format="reference" />
 
-    <attr name="iconTintColor" format="reference" />
-
     <attr name="userAgentIcon" format="reference" />
     <attr name="searchIcon" format="reference" />
     <attr name="homepageIcon" format="reference" />
@@ -60,4 +59,5 @@
     <attr name="selectAllIcon" format="reference" />
     <attr name="editIcon" format="reference" />
     <attr name="moveToFolderIcon" format="reference" />
+    <attr name="aboutIcon" format="reference" />
 </resources>
\ No newline at end of file
index 8b7f03a6f7e4e9043c5aaf1ca979ed73197827b5..960b3af97b4b84f91d24616da802b3dea6a986e5 100644 (file)
     <string name="share">Share</string>
     <string name="find_on_page">Find on Page</string>
     <string name="print">Print</string>
+    <string name="view_source">View Source</string>
     <string name="add_to_home_screen">Add to Home Screen</string>
         <string name="privacy_browser_web_page">Privacy Browser Web Page</string>
     <string name="refresh">Refresh</string>
     <string name="previous">Previous</string>
     <string name="next">Next</string>
 
+    <!-- View Source. -->
+    <string name="request_headers">Request Headers</string>
+    <string name="response_message">Response Message</string>
+    <string name="response_headers">Response Headers</string>
+    <string name="response_body">Response Body</string>
+    <string name="error_body">Error Body</string>
+    <string name="about_view_source">About View Source</string>
+    <string name="about_view_source_message">Because Android’s WebView does not expose the source information, a separate request was made using system tools to gather the information displayed in this activity.
+        There may be some differences between this data and that used by the WebView in the main activity. This limitation will be removed in the 4.x series with the release of Privacy WebView.</string>
+
     <!-- Create Home Screen Shortcut Alert Dialog. -->
     <string name="create_shortcut">Create Shortcut</string>
     <string name="shortcut_name">Shortcut name</string>
index 8f9c5939b5116e029d0f6f0c5a5cd1d783e5e089..45f624971f2fbcca267d9ef0728c89ee0793f4b9 100644 (file)
         <item name="progressTintColor">@color/blue_700</item>
         <item name="navigationIconTintColor">@color/blue_800</item>
         <item name="findOnPageIconTintColor">@color/blue_800</item>
+        <item name="viewSourceIconTintColor">@color/black</item>
         <item name="sslHeader">@color/blue_700</item>
         <item name="sslTitle">@color/blue_900</item>
         <item name="urlHistoryText">@color/black</item>
         <item name="redText">@color/red_a700</item>
+        <item name="aboutIcon">@drawable/about_light</item>
         <item name="dialogTabLayoutTheme">@style/PrivacyBrowserTabLayoutDialogLight</item>
     </style>
 
@@ -54,7 +56,7 @@
         <item name="aboutTitle">@color/blue_900</item>
         <item name="aboutText">@color/blue_700</item>
         <item name="aboutBackground">@color/white</item>
-        <item name="iconTintColor">@color/blue_800</item>
+        <item name="domainSettingsIconTintColor">@color/blue_800</item>
         <item name="deleteIcon">@drawable/delete_light</item>
         <item name="addIcon">@drawable/add_light</item>
         <item name="addBookmarkIcon">@drawable/create_bookmark_light</item>
         <item name="colorAccent">@color/blue_700</item>
     </style>
 
+    <style name="PrivacyBrowserProgressBar" parent="Widget.AppCompat.ProgressBar.Horizontal" >
+        <item name="android:indeterminateDrawable">@android:drawable/progress_horizontal</item>
+    </style>
+
 
     <!-- Dark theme styles. -->
 
         <item name="progressTintColor">@color/blue_600</item>
         <item name="navigationIconTintColor">@color/blue_600</item>
         <item name="findOnPageIconTintColor">@color/blue_600</item>
+        <item name="viewSourceIconTintColor">@color/gray_300</item>
         <item name="sslHeader">@color/blue_400</item>
         <item name="sslTitle">@color/blue_700</item>
         <item name="urlHistoryText">@color/gray_200</item>
         <item name="redText">@color/red_900</item>
+        <item name="aboutIcon">@drawable/about_dark</item>
     </style>
 
     <!-- `windowActionModeOverlay` makes the contextual app bar cover the support app bar.  `colorPrimaryDark` goes behind the status bar, which is then darkened by the overlay.-->
         <item name="aboutText">@color/blue_400</item>
         <item name="aboutBackground">@color/gray_850</item>
         <item name="listSelectorDrawable">@drawable/list_selector_dark</item>
-        <item name="iconTintColor">@color/blue_600</item>
+        <item name="domainSettingsIconTintColor">@color/blue_600</item>
         <item name="deleteIcon">@drawable/delete_dark</item>
         <item name="addIcon">@drawable/add_dark</item>
         <item name="addBookmarkIcon">@drawable/create_bookmark_dark</item>
diff --git a/fastlane/metadata/android/en/images/phoneScreenshots/02-Full Screen-TranslucentBars.png b/fastlane/metadata/android/en/images/phoneScreenshots/02-Full Screen-TranslucentBars.png
deleted file mode 100644 (file)
index ba3a6aa..0000000
Binary files a/fastlane/metadata/android/en/images/phoneScreenshots/02-Full Screen-TranslucentBars.png and /dev/null differ
diff --git a/fastlane/metadata/android/en/images/phoneScreenshots/02-FullScreen-TranslucentBars.png b/fastlane/metadata/android/en/images/phoneScreenshots/02-FullScreen-TranslucentBars.png
new file mode 100644 (file)
index 0000000..ba3a6aa
Binary files /dev/null and b/fastlane/metadata/android/en/images/phoneScreenshots/02-FullScreen-TranslucentBars.png differ