Add controls for form data. Fixes https://redmine.stoutner.com/issues/29
authorSoren Stoutner <soren@stoutner.com>
Mon, 27 Jun 2016 19:13:02 +0000 (12:13 -0700)
committerSoren Stoutner <soren@stoutner.com>
Mon, 27 Jun 2016 19:13:02 +0000 (12:13 -0700)
.idea/dictionaries/soren.xml
app/build.gradle
app/src/main/assets/guide_local_storage.html
app/src/main/assets/guide_overview.html
app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/SettingsFragment.java
app/src/main/res/menu/menu_options.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/preferences.xml

index b0b4df8f08b52b9da608946317f6055dae1c6570..2fcbda7330b49bbe72b750abdc4f90c2d8f2b4fb 100644 (file)
@@ -26,6 +26,7 @@
       <w>orbot</w>
       <w>panopticlick</w>
       <w>redmine</w>
+      <w>referer</w>
       <w>relativelayout</w>
       <w>robinlinus</w>
       <w>samsung</w>
index ed3da87c482afa54ee5fb4319c51a4b8c930398a..9b770e4e073518d01d7e62f9cf9babb686c26c9a 100644 (file)
@@ -55,5 +55,5 @@ dependencies {
     compile fileTree(dir: 'libs', include: ['*.jar'])
     compile 'com.android.support:design:23.4.0'
     // Only compile com.google.android.gms:play-services-ads for the free version.
-    freeCompile 'com.google.android.gms:play-services-ads:9.0.2'
+    freeCompile 'com.google.android.gms:play-services-ads:9.2.0'
 }
index 07a1eeff0d87408deaca9a420c1aebc5264fdf50..ae110a6b4a92227a8662a132afb0e2659a3351c5 100644 (file)
     the ads is loaded from the third-party broker's server instead of the main server.</p>
 
 <p>Because most of the advertisements on the internet are displayed from only a few brokers, it didn't take long for them to realize
-    that they could set a tracking cookie on the user's device and know every place that user goes.  Every time an ad loads from a broker,
-    the first thing it does it check to see if if the device already has a unique serial number in a tracking cookie.  If it does, it looks up
-    the profile for that serial number and makes a note of the new site.  This is why a user can do a search on one website for a
+    that they could set a tracking cookie on the user's device and know every place that user goes. Every time an ad loads from a broker,
+    the first thing it does it check to see if if the device already has a unique serial number in a tracking cookie. If it does, it looks up
+    the profile for that serial number and makes a note of the new site. This is why a user can do a search on one website for a
     product that they typically don't look for, like walnuts, and then suddenly start seeing advertisements for walnuts on every
     website they visit.</p>
 
-<p>In addition to ad brokers, social media sites discovered they could get in on the action.  A few years ago, the major social media sites
+<p>In addition to ad brokers, social media sites discovered they could get in on the action. A few years ago, the major social media sites
     like Facebook and Twitter convinced a large number of websites that it would be in there best interest to place little social media
-    icons on their pages.  These are not just images.  They contain <a href="https://developers.facebook.com/docs/plugins/like-button/">imbedded code</a> that
+    icons on their pages. These are not just images. They contain <a href="https://developers.facebook.com/docs/plugins/like-button/">imbedded code</a> that
     links back to the social media site, and, among other things, loads a third-party cookie on the device.  These cookies are placed even if the user does
     not have an account with the social media platform. Over time, companies like Facebook (which also run an ad network) have built up quite a large number
     of detailed profiles about people who have <a href="http://www.theverge.com/2016/5/27/11795248/facebook-ad-network-non-users-cookies-plug-ins">never even
 
 <h3>DOM Storage</h3>
 
-<p>Document Object Model storage, also known as web storage, is like cookies on steroids.  Whereas the maximum combined storage size for all cookies from
+<p>Document Object Model storage, also known as web storage, is like cookies on steroids. Whereas the maximum combined storage size for all cookies from
     a single URL is 4 kilobytes, DOM storage can hold between <a href="https://en.wikipedia.org/wiki/Web_storage#Storage_size">5-25 megabytes per site</a>.
     Because DOM storage uses JavaScript to read and write data, enabling it will do nothing unless JavaScript is also enabled.</p>
+
+
+<h3>Form Data</h3>
+
+<p>Form data contains information typed into web forms, like user names, addresses, phone numbers, etc., and lists them in a drop-down box on future visits.
+    Unlike the other forms of local storage, form data is not sent to the web server without specific user interaction.</p>
 </body>
 </html>
\ No newline at end of file
index 6f7ae182280a280ec5e42f5315f672a626a36dbe..a1c5701eeaf32dd65f6fbd7d4641b45aa31f490f 100644 (file)
@@ -41,7 +41,9 @@
 
 <h3>WebView Limitations</h3>
 
