mobile/android/modules/HelperApps.jsm

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 "use strict";
     6 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
     8 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
     9 Cu.import("resource://gre/modules/Services.jsm");
    10 Cu.import("resource://gre/modules/Prompt.jsm");
    11 Cu.import("resource://gre/modules/Messaging.jsm");
    13 XPCOMUtils.defineLazyGetter(this, "ContentAreaUtils", function() {
    14   let ContentAreaUtils = {};
    15   Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", ContentAreaUtils);
    16   return ContentAreaUtils;
    17 });
    19 this.EXPORTED_SYMBOLS = ["App","HelperApps"];
    21 function App(data) {
    22   this.name = data.name;
    23   this.isDefault = data.isDefault;
    24   this.packageName = data.packageName;
    25   this.activityName = data.activityName;
    26   this.iconUri = "-moz-icon://" + data.packageName;
    27 }
    29 App.prototype = {
    30   // callback will be null if a result is not requested
    31   launch: function(uri, callback) {
    32     HelperApps._launchApp(this, uri, callback);
    33     return false;
    34   }
    35 }
    37 var HelperApps =  {
    38   get defaultBrowsers() {
    39     delete this.defaultBrowsers;
    40     this.defaultBrowsers = this._getHandlers("http://www.example.com", {
    41       filterBrowsers: false,
    42       filterHtml: false
    43     });
    44     return this.defaultBrowsers;
    45   },
    47   // Finds handlers that have registered for text/html pages or urls ending in html. Some apps, like
    48   // the Samsung Video player will only appear for these urls, while some Browsers (like Link Bubble)
    49   // won't register here because of the text/html mime type.
    50   get defaultHtmlHandlers() {
    51     delete this.defaultHtmlHandlers;
    52     return this.defaultHtmlHandlers = this._getHandlers("http://www.example.com/index.html", {
    53       filterBrowsers: false,
    54       filterHtml: false
    55     });
    56   },
    58   _getHandlers: function(url, options) {
    59     let values = {};
    61     let handlers = this.getAppsForUri(Services.io.newURI(url, null, null), options);
    62     handlers.forEach(function(app) {
    63       values[app.name] = app;
    64     }, this);
    66     return values;
    67   },
    69   get protoSvc() {
    70     delete this.protoSvc;
    71     return this.protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
    72   },
    74   get urlHandlerService() {
    75     delete this.urlHandlerService;
    76     return this.urlHandlerService = Cc["@mozilla.org/uriloader/external-url-handler-service;1"].getService(Ci.nsIExternalURLHandlerService);
    77   },
    79   prompt: function showPicker(apps, promptOptions, callback) {
    80     let p = new Prompt(promptOptions).addIconGrid({ items: apps });
    81     p.show(callback);
    82   },
    84   getAppsForProtocol: function getAppsForProtocol(scheme) {
    85     let protoHandlers = this.protoSvc.getProtocolHandlerInfoFromOS(scheme, {}).possibleApplicationHandlers;
    87     let results = {};
    88     for (let i = 0; i < protoHandlers.length; i++) {
    89       try {
    90         let protoApp = protoHandlers.queryElementAt(i, Ci.nsIHandlerApp);
    91         results[protoApp.name] = new App({
    92           name: protoApp.name,
    93           description: protoApp.detailedDescription,
    94         });
    95       } catch(e) {}
    96     }
    98     return results;
    99   },
   101   getAppsForUri: function getAppsForUri(uri, flags = { }, callback) {
   102     flags.filterBrowsers = "filterBrowsers" in flags ? flags.filterBrowsers : true;
   103     flags.filterHtml = "filterHtml" in flags ? flags.filterHtml : true;
   105     // Query for apps that can/can't handle the mimetype
   106     let msg = this._getMessage("Intent:GetHandlers", uri, flags);
   107     let parseData = (d) => {
   108       let apps = []
   110       if (!d)
   111         return apps;
   113       apps = this._parseApps(d.apps);
   115       if (flags.filterBrowsers) {
   116         apps = apps.filter((app) => {
   117           return app.name && !this.defaultBrowsers[app.name];
   118         });
   119       }
   121       // Some apps will register for html files (the Samsung Video player) but should be shown
   122       // for non-HTML files (like videos). This filters them only if the page has an htm of html
   123       // file extension.
   124       if (flags.filterHtml) {
   125         // Matches from the first '.' to the end of the string, '?', or '#'
   126         let ext = /\.([^\?#]*)/.exec(uri.path);
   127         if (ext && (ext[1] === "html" || ext[1] === "htm")) {
   128           apps = apps.filter(function(app) {
   129             return app.name && !this.defaultHtmlHandlers[app.name];
   130           }, this);
   131         }
   132       }
   134       return apps;
   135     };
   137     if (!callback) {
   138       let data = this._sendMessageSync(msg);
   139       if (!data)
   140         return [];
   141       return parseData(data);
   142     } else {
   143       sendMessageToJava(msg, function(data) {
   144         callback(parseData(data));
   145       });
   146     }
   147   },
   149   launchUri: function launchUri(uri) {
   150     let msg = this._getMessage("Intent:Open", uri);
   151     sendMessageToJava(msg);
   152   },
   154   _parseApps: function _parseApps(appInfo) {
   155     // appInfo -> {apps: [app1Label, app1Default, app1PackageName, app1ActivityName, app2Label, app2Defaut, ...]}
   156     // see GeckoAppShell.java getHandlersForIntent function for details
   157     const numAttr = 4; // 4 elements per ResolveInfo: label, default, package name, activity name.
   159     let apps = [];
   160     for (let i = 0; i < appInfo.length; i += numAttr) {
   161       apps.push(new App({"name" : appInfo[i],
   162                  "isDefault" : appInfo[i+1],
   163                  "packageName" : appInfo[i+2],
   164                  "activityName" : appInfo[i+3]}));
   165     }
   167     return apps;
   168   },
   170   _getMessage: function(type, uri, options = {}) {
   171     let mimeType = options.mimeType;
   172     if (uri && mimeType == undefined)
   173       mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
   175     return {
   176       type: type,
   177       mime: mimeType,
   178       action: options.action || "", // empty action string defaults to android.intent.action.VIEW
   179       url: uri ? uri.spec : "",
   180       packageName: options.packageName || "",
   181       className: options.className || ""
   182     };
   183   },
   185   _launchApp: function launchApp(app, uri, callback) {
   186     if (callback) {
   187         let msg = this._getMessage("Intent:OpenForResult", uri, {
   188             packageName: app.packageName,
   189             className: app.activityName
   190         });
   192         sendMessageToJava(msg, function(data) {
   193             callback(data);
   194         });
   195     } else {
   196         let msg = this._getMessage("Intent:Open", uri, {
   197             packageName: app.packageName,
   198             className: app.activityName
   199         });
   201         sendMessageToJava(msg);
   202     }
   203   },
   205   _sendMessageSync: function(msg) {
   206     let res = null;
   207     sendMessageToJava(msg, function(data) {
   208       res = data;
   209     });
   211     let thread = Services.tm.currentThread;
   212     while (res == null)
   213       thread.processNextEvent(true);
   215     return res;
   216   },
   217 };

mercurial