Bug 1267402 - Implement chrome.pageAction.onClicked on Android r?kmag draft
authorMatthew Wein <mwein@mozilla.com>
Fri, 13 May 2016 18:36:06 -0700
changeset 367434 0d5dc3eb654dbaaab9be58d24aded1839fd6fd6e
parent 367433 9426bf3851462c728243b5b5866489805b31e088
child 521012 90a8a79d9815c70137181b94a81d1557660a67c2
push id18241
push usermwein@mozilla.com
push dateMon, 16 May 2016 18:00:49 +0000
reviewerskmag
bugs1267402
milestone49.0a1
Bug 1267402 - Implement chrome.pageAction.onClicked on Android r?kmag MozReview-Commit-ID: 4c8fRhWCJNc
mobile/android/components/extensions/ext-pageAction.js
mobile/android/components/extensions/schemas/page_action.json
mobile/android/components/extensions/test/mochitest/.eslintrc
mobile/android/components/extensions/test/mochitest/head.js
mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
mobile/android/modules/PageActions.jsm
--- a/mobile/android/components/extensions/ext-pageAction.js
+++ b/mobile/android/components/extensions/ext-pageAction.js
@@ -1,29 +1,43 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
+                                  "resource://devtools/shared/event-emitter.js");
+
 // Import the android PageActions module.
 XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
                                   "resource://gre/modules/PageActions.jsm");
 
+Cu.import("resource://gre/modules/ExtensionUtils.jsm");
+
+var {
+  SingletonEventManager,
+} = ExtensionUtils;
+
 // WeakMap[Extension -> PageAction]
 var pageActionMap = new WeakMap();
 
 function PageAction(options, extension) {
   this.id = null;
 
   let DEFAULT_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
 
   this.options = {
     title: options.default_title || extension.name,
     icon: DEFAULT_ICON,
     id: extension.id,
+    clickCallback: () => {
+      this.emit("click");
+    },
   };
+
+  EventEmitter.decorate(this);
 }
 
 PageAction.prototype = {
   show(tabId) {
     // TODO: Only show the PageAction for the tab with the provided tabId.
     if (!this.id) {
       this.id = PageActions.add(this.options);
     }
@@ -49,14 +63,24 @@ extensions.on("shutdown", (type, extensi
     pageActionMap.delete(extension);
   }
 });
 /* eslint-enable mozilla/balanced-listeners */
 
 extensions.registerSchemaAPI("pageAction", null, (extension, context) => {
   return {
     pageAction: {
+      onClicked: new SingletonEventManager(context, "pageAction.onClicked", fire => {
+        let listener = (event) => {
+          fire();
+        };
+        pageActionMap.get(extension).on("click", listener);
+        return () => {
+          pageActionMap.get(extension).off("click", listener);
+        };
+      }).api(),
+
       show(tabId) {
         pageActionMap.get(extension).show(tabId);
       },
     },
   };
 });
--- a/mobile/android/components/extensions/schemas/page_action.json
+++ b/mobile/android/components/extensions/schemas/page_action.json
@@ -207,17 +207,16 @@
             ]
           }
         ]
       }
     ],
     "events": [
       {
         "name": "onClicked",
-        "unsupported": true,
         "type": "function",
         "description": "Fired when a page action icon is clicked.  This event will not fire if the page action has a popup.",
         "parameters": [
           {
             "name": "tab",
             "$ref": "tabs.Tab"
           }
         ]
--- a/mobile/android/components/extensions/test/mochitest/.eslintrc
+++ b/mobile/android/components/extensions/test/mochitest/.eslintrc
@@ -1,7 +1,8 @@
 {
   "extends": "../../../../../../toolkit/components/extensions/test/mochitest/.eslintrc",
 
   "globals": {
     "isPageActionShown": true,
+    "clickPageAction": true,
   },
 }
--- a/mobile/android/components/extensions/test/mochitest/head.js
+++ b/mobile/android/components/extensions/test/mochitest/head.js
@@ -1,11 +1,15 @@
 "use strict";
 
-/* exported isPageActionShown */
+/* exported isPageActionShown clickPageAction */
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/PageActions.jsm");
 
 function isPageActionShown(extensionId) {
   return PageActions.isShown(extensionId);
 }
+
+function clickPageAction(extensionId) {
+  PageActions.synthesizeClick(extensionId);
+}
--- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
+++ b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
@@ -18,17 +18,20 @@ function backgroundScript() {
   browser.test.assertTrue("show" in browser.pageAction, "API method 'show' exists in browser.pageAction");
 
   // TODO: Use the Tabs API to obtain the tab ids for showing pageActions.
   let tabId = 1;
 
   browser.pageAction.show(tabId);
   browser.test.sendMessage("page-action-shown");
 
-  browser.test.notifyPass("page-action");
+  browser.pageAction.onClicked.addListener(tab => {
+    // TODO: Make sure we get the correct tab once the tabs API is supported.
+    browser.test.notifyPass("pageAction-clicked");
+  });
 }
 
 add_task(function* test_contentscript() {
   let extension = ExtensionTestUtils.loadExtension({
     background: "(" + backgroundScript.toString() + ")()",
     manifest: {
       "name": "PageAction Extension",
       "page_action": {
@@ -37,17 +40,19 @@ add_task(function* test_contentscript() 
     },
   });
 
   yield extension.startup();
   yield extension.awaitMessage("page-action-shown");
 
   is(isPageActionShown(extension.id), true, "The PageAction should be shown");
 
-  yield extension.awaitFinish("page-action");
+  clickPageAction(extension.id);
+
+  yield extension.awaitFinish("pageAction-clicked");
   yield extension.unload();
 
   is(isPageActionShown(extension.id), false, "The PageAction should be removed after unload");
 });
 </script>
 
 </body>
 </html>
--- a/mobile/android/modules/PageActions.jsm
+++ b/mobile/android/modules/PageActions.jsm
@@ -26,17 +26,16 @@ function resolveGeckoURI(aURI) {
     return registry.convertChromeURL(Services.io.newURI(aURI, null, null)).spec;
   } else if (aURI.startsWith("resource://")) {
     let handler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
     return handler.resolveURI(Services.io.newURI(aURI, null, null));
   }
   return aURI;
 }
 
-
 var PageActions = {
   _items: { },
 
   _inited: false,
 
   _maybeInit: function() {
     if (!this._inited && Object.keys(this._items).length > 0) {
       this._inited = true;
@@ -65,16 +64,23 @@ var PageActions = {
       }
     }
   },
 
   isShown: function(id) {
     return !!this._items[id];
   },
 
+  synthesizeClick: function(id) {
+    let item = this._items[id];
+    if (item && item.clickCallback) {
+      item.clickCallback();
+    }
+  },
+
   add: function(aOptions) {
     let id = aOptions.id || uuidgen.generateUUID().toString()
 
     Messaging.sendRequest({
       type: "PageActions:Add",
       id: id,
       title: aOptions.title,
       icon: resolveGeckoURI(aOptions.icon),