-<p>Privacy Browser uses Android's built-in WebView to render websites.  There are some limitations in the controls WebView exposes for managing privacy settings.
+<p>Privacy Browser uses Android's built-in WebView to render websites.  There are some limitations in the controls WebView exposes for managing privacy settings.  For example,
+    it isn't possible to enable some JavaScript commands while disabling others.  It also isn't possible to control the
+    <a href="https://blog.fastmail.com/2016/06/20/everything-you-could-ever-want-to-know-and-more-about-controlling-the-referer-header/">referer header</a>.
     Once Privacy Browser has matured to take full advantage of all the privacy options WebView does offer, some consideration might be made to imbedding a customized WebView
     or using a different rendering engine.</p>
 </body>
index e4e68c36957255d62865e3dcfb6087cb34722a6e..66fe512e549bf60eeaa4b89efb761aed46c369dd 100644 (file)
@@ -53,6 +53,7 @@ import android.webkit.WebChromeClient;
 import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
+import android.webkit.WebViewDatabase;
 import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -82,6 +83,8 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
     public static boolean thirdPartyCookiesEnabled;
     // domStorageEnabled is public static so it can be accessed from SettingsFragment.  It is also used in onCreate(), onCreateOptionsMenu(), and onOptionsItemSelected().
     public static boolean domStorageEnabled;
+    // saveFormDataEnabled is public static so it can be accessed from SettingsFragment.  It is also used in onCreate(), onCreateOptionsMenu(), and onOptionsItemSelected().
+    public static boolean saveFormDataEnabled;
     // javaScriptDisabledSearchURL is public static so it can be accessed from SettingsFragment.  It is also used in onCreate() and loadURLFromTextBox().
     public static String javaScriptDisabledSearchURL;
     // javaScriptEnabledSearchURL is public static so it can be accessed from SettingsFragment.  It is also used in onCreate() and loadURLFromTextBox().
@@ -321,6 +324,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         domStorageEnabled = savedPreferences.getBoolean("dom_storage_enabled", false);
         mainWebView.getSettings().setDomStorageEnabled(domStorageEnabled);
 
+        // Set the saved form data initial status.  The default is false.
+        saveFormDataEnabled = savedPreferences.getBoolean("save_form_data_enabled", false);
+        mainWebView.getSettings().setSaveFormData(saveFormDataEnabled);
+
         // Set the user agent initial status.
         String userAgentString = savedPreferences.getString("user_agent", "Default user agent");
         switch (userAgentString) {
@@ -427,6 +434,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         MenuItem toggleFirstPartyCookies = menu.findItem(R.id.toggleFirstPartyCookies);
         MenuItem toggleThirdPartyCookies = menu.findItem(R.id.toggleThirdPartyCookies);
         MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage);
+        MenuItem toggleSaveFormData = menu.findItem(R.id.toggleSaveFormData);
 
         // Set the initial status of the privacy icon.
         updatePrivacyIcon();
@@ -435,6 +443,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
         toggleFirstPartyCookies.setChecked(firstPartyCookiesEnabled);
         toggleThirdPartyCookies.setChecked(thirdPartyCookiesEnabled);
         toggleDomStorage.setChecked(domStorageEnabled);
+        toggleSaveFormData.setChecked(saveFormDataEnabled);
 
         return true;
     }
@@ -449,13 +458,18 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
             toggleThirdPartyCookies.setEnabled(false);
         }
 
+        // Enable DOM Storage if JavaScript is enabled.
+        MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage);
+        toggleDomStorage.setEnabled(javaScriptEnabled);
+
         // Enable Clear Cookies if there are any.
         MenuItem clearCookies = menu.findItem(R.id.clearCookies);
         clearCookies.setEnabled(cookieManager.hasCookies());
 
-        // Enable DOM Storage if JavaScript is enabled.
-        MenuItem toggleDomStorage = menu.findItem(R.id.toggleDomStorage);
-        toggleDomStorage.setEnabled(javaScriptEnabled);
+        // Enable Clear Form Data is there is any.
+        MenuItem clearFormData = menu.findItem(R.id.clearFormData);
+        WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(this);
+        clearFormData.setEnabled(mainWebViewDatabase.hasFormData());
 
         // Run all the other default commands.
         super.onPrepareOptionsMenu(menu);
@@ -546,6 +560,20 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 mainWebView.reload();
                 return true;
 
