Add option to remove Google Analytics from URLs. https://redmine.stoutner.com/issues/414
authorSoren Stoutner <soren@stoutner.com>
Wed, 8 May 2019 22:04:01 +0000 (15:04 -0700)
committerSoren Stoutner <soren@stoutner.com>
Wed, 8 May 2019 22:04:01 +0000 (15:04 -0700)
27 files changed:
.idea/assetWizardSettings.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/assets/ru/about_licenses_dark.html
app/src/main/assets/ru/about_licenses_light.html
app/src/main/assets/shared_images/link_off_dark.png [new file with mode: 0644]
app/src/main/assets/shared_images/link_off_light.png [new file with mode: 0644]
app/src/main/assets/tr/about_licenses_dark.html
app/src/main/assets/tr/about_licenses_light.html
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java
app/src/main/java/com/stoutner/privacybrowser/fragments/SettingsFragment.java
app/src/main/res/drawable/modify_url_disabled_dark.xml [new file with mode: 0644]
app/src/main/res/drawable/modify_url_disabled_light.xml [new file with mode: 0644]
app/src/main/res/drawable/modify_url_enabled_dark.xml [new file with mode: 0644]
app/src/main/res/drawable/modify_url_enabled_light.xml [new file with mode: 0644]
app/src/main/res/drawable/more_disabled_dark.xml
app/src/main/res/drawable/more_disabled_light.xml
app/src/main/res/drawable/more_enabled_dark.xml
app/src/main/res/drawable/more_enabled_light.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/preferences.xml

index e1c83ef..1db0cae 100644 (file)
                         </option>
                         <option name="values">
                           <map>
+                            <entry key="assetSourceType" value="FILE" />
                             <entry key="autoMirrored" value="true" />
-                            <entry key="outputName" value="tab" />
-                            <entry key="sourceFile" value="$USER_HOME$/ownCloud/Android/Privacy Browser/Icons/Icons/file_copy_light.svg" />
+                            <entry key="outputName" value="modify_url" />
+                            <entry key="sourceFile" value="$USER_HOME$/ownCloud/Android/Privacy Browser/Icons/Icons/link_off_light.svg" />
                           </map>
                         </option>
                       </PersistentState>
index aaaac72..86b8293 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 69b7a2d..e156dcb 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
index 0283e5b..2efa366 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 2a0b87a..8da7e03 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
index 27318b7..117dd36 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 97b70bf..b2e078a 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
index 4e01d4f..231f25a 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 320d866..f31976f 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
index 1ca17ea..a7c1bbe 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 7f90a11..9304d2b 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
diff --git a/app/src/main/assets/shared_images/link_off_dark.png b/app/src/main/assets/shared_images/link_off_dark.png
new file mode 100644 (file)
index 0000000..2d80b53
Binary files /dev/null and b/app/src/main/assets/shared_images/link_off_dark.png differ
diff --git a/app/src/main/assets/shared_images/link_off_light.png b/app/src/main/assets/shared_images/link_off_light.png
new file mode 100644 (file)
index 0000000..d85bfc6
Binary files /dev/null and b/app/src/main/assets/shared_images/link_off_light.png differ
index 627b822..aa4fc54 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_dark.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_dark.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_dark.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_dark.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_dark.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_dark.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_dark.png"> location_off.</p>
index 8876b9d..fbe184b 100644 (file)
         <p><img class="icon" src="../shared_images/important_devices_light.png"> important_devices.</p>
         <p><img class="icon" src="../shared_images/info_outline_light.png"> info_outline.</p>
         <p><img class="icon" src="../shared_images/language_light.png"> language.</p>
+        <p><img class="icon" src="../shared_images/link_off_light.png"> link_off.</p>
         <p><img class="icon" src="../shared_images/list_light.png"> list.</p>
         <p><img class="icon" src="../shared_images/local_activity_light.png"> local_activity.</p>
         <p><img class="icon" src="../shared_images/location_off_light.png"> location_off.</p>
