gecko/mobile/android/chrome/content/HelperApps.js
2013-08-23 16:28:00 -07:00

193 lines
6.0 KiB
JavaScript

/* 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/. */
"use strict";
XPCOMUtils.defineLazyGetter(this, "ContentAreaUtils", function() {
let ContentAreaUtils = {};
Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", ContentAreaUtils);
return ContentAreaUtils;
});
function getBridge() {
return Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
}
function sendMessageToJava(aMessage) {
return getBridge().handleGeckoMessage(JSON.stringify(aMessage));
}
var HelperApps = {
get defaultHttpHandlers() {
let protoHandlers = this.getAppsForProtocol("http");
var results = {};
for (var i = 0; i < protoHandlers.length; i++) {
try {
let protoApp = protoHandlers.queryElementAt(i, Ci.nsIHandlerApp);
results[protoApp.name] = protoApp;
} catch(e) {}
}
delete this.defaultHttpHandlers;
return this.defaultHttpHandlers = results;
},
get protoSvc() {
delete this.protoSvc;
return this.protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
},
get urlHandlerService() {
delete this.urlHandlerService;
return this.urlHandlerService = Cc["@mozilla.org/uriloader/external-url-handler-service;1"].getService(Ci.nsIExternalURLHandlerService);
},
getAppsForProtocol: function getAppsForProtocol(uri) {
let handlerInfoProto = this.protoSvc.getProtocolHandlerInfoFromOS(uri, {});
return handlerInfoProto.possibleApplicationHandlers;
},
getAppsForUri: function getAppsFor(uri) {
let found = [];
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
// empty action string defaults to android.intent.action.VIEW
let msg = {
type: "Intent:GetHandlers",
mime: mimeType,
action: "",
url: uri.spec,
packageName: "",
className: ""
};
let apps = this._parseApps(JSON.parse(sendMessageToJava(msg)));
for (let i = 0; i < apps.length; i++) {
let appName = apps[i].name;
if (appName.length > 0 && !this.defaultHttpHandlers[appName])
found.push(apps[i]);
}
return found;
},
updatePageAction: function setPageAction(uri) {
let apps = this.getAppsForUri(uri);
if (apps.length > 0)
this._setPageActionFor(uri, apps);
else
this._removePageAction();
},
_setPageActionFor: function setPageActionFor(uri, apps) {
this._pageActionUri = uri;
// If the pageaction is already added, simply update the URI to be launched when 'onclick' is triggered.
if (this._pageActionId != undefined)
return;
this._pageActionId = NativeWindow.pageactions.add({
title: Strings.browser.GetStringFromName("openInApp.pageAction"),
icon: "drawable://icon_openinapp",
clickCallback: function() {
if (apps.length == 1)
this._launchApp(apps[0], this._pageActionUri);
else
this.openUriInApp(this._pageActionUri);
}.bind(this)
});
},
_removePageAction: function removePageAction() {
if(!this._pageActionId)
return;
NativeWindow.pageactions.remove(this._pageActionId);
delete this._pageActionId;
},
_launchApp: function launchApp(appData, uri) {
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
let msg = {
type: "Intent:Open",
mime: mimeType,
action: "android.intent.action.VIEW",
url: uri.spec,
packageName: appData.packageName,
className: appData.activityName
};
sendMessageToJava(msg);
},
openUriInApp: function openUriInApp(uri) {
let mimeType = ContentAreaUtils.getMIMETypeForURI(uri) || "";
let msg = {
type: "Intent:Open",
mime: mimeType,
action: "",
url: uri.spec,
packageName: "",
className: ""
};
sendMessageToJava(msg);
},
_parseApps: function _parseApps(aJSON) {
// aJSON -> {apps: [app1Label, app1Default, app1PackageName, app1ActivityName, app2Label, app2Defaut, ...]}
// see GeckoAppShell.java getHandlersForIntent function for details
let appInfo = aJSON.apps;
const numAttr = 4; // 4 elements per ResolveInfo: label, default, package name, activity name.
let apps = [];
for (let i = 0; i < appInfo.length; i += numAttr) {
apps.push({"name" : appInfo[i],
"isDefault" : appInfo[i+1],
"packageName" : appInfo[i+2],
"activityName" : appInfo[i+3]});
}
return apps;
},
showDoorhanger: function showDoorhanger(aUri, aCallback) {
let permValue = Services.perms.testPermission(aUri, "native-intent");
if (permValue != Services.perms.UNKNOWN_ACTION) {
if (permValue == Services.perms.ALLOW_ACTION) {
if (aCallback)
aCallback(aUri);
else
this.openUriInApp(aUri);
} else if (permValue == Services.perms.DENY_ACTION) {
// do nothing
}
return;
}
let apps = this.getAppsForUri(aUri);
let strings = Strings.browser;
let message = "";
if (apps.length == 1)
message = strings.formatStringFromName("helperapps.openWithApp2", [apps[0].name], 1);
else
message = strings.GetStringFromName("helperapps.openWithList2");
let buttons = [{
label: strings.GetStringFromName("helperapps.open"),
callback: function(aChecked) {
if (aChecked)
Services.perms.add(aUri, "native-intent", Ci.nsIPermissionManager.ALLOW_ACTION);
if (aCallback)
aCallback(aUri);
else
this.openUriInApp(aUri);
}
}, {
label: strings.GetStringFromName("helperapps.ignore"),
callback: function(aChecked) {
if (aChecked)
Services.perms.add(aUri, "native-intent", Ci.nsIPermissionManager.DENY_ACTION);
}
}];
let options = { checkbox: Strings.browser.GetStringFromName("helperapps.dontAskAgain") };
NativeWindow.doorhanger.show(message, "helperapps-open", buttons, BrowserApp.selectedTab.id, options);
}
};