+            case R.id.toggleSaveFormData:
+                // Switch the status of saveFormDataEnabled.
+                saveFormDataEnabled = !saveFormDataEnabled;
+
+                // Update the menu checkbox.
+                menuItem.setChecked(saveFormDataEnabled);
+
+                // Apply the new form data status.
+                mainWebView.getSettings().setSaveFormData(saveFormDataEnabled);
+
+                // Reload the WebView.
+                mainWebView.reload();
+                return true;
+
             case R.id.clearCookies:
                 if (Build.VERSION.SDK_INT < 21) {
                     cookieManager.removeAllCookie();
@@ -561,6 +589,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation
                 Snackbar.make(findViewById(R.id.mainWebView), R.string.dom_storage_deleted, Snackbar.LENGTH_SHORT).show();
                 return true;
 
+            case R.id.clearFormData:
+                WebViewDatabase mainWebViewDatabase = WebViewDatabase.getInstance(this);
+                mainWebViewDatabase.clearFormData();
+                mainWebView.reload();
+                return true;
+
             case R.id.share:
                 Intent shareIntent = new Intent();
                 shareIntent.setAction(Intent.ACTION_SEND);
index 132de65cf031d8e8851645cc55676d50d5a06d94..2afa9e789437830ef7dacf4f2c5c4c5856af33b6 100644 (file)
@@ -189,6 +189,19 @@ public class SettingsFragment extends PreferenceFragment {
                         updatePrivacyIcon();
                         break;
 
+                    case "save_form_data_enabled":
+                        // Set saveFormDataEnabled to the new state.  The default is false.
+                        MainWebViewActivity.saveFormDataEnabled = sharedPreferences.getBoolean("save_form_data_enabled", false);
+
+                        // Update the checkbox in the options menu.
+                        MenuItem saveFormDataMenuItem = MainWebViewActivity.mainMenu.findItem(R.id.toggleSaveFormData);
+                        saveFormDataMenuItem.setChecked(MainWebViewActivity.saveFormDataEnabled);
+
+                        // Update mainWebView and reload the website.
+                        MainWebViewActivity.mainWebView.getSettings().setSaveFormData(MainWebViewActivity.saveFormDataEnabled);
+                        MainWebViewActivity.mainWebView.reload();
+                        break;
+
                     case "user_agent":
                         String userAgentString = sharedPreferences.getString("user_agent", "Default user agent");
 
index 5655644a6d807876953ffe1a89cffeb6aeb59aa8..d380a060227aa65b0a15f725058c5235da9daf52 100644 (file)
         android:checkable="true"
         app:showAsAction="never" />
 
+    <item
+        android:id="@+id/toggleSaveFormData"
+        android:title="@string/form_data"
+        android:orderInCategory="50"
+        android:checkable="true"
+        app:showAsAction="never" />
+
     <item
         android:id="@+id/clearCookies"
         android:title="@string/clear_cookies"
-        android:orderInCategory="50"
+        android:orderInCategory="60"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/clearDomStorage"
         android:title="@string/clear_dom_storage"
-        android:orderInCategory="60"
+        android:orderInCategory="70"
+        app:showAsAction="never" />
+
+    <item
+        android:id="@+id/clearFormData"
+        android:title="@string/clear_form_data"
+        android:orderInCategory="80"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/share"
         android:title="@string/share"
-        android:orderInCategory="70"
+        android:orderInCategory="90"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/addToHomescreen"
         android:title="@string/add_to_home_screen"
-        android:orderInCategory="80"
+        android:orderInCategory="100"
         app:showAsAction="never" />
 
     <item
         android:id="@+id/refresh"
         android:title="@string/refresh"
-        android:orderInCategory="90"
+        android:orderInCategory="110"
         app:showAsAction="never" />
 </menu>
index eaaf2cd75e48ac25104a9a623231719e910dc2d6..eabe4beb9961ad7151d3246f17e1989b896708bc 100644 (file)
     <string name="first_party_cookies">First-Party Cookies</string>
     <string name="third_party_cookies">Third-Party Cookies</string>
     <string name="dom_storage">DOM Storage</string>
+    <string name="form_data">Form Data</string>
     <string name="clear_cookies">Clear Cookies</string>
     <string name="clear_dom_storage">Clear DOM Storage</string>
+    <string name="clear_form_data">Clear Form Data</string>
     <string name="share">Share</string>
     <string name="add_to_home_screen">Add to Home Screen</string>
     <string name="refresh">Refresh</string>
@@ -82,6 +84,8 @@
     <string name="third_party_cookies_summary">This setting requires Android Lollipop (version 5.0) or higher.  It has no effect if first-party cookies are disabled.</string>
     <string name="dom_storage_preference">Enable DOM storage by default</string>
     <string name="dom_storage_preference_summary">JavaScript must be enabled for DOM storage to function.</string>
+    <string name="save_form_data_preference">Enable saving of form data by default</string>
+    <string name="save_form_data_preference_summary">Saved form data can auto-populate fields on websites.</string>
     <string name="user_agent">User agent</string>
     <string-array name="user_agent_entries">
         <item>WebView Default</item>
index e08c71e57c12b5272aedc8bc88423a17940f423b..702db50eb3b5ad2b88cb8235f8c796603f4b4046 100644 (file)
             android:summary="@string/dom_storage_preference_summary"
             android:defaultValue="false" />
 
+        <SwitchPreference
+            android:key="save_form_data_enabled"
+            android:title="@string/save_form_data_preference"
+            android:summary="@string/save_form_data_preference_summary"
+            android:defaultValue="false" />
+
         <ListPreference
             android:key="user_agent"
             android:title="@string/user_agent"