index df7cef4..7900b06 100644 (file)
@@ -279,6 +279,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     // The swipe refresh layout top padding is used when exiting full screen browsing mode.  It is used in an inner class in `initializeWebView()`.
     private int swipeRefreshLayoutPaddingTop;
 
+    // The URL sanitizers are set in `applyAppSettings()` and used in `sanitizeUrl()`.
+    private boolean sanitizeGoogleAnalytics;
+
     // The download strings are used in `onCreate()`, `onRequestPermissionResult()` and `initializeWebView()`.
     private String downloadUrl;
     private String downloadContentDisposition;
@@ -2999,6 +3002,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
     }
 
     private void loadUrl(String url) {
+        // Sanitize the URL.
+        url = sanitizeUrl(url);
+
         // Apply the domain settings.
         applyDomainSettings(currentWebView, url, true, false);
 
@@ -3053,6 +3059,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         // Store the values from the shared preferences in variables.
         incognitoModeEnabled = sharedPreferences.getBoolean("incognito_mode", false);
         boolean doNotTrackEnabled = sharedPreferences.getBoolean("do_not_track", false);
+        sanitizeGoogleAnalytics = sharedPreferences.getBoolean("google_analytics", true);
         proxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
         fullScreenBrowsingModeEnabled = sharedPreferences.getBoolean("full_screen_browsing_mode", false);
         hideAppBar = sharedPreferences.getBoolean("hide_app_bar", true);
@@ -3959,12 +3966,33 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
         startActivity(openWithBrowserIntent);
     }
 
