Bug 1362994 - Implement browsingData.settings WebExtension API method on android. r?sebastian, mattw draft
authorTushar Saini (:shatur) <tushar.saini1285@gmail.com>
Fri, 02 Jun 2017 23:11:49 +0530
changeset 609584 01f2fca93f48cfcbae58b15e7ca75cf8fe005a26
parent 609583 bbfd2e65ca88899282fba245cedee3ca2875618e
child 609585 8297595fa19c5ee558c8ac6c14d19d7514eade55
child 609586 b53b372acd00a321709fbeed2402b2fa7aba2e03
push id68586
push userbmo:tushar.saini1285@gmail.com
push dateSun, 16 Jul 2017 20:47:21 +0000
reviewerssebastian, mattw
bugs1362994
milestone56.0a1
Bug 1362994 - Implement browsingData.settings WebExtension API method on android. r?sebastian, mattw MozReview-Commit-ID: G9frPBFPHCT
mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java
mobile/android/components/extensions/ext-android.js
mobile/android/components/extensions/ext-browsingData.js
mobile/android/components/extensions/jar.mn
mobile/android/components/extensions/schemas/browsing_data.json
mobile/android/components/extensions/schemas/jar.mn
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_settings.html
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/MultiPrefMultiChoicePreference.java
@@ -49,17 +49,17 @@ class MultiPrefMultiChoicePreference ext
 
     // Overridden to do a one time import for the old preference type to the new one.
     @Override
     protected synchronized void loadPersistedValues() {
         // This will load the new pref if it exists.
         super.loadPersistedValues();
 
         // First check if we've already done the import the old data. If so, nothing to load.
-        final SharedPreferences prefs = GeckoSharedPrefs.forApp(getContext());
+        final SharedPreferences prefs = GeckoSharedPrefs.forProfile(getContext());
         final boolean imported = getPersistedBoolean(prefs, getKey() + IMPORT_SUFFIX, false);
         if (imported) {
             return;
         }
 
         // Load the data we'll need to find the old style prefs
         final CharSequence[] init = getInitialValues();
         final CharSequence[] entries = getEntries();
--- a/mobile/android/components/extensions/ext-android.js
+++ b/mobile/android/components/extensions/ext-android.js
@@ -54,16 +54,25 @@ extensions.registerModules({
     url: "chrome://browser/content/ext-browserAction.js",
     schema: "chrome://browser/content/schemas/browser_action.json",
     scopes: ["addon_parent"],
     manifest: ["browser_action"],
     paths: [
       ["browserAction"],
     ],
   },
+  browsingData: {
+    url: "chrome://browser/content/ext-browsingData.js",
+    schema: "chrome://browser/content/schemas/browsing_data.json",
+    scopes: ["addon_parent"],
+    manifest: ["browsing_data"],
+    paths: [
+      ["browsingData"],
+    ],
+  },
   pageAction: {
     url: "chrome://browser/content/ext-pageAction.js",
     schema: "chrome://browser/content/schemas/page_action.json",
     scopes: ["addon_parent"],
     manifest: ["page_action"],
     paths: [
       ["pageAction"],
     ],
new file mode 100644
--- /dev/null
+++ b/mobile/android/components/extensions/ext-browsingData.js
@@ -0,0 +1,60 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+Cu.import("resource://gre/modules/Task.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+                                  "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences",
+                                  "resource://gre/modules/SharedPreferences.jsm");
+
+this.browsingData = class extends ExtensionAPI {
+  getAPI(context) {
+    return {
+      browsingData: {
+        settings() {
+          const PREF_DOMAIN = "android.not_a_preference.privacy.clear";
+          const PREF_KEY_PREFIX = "private.data.";
+          // The following prefs are the only ones in Firefox that match corresponding
+          // values used by Chrome when rerturning settings.
+          const PREF_LIST = ["cache", "history", "formdata", "cookies_sessions", "downloadFiles"];
+
+          let dataToRemove = {};
+          let dataRemovalPermitted = {};
+
+          // We do not provide option to delete history by time
+          // so, since value is given 0, which means Everything
+          let since = 0;
+          let dataTrue = SharedPreferences.forProfile().getSetPref(PREF_DOMAIN);
+          let options = {since};
+          let name;
+
+          for (let item of PREF_LIST) {
+            // The property formData needs a different case than the
+            // formdata preference.
+            switch(item){
+              case "formdata":
+                name = "formData";
+                break;
+              case "cookies_sessions":
+                name = "cookies";
+                break;
+              case "downloadFiles":
+                name = "downloads";
+                break;
+              default:
+                name = item;
+            }
+            dataToRemove[name] = dataTrue.indexOf(`${PREF_KEY_PREFIX}${item}`) > -1;
+            // Firefox doesn't have the same concept of dataRemovalPermitted
+            // as Chrome, so it will always be true.
+            dataRemovalPermitted[name] = true;
+          }
+
+          return Promise.resolve({options, dataToRemove, dataRemovalPermitted});
+        },
+      },
+    };
+  }
+};
\ No newline at end of file
--- a/mobile/android/components/extensions/jar.mn
+++ b/mobile/android/components/extensions/jar.mn
@@ -2,11 +2,12 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 chrome.jar:
     content/ext-android.js
     content/ext-c-android.js
     content/ext-c-tabs.js
     content/ext-browserAction.js
+    content/ext-browsingData.js
     content/ext-pageAction.js
     content/ext-tabs.js
     content/ext-utils.js
copy from browser/components/extensions/schemas/browsing_data.json
copy to mobile/android/components/extensions/schemas/browsing_data.json
--- a/browser/components/extensions/schemas/browsing_data.json
+++ b/mobile/android/components/extensions/schemas/browsing_data.json
@@ -157,16 +157,17 @@
           }
         ]
       },
       {
         "name": "remove",
         "description": "Clears various types of browsing data stored in a user's profile.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "dataToRemove",
             "$ref": "DataTypeSet",
@@ -201,16 +202,17 @@
           }
         ]
       },
       {
         "name": "removeCache",
         "description": "Clears the browser's cache.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -220,16 +222,17 @@
           }
         ]
       },
       {
         "name": "removeCookies",
         "description": "Clears the browser's cookies and server-bound certificates modified within a particular timeframe.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -239,16 +242,17 @@
           }
         ]
       },
       {
         "name": "removeDownloads",
         "description": "Clears the browser's list of downloaded files (<em>not</em> the downloaded files themselves).",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -278,16 +282,17 @@
           }
         ]
       },
       {
         "name": "removeFormData",
         "description": "Clears the browser's stored form data (autofill).",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -297,16 +302,17 @@
           }
         ]
       },
       {
         "name": "removeHistory",
         "description": "Clears the browser's history.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -356,16 +362,17 @@
           }
         ]
       },
       {
         "name": "removePluginData",
         "description": "Clears plugins' data.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
@@ -375,16 +382,17 @@
           }
         ]
       },
       {
         "name": "removePasswords",
         "description": "Clears the browser's stored passwords.",
         "type": "function",
         "async": "callback",
+        "unsupported": true,
         "parameters": [
           {
             "$ref": "RemovalOptions",
             "name": "options"
           },
           {
             "name": "callback",
             "type": "function",
--- a/mobile/android/components/extensions/schemas/jar.mn
+++ b/mobile/android/components/extensions/schemas/jar.mn
@@ -1,8 +1,9 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 chrome.jar:
     content/schemas/browser_action.json
+    content/schemas/browsing_data.json
     content/schemas/page_action.json
     content/schemas/tabs.json
new file mode 100644
--- /dev/null
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_settings.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>BrowsingData Settings test</title>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
+  <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+var {SharedPreferences} = Cu.import("resource://gre/modules/SharedPreferences.jsm", {});
+
+const PREF_DOMAIN = "android.not_a_preference.privacy.clear";
+const PREF_KEY_PREFIX = "private.data.";
+const SETTINGS_LIST = ["cache", "cookies", "history", "formData", "downloads"];
+
+function checkPrefs(key, dataToRemove, prefs, PREF_SUFFIX) {
+  let PREF_VALUE = prefs.indexOf(`${PREF_KEY_PREFIX}${PREF_SUFFIX}`) > -1;
+  is(dataToRemove, PREF_VALUE, `${key} property of dataToRemove matches the expected pref.`);
+}
+
+function testSettingsPrefrences(dataToRemove){
+  let prefs = SharedPreferences.forProfile().getSetPref(PREF_DOMAIN);
+
+  for (let key of Object.keys(dataToRemove)) {
+    switch(key){
+      case "formData":
+        checkPrefs(key, dataToRemove[key], prefs, "formdata");
+        break;
+      case "cookies":
+        checkPrefs(key, dataToRemove[key], prefs, "cookies_sessions");
+        break;
+      case "downloads":
+        checkPrefs(key, dataToRemove[key], prefs, "downloadFiles");
+        break;
+      default:
+        checkPrefs(key, dataToRemove[key], prefs, key);
+    }
+  }
+}
+
+add_task(function* testSettings() {
+  function background() {
+    browser.test.onMessage.addListener(msg => {
+      browser.browsingData.settings().then(settings => {
+        browser.test.sendMessage("settings", settings);
+      });
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      "permissions": ["browsingData"],
+    },
+  });
+
+  yield extension.startup();
+
+  extension.sendMessage("settings");
+  let settings = yield extension.awaitMessage("settings");
+  let dataToRemove = settings.dataToRemove;
+  let dataRemovalPermitted = settings.dataRemovalPermitted;
+
+  // Verify that we get the keys we expect.
+  for (let key in SETTINGS_LIST) {
+    ok(key in Object.keys(dataToRemove), `dataToRemove contains expected property.`);
+    ok(key in Object.keys(dataRemovalPermitted), `dataRemovalPermitted contains expected property.`);
+  }
+
+  // Verify values of keys are as expected.
+  testSettingsPrefrences(dataToRemove);
+
+  for (let key of Object.keys(dataRemovalPermitted)) {
+    is(true, dataRemovalPermitted[key],
+      `${key} property of dataRemovalPermitted matches the expected pref.`);
+  }
+
+  // Verify object options returned as expected.
+  // For now, We do not provide option to delete history by time, so,
+  // since value is given 0, which means Everything.
+  is(settings.options.since, 0, `options contains expected value.`);
+
+  // Explicitly set some prefs to true
+  const NEW_PREFS = ["private.data.cache", "private.data.cookies_sessions"];
+
+  SharedPreferences.forProfile().setSetPref(PREF_DOMAIN, NEW_PREFS);
+
+  extension.sendMessage("settings");
+  settings = yield extension.awaitMessage("settings");
+  testSettingsPrefrences(settings.dataToRemove);
+
+  yield extension.unload();
+});
+</script>
+
+</body>
+</html>
\ No newline at end of file