diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index 028e4a6a69a..7895b035815 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -485,6 +485,7 @@ pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/beta/faq/"); pref("app.featuresURL", "http://www.mozilla.com/%LOCALE%/mobile/features/"); pref("app.faqURL", "http://www.mozilla.com/%LOCALE%/mobile/faq/"); #endif +pref("app.marketplaceURL", "https://marketplace.mozilla.org/"); // Name of alternate about: page for certificate errors (when undefined, defaults to about:neterror) pref("security.alternate_certificate_error_page", "certerror"); diff --git a/mobile/android/chrome/content/aboutApps.js b/mobile/android/chrome/content/aboutApps.js new file mode 100644 index 00000000000..35884bfb792 --- /dev/null +++ b/mobile/android/chrome/content/aboutApps.js @@ -0,0 +1,160 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * 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/. + * + * ***** END LICENSE BLOCK ***** */ + +let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils; + +Cu.import("resource://gre/modules/Services.jsm") +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Webapps.jsm"); + +let gStrings = Services.strings.createBundle("chrome://browser/locale/aboutApps.properties"); + +XPCOMUtils.defineLazyGetter(window, "gChromeWin", function() + window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow) + .QueryInterface(Ci.nsIDOMChromeWindow)); + +var AppsUI = { + uninstall: null, + shortcut: null +}; + +function onLoad(aEvent) { + try { + let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter); + let link = document.getElementById("marketplaceURL"); + let url = formatter.formatURLPref(link.getAttribute("pref")); + link.setAttribute("href", url); + } catch (e) {} + + navigator.mozApps.mgmt.oninstall = onInstall; + navigator.mozApps.mgmt.onuninstall = onUninstall; + updateList(); + + let contextmenus = gChromeWin.NativeWindow.contextmenus; + AppsUI.shortcut = contextmenus.add(gStrings.GetStringFromName("appsContext.shortcut"), contextmenus.SelectorContext("div[mozApp]"), + function(aTarget) { + let manifest = aTarget.manifest; + createShortcut(manifest.name, manifest.fullLaunchPath(), manifest.iconURLForSize("64"), "webapp"); + }); + AppsUI.uninstall = contextmenus.add(gStrings.GetStringFromName("appsContext.uninstall"), contextmenus.SelectorContext("div[mozApp]"), + function(aTarget) { + aTarget.app.uninstall(); + }); +} + +function onUnload(aEvent) { + let contextmenus = gChromeWin.NativeWindow.contextmenus; + if (AppsUI.shortcut) + contextmenus.remove(AppsUI.shortcut); + if (AppsUI.uninstall) + contextmenus.remove(AppsUI.uninstall); +} + +function updateList() { + let grid = document.getElementById("appgrid"); + while (grid.lastChild) { + grid.removeChild(grid.lastChild); + } + + let request = navigator.mozApps.mgmt.getAll(); + request.onsuccess = function() { + for (let i = 0; i < request.result.length; i++) + addApplication(request.result[i]); + if (!request.result.length) + document.getElementById("noapps").className = ""; + } +} + +function addApplication(aApp) { + let list = document.getElementById("appgrid"); + let manifest = new DOMApplicationManifest(aApp.manifest, aApp.origin); + + let container = document.createElement("div"); + container.className = "app"; + container.setAttribute("id", "app-" + aApp.origin); + container.setAttribute("mozApp", aApp.origin); + container.setAttribute("title", manifest.name); + + let img = document.createElement("img"); + img.src = manifest.iconURLForSize("64"); + img.setAttribute("title", manifest.name); + + let title = document.createElement("div"); + title.appendChild(document.createTextNode(manifest.name)); + + container.appendChild(img); + container.appendChild(title); + list.appendChild(container); + + container.addEventListener("click", function(aEvent) { + aApp.launch(); + }, false); + container.app = aApp; + container.manifest = manifest; +} + +function onInstall(aEvent) { + let node = document.getElementById("app-" + aEvent.application.origin); + if (node) + return; + + addApplication(aEvent.application); + document.getElementById("noapps").className = "hidden"; +} + +function onUninstall(aEvent) { + let node = document.getElementById("app-" + aEvent.application.origin); + if (node) { + let parent = node.parentNode; + parent.removeChild(node); + if (!parent.firstChild) + document.getElementById("noapps").className = ""; + } +} + +function createShortcut(aTitle, aURL, aIconURL, aType) { + // The background images are 72px, but Android will resize as needed. + // Bigger is better than too small. + const kIconSize = 72; + const kOverlaySize = 32; + const kOffset = 20; + + let canvas = document.createElement("canvas"); + + function _createShortcut() { + let icon = canvas.toDataURL("image/png", ""); + canvas = null; + try { + let shell = Cc["@mozilla.org/browser/shell-service;1"].createInstance(Ci.nsIShellService); + shell.createShortcut(aTitle, aURL, icon, aType); + } catch(e) { + Cu.reportError(e); + } + } + + canvas.width = canvas.height = kIconSize; + let ctx = canvas.getContext("2d"); + + let favicon = new Image(); + favicon.onload = function() { + // Center the favicon and overlay it on the background + ctx.drawImage(favicon, kOffset, kOffset, kOverlaySize, kOverlaySize); + _createShortcut(); + } + + favicon.onerror = function() { + Cu.reportError("CreateShortcut: favicon image load error"); + } + + favicon.src = aIconURL; +} diff --git a/mobile/android/chrome/content/aboutApps.xhtml b/mobile/android/chrome/content/aboutApps.xhtml new file mode 100644 index 00000000000..310d1ffdd99 --- /dev/null +++ b/mobile/android/chrome/content/aboutApps.xhtml @@ -0,0 +1,46 @@ + + +# ***** BEGIN LICENSE BLOCK ***** +# +# 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/. +# +# ***** END LICENSE BLOCK ***** + + + %htmlDTD; + + %globalDTD; + + %aboutAppsDTD; + + %browserDTD; +]> + + +
+