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; +]> + + + + &aboutApps.title; + + + + + + + +
+
&aboutApps.title;
+ +
+
+
+
+
+
+ + diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 8ed16910d9e..b094c43f642 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -1263,7 +1263,9 @@ var NativeWindow = { let popupNode = aEvent.originalTarget; let title = ""; - if ((popupNode instanceof Ci.nsIDOMHTMLAnchorElement && popupNode.href) || + if (popupNode.hasAttribute("title")) { + title = popupNode.getAttribute("title") + } else if ((popupNode instanceof Ci.nsIDOMHTMLAnchorElement && popupNode.href) || (popupNode instanceof Ci.nsIDOMHTMLAreaElement && popupNode.href)) { title = this._getLinkURL(popupNode); } else if (popupNode instanceof Ci.nsIImageLoadingContent && popupNode.currentURI) { diff --git a/mobile/android/chrome/jar.mn b/mobile/android/chrome/jar.mn index e20c9826f8d..05457fcc22a 100644 --- a/mobile/android/chrome/jar.mn +++ b/mobile/android/chrome/jar.mn @@ -10,6 +10,8 @@ chrome.jar: content/aboutCertError.xhtml (content/aboutCertError.xhtml) content/aboutHome.xhtml (content/aboutHome.xhtml) * content/aboutRights.xhtml (content/aboutRights.xhtml) +* content/aboutApps.xhtml (content/aboutApps.xhtml) + content/aboutApps.js (content/aboutApps.js) content/blockedSite.xhtml (content/blockedSite.xhtml) content/languages.properties (content/languages.properties) * content/browser.xul (content/browser.xul) diff --git a/mobile/android/components/AboutRedirector.js b/mobile/android/components/AboutRedirector.js index 1d1c7ecca18..cbf4f68c5e9 100644 --- a/mobile/android/components/AboutRedirector.js +++ b/mobile/android/components/AboutRedirector.js @@ -85,6 +85,10 @@ let modules = { home: { uri: "chrome://browser/content/aboutHome.xhtml", privileged: true + }, + apps: { + uri: "chrome://browser/content/aboutApps.xhtml", + privileged: true } } diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest index 81173e7ddc7..d575b29d2d2 100644 --- a/mobile/android/components/MobileComponents.manifest +++ b/mobile/android/components/MobileComponents.manifest @@ -7,6 +7,7 @@ contract @mozilla.org/network/protocol/about;1?what=empty {322ba47e-7047-4f71-ae contract @mozilla.org/network/protocol/about;1?what=rights {322ba47e-7047-4f71-aebf-cb7d69325cd9} contract @mozilla.org/network/protocol/about;1?what=certerror {322ba47e-7047-4f71-aebf-cb7d69325cd9} contract @mozilla.org/network/protocol/about;1?what=home {322ba47e-7047-4f71-aebf-cb7d69325cd9} +contract @mozilla.org/network/protocol/about;1?what=apps {322ba47e-7047-4f71-aebf-cb7d69325cd9} #ifdef MOZ_SAFE_BROWSING contract @mozilla.org/network/protocol/about;1?what=blocked {322ba47e-7047-4f71-aebf-cb7d69325cd9} #endif diff --git a/mobile/android/locales/en-US/chrome/aboutApps.dtd b/mobile/android/locales/en-US/chrome/aboutApps.dtd new file mode 100644 index 00000000000..c7ea6d37ce8 --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutApps.dtd @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/aboutApps.properties b/mobile/android/locales/en-US/chrome/aboutApps.properties new file mode 100644 index 00000000000..86d5a7c049d --- /dev/null +++ b/mobile/android/locales/en-US/chrome/aboutApps.properties @@ -0,0 +1,2 @@ +appsContext.uninstall=Uninstall +appsContext.shortcut=Add to Home Screen diff --git a/mobile/android/locales/jar.mn b/mobile/android/locales/jar.mn index 7e1fb7a88eb..ff6eb31ef9c 100644 --- a/mobile/android/locales/jar.mn +++ b/mobile/android/locales/jar.mn @@ -5,6 +5,8 @@ locale/@AB_CD@/browser/about.dtd (%chrome/about.dtd) locale/@AB_CD@/browser/aboutAddons.dtd (%chrome/aboutAddons.dtd) locale/@AB_CD@/browser/aboutAddons.properties (%chrome/aboutAddons.properties) + locale/@AB_CD@/browser/aboutApps.dtd (%chrome/aboutApps.dtd) + locale/@AB_CD@/browser/aboutApps.properties (%chrome/aboutApps.properties) locale/@AB_CD@/browser/aboutCertError.dtd (%chrome/aboutCertError.dtd) locale/@AB_CD@/browser/browser.properties (%chrome/browser.properties) locale/@AB_CD@/browser/config.dtd (%chrome/config.dtd) diff --git a/mobile/android/themes/core/aboutApps.css b/mobile/android/themes/core/aboutApps.css new file mode 100644 index 00000000000..f10b351d53f --- /dev/null +++ b/mobile/android/themes/core/aboutApps.css @@ -0,0 +1,43 @@ + +html { + font-family: "Droid Sans",helvetica,arial,clean,sans-serif; + font-size: 18px; + background-image: url("chrome://browser/skin/images/about-bg-lightblue.png"); + -moz-text-size-adjust: none; +} + +#main-container { + margin: 1em; + padding: 1em; + border-radius: 10px; + border: 1px solid grey; + background-color: white; +} + +.spacer { + clear: both; +} + +.app { + float: left; + cursor: pointer; + text-align: center; + margin: 1em; + width: 70px; + height: 85px; + font-size: 10px; +} + +.app img { + width: 64px; + height: 64px; +} + +#noapps { + padding: 1em; + text-align: center; +} + +.hidden { + display: none; +} diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn index 4b308be2c87..9d912de5ceb 100644 --- a/mobile/android/themes/core/jar.mn +++ b/mobile/android/themes/core/jar.mn @@ -5,6 +5,7 @@ chrome.jar: skin/aboutPage.css (aboutPage.css) skin/about.css (about.css) skin/aboutAddons.css (aboutAddons.css) + skin/aboutApps.css (aboutApps.css) * skin/browser.css (browser.css) * skin/content.css (content.css) skin/config.css (config.css)