+    private String sanitizeUrl(String url) {
+        // Sanitize Google Analytics.
+        if (sanitizeGoogleAnalytics) {
+            // Remove `?utm_`.
+            if (url.contains("?utm_")) {
+                url = url.substring(0, url.indexOf("?utm_"));
+            }
+
+            // Remove `&utm_`.
+            if (url.contains("&utm_")) {
+                url = url.substring(0, url.indexOf("&utm_"));
+            }
+        }
+
+        // Return the sanitized URL.
+        return url;
+    }
+
     public void addTab(View view) {
         // Add a new tab with a blank URL.
         addNewTab("");
     }
 
     private void addNewTab(String url) {
+        // Sanitize the URL.
+        url = sanitizeUrl(url);
+
         // Get a handle for the tab layout and the view pager.
         TabLayout tabLayout = findViewById(R.id.tablayout);
         ViewPager webViewPager = findViewById(R.id.webviewpager);
@@ -4770,6 +4798,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook
             // The deprecated `shouldOverrideUrlLoading` must be used until API >= 24.
             @Override
             public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                // Sanitize the url.
+                url = sanitizeUrl(url);
+
                 if (url.startsWith("http")) {  // Load the URL in Privacy Browser.
                     // Apply the domain settings for the new URL.  This doesn't do anything if the domain has not changed.
                     boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false);
index 35956e9..37225fb 100644 (file)
@@ -60,7 +60,7 @@ public class SettingsFragment extends PreferenceFragment {
         Preference firstPartyCookiesPreference = findPreference("first_party_cookies");
         Preference thirdPartyCookiesPreference = findPreference("third_party_cookies");
         Preference domStoragePreference = findPreference("dom_storage");
-        Preference saveFormDataPreference = findPreference("save_form_data");  // The form data preference can be removed once the minimum API >= 26.
+        Preference formDataPreference = findPreference("save_form_data");  // The form data preference can be removed once the minimum API >= 26.
         Preference userAgentPreference = findPreference("user_agent");
         Preference customUserAgentPreference = findPreference("custom_user_agent");
         Preference incognitoModePreference = findPreference("incognito_mode");
@@ -72,6 +72,7 @@ public class SettingsFragment extends PreferenceFragment {
         Preference fanboySocialBlockingListPreference = findPreference("fanboys_social_blocking_list");
         Preference ultraPrivacyPreference = findPreference("ultraprivacy");
         Preference blockAllThirdPartyRequestsPreference = findPreference("block_all_third_party_requests");
+        Preference googleAnalyticsPreference = findPreference("google_analytics");
         Preference proxyThroughOrbotPreference = findPreference("proxy_through_orbot");
         Preference torHomepagePreference = findPreference("tor_homepage");
         Preference torSearchPreference = findPreference("tor_search");
@@ -130,7 +131,7 @@ public class SettingsFragment extends PreferenceFragment {
             PreferenceCategory clearAndExitCategory = (PreferenceCategory) findPreference("clear_and_exit");
 
             // Remove the form data preferences.
-            privacyCategory.removePreference(saveFormDataPreference);
+            privacyCategory.removePreference(formDataPreference);
             clearAndExitCategory.removePreference(clearFormDataPreference);
         }
 
@@ -288,12 +289,12 @@ public class SettingsFragment extends PreferenceFragment {
         // Set the save form data icon if API < 26.  Save form data has no effect on API >= 26.
         if (Build.VERSION.SDK_INT < 26) {
             if (savedPreferences.getBoolean("save_form_data", false)) {
-                saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
+                formDataPreference.setIcon(R.drawable.form_data_enabled);
             } else {
                 if (darkTheme) {
-                    saveFormDataPreference.setIcon(R.drawable.form_data_disabled_dark);
+                    formDataPreference.setIcon(R.drawable.form_data_disabled_dark);
                 } else {
-                    saveFormDataPreference.setIcon(R.drawable.form_data_disabled_light);
+                    formDataPreference.setIcon(R.drawable.form_data_disabled_light);
                 }
             }
         }
@@ -457,6 +458,21 @@ public class SettingsFragment extends PreferenceFragment {
             }
         }
 
+        // Set the Google Analytics icons according to the theme.
+        if (savedPreferences.getBoolean("google_analytics", true)) {
+            if (darkTheme) {
+                googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled_dark);
+            } else {
+                googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled_light);
+            }
+        } else {
+            if (darkTheme) {
+                googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled_dark);
+            } else {
+                googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled_light);
+            }
+        }
+
         // Set the Tor icons according to the theme.
         if (proxyThroughOrbot) {  // Proxying is enabled.
             if (darkTheme) {
@@ -829,12 +845,12 @@ public class SettingsFragment extends PreferenceFragment {
                 case "save_form_data":
                     // Update the icon.
                     if (sharedPreferences.getBoolean("save_form_data", false)) {
-                        saveFormDataPreference.setIcon(R.drawable.form_data_enabled);
+                        formDataPreference.setIcon(R.drawable.form_data_enabled);
                     } else {
                         if (darkTheme) {
-                            saveFormDataPreference.setIcon(R.drawable.form_data_disabled_dark);
+                            formDataPreference.setIcon(R.drawable.form_data_disabled_dark);
                         } else {
-                            saveFormDataPreference.setIcon(R.drawable.form_data_disabled_light);
+                            formDataPreference.setIcon(R.drawable.form_data_disabled_light);
                         }
                     }
                     break;
@@ -1110,6 +1126,23 @@ public class SettingsFragment extends PreferenceFragment {
                     }
                     break;
 
+                case "google_analytics":
+                    // Update the icon.
+                    if (sharedPreferences.getBoolean("google_analytics", true)) {
+                        if (darkTheme) {
+                            googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled_dark);
+                        } else {
+                            googleAnalyticsPreference.setIcon(R.drawable.modify_url_enabled_light);
+                        }
+                    } else {
+                        if (darkTheme) {
+                            googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled_dark);
+                        } else {
+                            googleAnalyticsPreference.setIcon(R.drawable.modify_url_disabled_light);
+                        }
+                    }
+                    break;
+
                 case "proxy_through_orbot":
                     // Get current settings.
                     boolean currentProxyThroughOrbot = sharedPreferences.getBoolean("proxy_through_orbot", false);
diff --git a/app/src/main/res/drawable/modify_url_disabled_dark.xml b/app/src/main/res/drawable/modify_url_disabled_dark.xml
new file mode 100644 (file)
index 0000000..907eeec
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `modify_url_disabled_dark.xml` comes from the Android Material icon set, where it is called `link_off`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:autoMirrored="true"
+    tools:ignore="VectorRaster" >
+
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
+    <path
+        android:fillColor="#FF9E9E9E"
+        android:pathData="M17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1 0,1.43 -0.98,2.63 -2.31,2.98l1.46,1.46C20.88,15.61 22,13.95 22,12c0,-2.76 -2.24,-5 -5,-5zM16,11h-2.19l2,2L16,13zM2,4.27l3.11,3.11C3.29,8.12 2,9.91 2,12c0,2.76 2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1 0,-1.59 1.21,-2.9 2.76,-3.07L8.73,11L8,11v2h2.73L13,15.27L13,17h1.73l4.01,4L20,19.74 3.27,3 2,4.27z"/>
+</vector>
diff --git a/app/src/main/res/drawable/modify_url_disabled_light.xml b/app/src/main/res/drawable/modify_url_disabled_light.xml
new file mode 100644 (file)
index 0000000..a8f2b29
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `modify_url_disabled_light.xml` comes from the Android Material icon set, where it is called `link_off`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:autoMirrored="true"
+    tools:ignore="VectorRaster" >
+
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
+    <path
+        android:fillColor="#FF757575"
+        android:pathData="M17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1 0,1.43 -0.98,2.63 -2.31,2.98l1.46,1.46C20.88,15.61 22,13.95 22,12c0,-2.76 -2.24,-5 -5,-5zM16,11h-2.19l2,2L16,13zM2,4.27l3.11,3.11C3.29,8.12 2,9.91 2,12c0,2.76 2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1 0,-1.59 1.21,-2.9 2.76,-3.07L8.73,11L8,11v2h2.73L13,15.27L13,17h1.73l4.01,4L20,19.74 3.27,3 2,4.27z"/>
+</vector>
diff --git a/app/src/main/res/drawable/modify_url_enabled_dark.xml b/app/src/main/res/drawable/modify_url_enabled_dark.xml
new file mode 100644 (file)
index 0000000..7bcd082
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `modify_url_enabled_dark.xml` comes from the Android Material icon set, where it is called `link_off`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:autoMirrored="true"
+    tools:ignore="VectorRaster" >
+
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
+    <path
+        android:fillColor="#FF1E88E5"
+        android:pathData="M17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1 0,1.43 -0.98,2.63 -2.31,2.98l1.46,1.46C20.88,15.61 22,13.95 22,12c0,-2.76 -2.24,-5 -5,-5zM16,11h-2.19l2,2L16,13zM2,4.27l3.11,3.11C3.29,8.12 2,9.91 2,12c0,2.76 2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1 0,-1.59 1.21,-2.9 2.76,-3.07L8.73,11L8,11v2h2.73L13,15.27L13,17h1.73l4.01,4L20,19.74 3.27,3 2,4.27z"/>
+</vector>
diff --git a/app/src/main/res/drawable/modify_url_enabled_light.xml b/app/src/main/res/drawable/modify_url_enabled_light.xml
new file mode 100644 (file)
index 0000000..8f5c094
--- /dev/null
@@ -0,0 +1,18 @@
+<!-- `modify_url_enabled_light.xml` comes from the Android Material icon set, where it is called `link_off`.  It is released under the Apache License 2.0. -->
+
+<!-- `tools:ignore="VectorRaster"` removes the lint warning about `android:autoMirrored="true"` not applying to API < 21. -->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:autoMirrored="true"
+    tools:ignore="VectorRaster" >
+
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
+    <path
+        android:fillColor="#FF1565C0"
+        android:pathData="M17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1 0,1.43 -0.98,2.63 -2.31,2.98l1.46,1.46C20.88,15.61 22,13.95 22,12c0,-2.76 -2.24,-5 -5,-5zM16,11h-2.19l2,2L16,13zM2,4.27l3.11,3.11C3.29,8.12 2,9.91 2,12c0,2.76 2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1 0,-1.59 1.21,-2.9 2.76,-3.07L8.73,11L8,11v2h2.73L13,15.27L13,17h1.73l4.01,4L20,19.74 3.27,3 2,4.27z"/>
+</vector>
index c877d9b..ca98677 100644 (file)
@@ -11,7 +11,7 @@
     android:viewportWidth="24.0"
     tools:ignore="VectorRaster">
 
-    <!-- We have to use a hard coded color until API >= 21.  Then we can use `@color`. -->
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
     <path
         android:fillColor="#FF9E9E9E"
         android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.97,0.89 1.66,0.89L22,21c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM9,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM14,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
index 7b6c9b5..1ea8021 100644 (file)
@@ -11,7 +11,7 @@
     android:viewportWidth="24.0"
     tools:ignore="VectorRaster">
 
-    <!-- We have to use a hard coded color until API >= 21.  Then we can use `@color`. -->
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
     <path
         android:fillColor="#FF757575"
         android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.97,0.89 1.66,0.89L22,21c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM9,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM14,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
index 4ac5717..d7fcaa5 100644 (file)
@@ -11,7 +11,7 @@
     android:width="24dp"
     tools:ignore="VectorRaster">
 
-    <!-- We have to use a hard coded color until API >= 21.  Then we can use `@color`. -->
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
     <path
         android:fillColor="#FF1E88E5"
         android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.97,0.89 1.66,0.89L22,21c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM9,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM14,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
index b61bf65..0f494c9 100644 (file)
@@ -11,7 +11,7 @@
     android:width="24dp"
     tools:ignore="VectorRaster">
 
-    <!-- We have to use a hard coded color until API >= 21.  Then we can use `@color`. -->
+    <!-- A hard coded color must be used until the minimum API >= 21.  Then `@color` can be used. -->
     <path
         android:fillColor="#FF1565C0"
         android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0,12l5.41,8.11c0.36,0.53 0.97,0.89 1.66,0.89L22,21c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM9,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM14,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM19,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
index c48c937..099857f 100644 (file)
         <string name="ultraprivacy_summary">UltraPrivacy blocks trackers that EasyPrivacy doesn’t because doing so can break websites.</string>
         <string name="block_all_third_party_requests">Block all third-party requests</string>
         <string name="block_all_third_party_requests_summary">Blocking all third-party requests increases privacy, but it breaks many websites.</string>
+    <string name="url_modification">URL Modification</string>
+        <string name="google_analytics">Google Analytics</string>
+        <string name="google_analytics_summary">Remove “?utm_” or “&amp;utm_” and anything after it from URLs.</string>
     <string name="tor">Tor</string>
         <string name="proxy_through_orbot">Proxy through Orbot</string>
         <string name="proxy_through_orbot_summary">Proxy all web traffic through Orbot on localhost:8118.</string>
index af3e7a5..dc8ffcb 100644 (file)
             android:defaultValue="false" />
     </PreferenceCategory>
 
+    <PreferenceCategory
+        android:key="url_modification"
+        android:title="@string/url_modification" >
+
+        <SwitchPreference
+            android:key="google_analytics"
+            android:title="@string/google_analytics"
+            android:summary="@string/google_analytics_summary"
+            android:defaultValue="true" />
+    </PreferenceCategory>
+
     <PreferenceCategory
         android:key="tor"
         android:title="@string/tor" >