Bug 1362994 - Implement browsingData.settings WebExtension API method on android. r?sebastian, mattw, bsilverberg draft
authorTushar Saini (:shatur) <tushar.saini1285@gmail.com>
Fri, 02 Jun 2017 23:11:49 +0530
changeset 612461 0896dbee652baa4c68b997fbf9ba8c45635ed765
parent 612460 d3472721f508c2fa90f018d58976edaa4d85b773
child 638402 518269b67f8af081695f2d01140c53a020301c5e
push id69491
push userbmo:tushar.saini1285@gmail.com
push dateThu, 20 Jul 2017 17:47:35 +0000
reviewerssebastian, mattw, bsilverberg
bugs1362994
milestone56.0a1
Bug 1362994 - Implement browsingData.settings WebExtension API method on android. r?sebastian, mattw, bsilverberg MozReview-Commit-ID: G9frPBFPHCT
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/chrome.ini
mobile/android/components/extensions/test/mochitest/test_ext_browsingData_settings.html
--- 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,57 @@
+/* -*- 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 returning settings.
+          const PREF_LIST = ["cache", "history", "formdata", "cookies_sessions", "downloadFiles"];
+
+          let dataTrue = SharedPreferences.forProfile().getSetPref(PREF_DOMAIN);
+          let name;
+
+          let dataToRemove = {};
+          let dataRemovalPermitted = {};
+
+          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.includes(`${PREF_KEY_PREFIX}${item}`);
+            // Firefox doesn't have the same concept of dataRemovalPermitted
+            // as Chrome, so it will always be true.
+            dataRemovalPermitted[name] = true;
+          }
+          // We do not provide option to delete history by time
+          // so, since value is given 0, which means Everything
+          return Promise.resolve({options: {since: 0}, 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
--- a/mobile/android/components/extensions/test/mochitest/chrome.ini
+++ b/mobile/android/components/extensions/test/mochitest/chrome.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   head.js
   ../../../../../../toolkit/components/extensions/test/mochitest/chrome_cleanup_script.js
 tags = webextensions
 
 [test_ext_browserAction_getTitle_setTitle.html]
 [test_ext_browserAction_onClicked.html]
+[test_ext_browsingData_settings.html]
 [test_ext_pageAction_show_hide.html]
 [test_ext_pageAction_getPopup_setPopup.html]
 skip-if = os == 'android' # bug 1373170
new file mode 100644
--- /dev/null
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_browsingData_settings.html
@@ -0,0 +1,101 @@
+<!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, actualValue, prefs, prefSuffix) {
+  let prefValue = prefs.includes(`${PREF_KEY_PREFIX}${prefSuffix}`);
+  is(actualValue, prefValue, `${key} property of dataToRemove matches the expected pref.`);
+}
+
+function testSettingsPreferences(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(async function testSettings() {
+  function background() {
+    browser.test.onMessage.addListener(async (msg) => {
+      if (msg == "retrieve-settings") {
+        let settings = await browser.browsingData.settings();
+        browser.test.sendMessage("settings", settings);
+      }
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      "permissions": ["browsingData"],
+    },
+  });
+
+  await extension.startup();
+
+  extension.sendMessage("retrieve-settings");
+  let {options, dataToRemove, dataRemovalPermitted} = await extension.awaitMessage("settings");
+
+  // Verify that we get the keys we expect.
+  is(SETTINGS_LIST.length, Object.keys(dataToRemove).length, `dataToRemove contains expected no of keys`);
+  is(SETTINGS_LIST.length, Object.keys(dataRemovalPermitted).length, `dataRemovalPermitted contains expected no of keys`);
+  for (let key of SETTINGS_LIST) {
+    is(true, dataRemovalPermitted[key],
+      `${key} property of dataRemovalPermitted matches the expected value.`);
+  }
+
+  // Verify values of dataToRemove keys are as expected.
+  testSettingsPreferences(dataToRemove);
+
+  // 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(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("retrieve-settings");
+  let settings = await extension.awaitMessage("settings");
+  testSettingsPreferences(settings.dataToRemove);
+
+  await extension.unload();
+});
+</script>
+
+</body>
+</html>
\ No newline at end of file