Bug 590225 - webapps OS level integration for Android a=blocking-fennec, r=mwu,vladimir, blassey
authorFabrice Desré <fabrice@mozilla.com>
Fri, 15 Oct 2010 14:16:45 -0400
changeset 55889 d30d0303cd0f32905151c12ec6457f768e079fa6
parent 55888 156e39355da27624ca6f2b8bc7d703e44d0c640f
child 55890 e226f886e301c7187b93443e711767148b6e3df2
push idunknown
push userunknown
push dateunknown
reviewersblocking-fennec, mwu, vladimir, blassey
bugs590225
milestone2.0b8pre
Bug 590225 - webapps OS level integration for Android a=blocking-fennec, r=mwu,vladimir, blassey
embedding/android/AndroidManifest.xml.in
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
toolkit/components/Makefile.in
toolkit/components/build/Makefile.in
toolkit/components/build/nsToolkitCompsCID.h
toolkit/components/build/nsToolkitCompsModule.cpp
toolkit/components/webapps/Makefile.in
toolkit/components/webapps/nsIWebappsSupport.idl
toolkit/components/webapps/nsWebappsSupport.cpp
toolkit/components/webapps/nsWebappsSupport.h
widget/src/android/AndroidBridge.cpp
widget/src/android/AndroidBridge.h
widget/src/android/nsAppShell.cpp
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -4,19 +4,20 @@
       package="org.mozilla.@MOZ_APP_NAME@"
       android:installLocation="auto"
       android:versionCode="1"
       android:versionName="@MOZ_APP_VERSION@"
       android:sharedUserId="org.mozilla.sharedID">
     <uses-sdk android:minSdkVersion="5"
               android:targetSdkVersion="5"/>
 
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 
-    <uses-permission android:name="android.permission.INTERNET"/> 
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
 
     <application android:label="@MOZ_APP_DISPLAYNAME@"
 		 android:icon="@drawable/icon"
 		 android:debuggable="true">
         <activity android:name="App"
                   android:label="@MOZ_APP_DISPLAYNAME@"
                   android:configChanges="keyboard|keyboardHidden|orientation|mcc|mnc"
                   android:windowSoftInputMode="stateUnspecified|adjustResize"
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -196,16 +196,25 @@ abstract public class GeckoApp
     @Override
     protected void onNewIntent(Intent intent) {
         final String action = intent.getAction();
         if (Intent.ACTION_VIEW.equals(action)) {
             String uri = intent.getDataString();
             GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
             Log.i("GeckoApp","onNewIntent: "+uri);
         }
+        else if (Intent.ACTION_MAIN.equals(action)) {
+            Log.i("GeckoApp", "Intent : ACTION_MAIN");
+            GeckoAppShell.sendEventToGecko(new GeckoEvent(""));
+        }
+        else if (action.equals("org.mozilla.fennec.WEBAPP")) {
+            String uri = intent.getStringExtra("args");
+            GeckoAppShell.sendEventToGecko(new GeckoEvent(uri));
+            Log.i("GeckoApp","Intent : WEBAPP - " + uri);
+        }
     }
 
     @Override
     public void onPause()
     {
 
         Log.i("GeckoApp", "pause");
         GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_PAUSING));
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -358,16 +358,36 @@ class GeckoAppShell
             System.exit(0);
         }
 
     }
     static void scheduleRestart() {
         Log.i("GeckoAppJava", "scheduling restart");
         gRestartScheduled = true;        
     }
+ 
+    // "Installs" an application by creating a shortcut
+    static void installWebApplication(String aURI, String aTitle, String aIconData) {
+        Log.w("GeckoAppJava", "installWebApplication for " + aURI + " [" + aTitle + "]");
+
+        // the intent to be launched by the shortcut
+        Intent shortcutIntent = new Intent("org.mozilla.fennec.WEBAPP");
+        shortcutIntent.setClassName(GeckoApp.mAppContext,
+                                    "org.mozilla." + GeckoApp.mAppContext.getAppName() + ".App");
+        shortcutIntent.putExtra("args", "--webapp=" + aURI);
+        
+        Intent intent = new Intent();
+        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
+        byte[] raw = Base64.decode(aIconData.substring(22), Base64.DEFAULT);
+        Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);
+        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
+        intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
+        GeckoApp.mAppContext.sendBroadcast(intent);
+    }
     
     static String[] getHandlersForMimeType(String aMimeType, String aAction) {
         Intent intent = getIntentForActionString(aAction);
         if (aMimeType != null && aMimeType.length() > 0)
             intent.setType(aMimeType);
         return getHandlersForIntent(intent);
     }
 
--- a/toolkit/components/Makefile.in
+++ b/toolkit/components/Makefile.in
@@ -65,16 +65,17 @@ PARALLEL_DIRS += \
   perf \
   places \
   prompts \
   startup \
   statusfilter \
   typeaheadfind \
   urlformatter \
   viewconfig \
+  webapps \
   $(NULL)
 
 ifdef BUILD_CTYPES
 PARALLEL_DIRS += \
   ctypes \
   $(NULL)
 endif
 
--- a/toolkit/components/build/Makefile.in
+++ b/toolkit/components/build/Makefile.in
@@ -75,16 +75,22 @@ LOCAL_INCLUDES = \
 	$(NULL)
 
 ifdef ALERTS_SERVICE
 LOCAL_INCLUDES += \
 	-I$(srcdir)/../alerts/src \
 	$(NULL)
 endif
 
+ifeq (Android,$(OS_TARGET))
+LOCAL_INCLUDES += \
+	-I$(srcdir)/../webapps \
+	$(NULL)
+endif
+
 SHARED_LIBRARY_LIBS = \
 	../find/src/$(LIB_PREFIX)mozfind_s.$(LIB_SUFFIX) \
 	../typeaheadfind/src/$(LIB_PREFIX)fastfind_s.$(LIB_SUFFIX) \
 	../startup/src/$(LIB_PREFIX)appstartup_s.$(LIB_SUFFIX) \
 	../statusfilter/$(LIB_PREFIX)mozbrwsr_s.$(LIB_SUFFIX) \
 	$(NULL)
 
 ifndef MOZ_DISABLE_PARENTAL_CONTROLS
@@ -115,16 +121,20 @@ ifdef MOZ_URL_CLASSIFIER
 SHARED_LIBRARY_LIBS += ../url-classifier/src/$(LIB_PREFIX)urlclassifier_s.$(LIB_SUFFIX)
 EXTRA_DSO_LDOPTS += $(ZLIB_LIBS)
 endif
 
 ifdef MOZ_FEEDS
 SHARED_LIBRARY_LIBS += ../feeds/src/$(LIB_PREFIX)feed_s.$(LIB_SUFFIX)
 endif
 
+ifeq (Android,$(OS_TARGET))
+SHARED_LIBRARY_LIBS += ../webapps/$(LIB_PREFIX)webapps_s.$(LIB_SUFFIX)
+endif
+
 EXTRA_DSO_LIBS = gkgfx
 
 EXTRA_DSO_LDOPTS += \
 	$(LIBS_DIR) \
 	$(EXTRA_DSO_LIBS) \
 	$(MOZ_UNICHARUTIL_LIBS) \
 	$(MOZ_COMPONENT_LIBS) \
 	$(MOZ_JS_LIBS) \
--- a/toolkit/components/build/nsToolkitCompsCID.h
+++ b/toolkit/components/build/nsToolkitCompsCID.h
@@ -114,16 +114,19 @@
   "@mozilla.org/browser/favicon-service;1"
 
 #define NS_PLACESIMPORTEXPORTSERVICE_CONTRACTID \
   "@mozilla.org/browser/places/import-export-service;1"
 
 #define NS_APPSTARTUP_CONTRACTID \
   "@mozilla.org/toolkit/app-startup;1"
 
+#define NS_WEBAPPSSUPPORT_CONTRACTID \
+  "@mozilla.org/webapps/installer;1"
+
 /////////////////////////////////////////////////////////////////////////////
 
 // {A0CCAAF8-09DA-44D8-B250-9AC3E93C8117}
 #define NS_ALERTSSERVICE_CID \
 { 0xa0ccaaf8, 0x9da, 0x44d8, { 0xb2, 0x50, 0x9a, 0xc3, 0xe9, 0x3c, 0x81, 0x17 } }
 
 // {84E11F80-CA55-11DD-AD8B-0800200C9A66}
 #define NS_SYSTEMALERTSSERVICE_CID \
@@ -197,8 +200,12 @@
 { 0x428e6d12, 0x9c6d, 0x436f, {0xb7, 0xa3, 0x6c, 0xa5, 0xf4, 0x80, 0x92, 0x12}}
 
 #define NS_FAVICONSERVICE_CID \
 { 0x984e3259, 0x9266, 0x49cf, { 0xb6, 0x05, 0x60, 0xb0, 0x22, 0xa0, 0x07, 0x56 } }
 
 // {6fb0c970-e1b1-11db-8314-0800200c9a66}
 #define NS_PLACESIMPORTEXPORTSERVICE_CID \
 { 0x6fb0c970, 0xe1b1, 0x11db, { 0x83, 0x14, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
+
+#define NS_WEBAPPSSUPPORT_CID \
+{ 0xd0b62752, 0x88be, 0x4c88, {0x94, 0xe5, 0xc6, 0x9e, 0x15, 0xa1, 0x0c, 0x4e} }
+
--- a/toolkit/components/build/nsToolkitCompsModule.cpp
+++ b/toolkit/components/build/nsToolkitCompsModule.cpp
@@ -67,16 +67,20 @@
 #endif
 
 #ifdef MOZ_FEEDS
 #include "nsScriptableUnescapeHTML.h"
 #endif
 
 #include "nsBrowserStatusFilter.h"
 
+#ifdef ANDROID
+#include "nsWebappsSupport.h"
+#endif
+
 /////////////////////////////////////////////////////////////////////////////
 
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsAppStartup, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsUserInfo)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFindService)
 
 #if defined(XP_WIN) && !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsParentalControlsServiceWin)
@@ -120,16 +124,20 @@ nsUrlClassifierDBServiceConstructor(nsIS
 #endif
 
 #ifdef MOZ_FEEDS
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptableUnescapeHTML)
 #endif
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserStatusFilter)
 
+#ifdef ANDROID
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebappsSupport)
+#endif
+
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID);
 NS_DEFINE_NAMED_CID(NS_USERINFO_CID);
 #ifdef ALERTS_SERVICE
 NS_DEFINE_NAMED_CID(NS_ALERTSSERVICE_CID);
 #endif
 #if defined(XP_WIN) && !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
 NS_DEFINE_NAMED_CID(NS_PARENTALCONTROLSSERVICE_CID);
 #endif
@@ -146,16 +154,20 @@ NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERUTIL
 NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERHASHCOMPLETER_CID);
 #endif
 #ifdef MOZ_FEEDS
 NS_DEFINE_NAMED_CID(NS_SCRIPTABLEUNESCAPEHTML_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILTER_CID);
 NS_DEFINE_NAMED_CID(NS_CHARSETMENU_CID);
 
+#ifdef ANDROID
+NS_DEFINE_NAMED_CID(NS_WEBAPPSSUPPORT_CID);
+#endif
+
 static const mozilla::Module::CIDEntry kToolkitCIDs[] = {
   { &kNS_TOOLKIT_APPSTARTUP_CID, false, NULL, nsAppStartupConstructor },
   { &kNS_USERINFO_CID, false, NULL, nsUserInfoConstructor },
 #ifdef ALERTS_SERVICE
   { &kNS_ALERTSSERVICE_CID, false, NULL, nsAlertsServiceConstructor },
 #endif
 #if defined(XP_WIN) && !defined(MOZ_DISABLE_PARENTAL_CONTROLS)
   { &kNS_PARENTALCONTROLSSERVICE_CID, false, NULL, nsParentalControlsServiceWinConstructor },
@@ -172,16 +184,19 @@ static const mozilla::Module::CIDEntry k
   { &kNS_URLCLASSIFIERUTILS_CID, false, NULL, nsUrlClassifierUtilsConstructor },
   { &kNS_URLCLASSIFIERHASHCOMPLETER_CID, false, NULL, nsUrlClassifierHashCompleterConstructor },
 #endif
 #ifdef MOZ_FEEDS
   { &kNS_SCRIPTABLEUNESCAPEHTML_CID, false, NULL, nsScriptableUnescapeHTMLConstructor },
 #endif
   { &kNS_BROWSERSTATUSFILTER_CID, false, NULL, nsBrowserStatusFilterConstructor },
   { &kNS_CHARSETMENU_CID, false, NULL, NS_NewCharsetMenu },
+#ifdef ANDROID
+  { &kNS_WEBAPPSSUPPORT_CID, false, NULL, nsWebappsSupportConstructor },
+#endif
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kToolkitContracts[] = {
   { NS_APPSTARTUP_CONTRACTID, &kNS_TOOLKIT_APPSTARTUP_CID },
   { NS_USERINFO_CONTRACTID, &kNS_USERINFO_CID },
 #ifdef ALERTS_SERVICE
   { NS_ALERTSERVICE_CONTRACTID, &kNS_ALERTSSERVICE_CID },
@@ -202,16 +217,19 @@ static const mozilla::Module::ContractID
   { NS_URLCLASSIFIERUTILS_CONTRACTID, &kNS_URLCLASSIFIERUTILS_CID },
   { NS_URLCLASSIFIERHASHCOMPLETER_CONTRACTID, &kNS_URLCLASSIFIERHASHCOMPLETER_CID },
 #endif
 #ifdef MOZ_FEEDS
   { NS_SCRIPTABLEUNESCAPEHTML_CONTRACTID, &kNS_SCRIPTABLEUNESCAPEHTML_CID },
 #endif
   { NS_BROWSERSTATUSFILTER_CONTRACTID, &kNS_BROWSERSTATUSFILTER_CID },
   { NS_RDF_DATASOURCE_CONTRACTID_PREFIX NS_CHARSETMENU_PID, &kNS_CHARSETMENU_CID },
+#ifdef ANDROID
+  { NS_WEBAPPSSUPPORT_CONTRACTID, &kNS_WEBAPPSSUPPORT_CID },
+#endif
   { NULL }
 };
 
 static const mozilla::Module kToolkitModule = {
   mozilla::Module::kVersion,
   kToolkitCIDs,
   kToolkitContracts
 };
new file mode 100644
--- /dev/null
+++ b/toolkit/components/webapps/Makefile.in
@@ -0,0 +1,65 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is Mozilla Webapp code.
+#
+# The Initial Developer of the Original Code is
+# the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#    Fabrice Desré <fabrice@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE_NAME = webapps
+MODULE      = webapps
+ 
+ifeq (Android,$(OS_TARGET))
+LIBRARY_NAME    = webapps_s
+LIBXUL_LIBRARY  = 1
+IS_COMPONENT    = 1
+EXPORT_LIBRARY  = 1
+
+CPPSRCS = \
+        nsWebappsSupport.cpp \
+        $(NULL)
+
+EXTRA_DSO_LDOPTS += \
+        $(MOZ_COMPONENT_LIBS) \
+        $(NULL)
+endif
+
+XPIDLSRCS = nsIWebappsSupport.idl
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/toolkit/components/webapps/nsIWebappsSupport.idl
@@ -0,0 +1,60 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Webapp code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[scriptable, uuid(adb91273-0cf1-4bbe-a37b-22e660192e2a)]
+interface nsIWebappsSupport : nsISupports
+{
+  /**
+   * This method installs a web app.
+   *
+   * @param title     the user-friendly name of the application.
+   * @param uri       the uri of the web app.
+   * @param iconData  a base64 encoded representation of the application's icon.
+   */
+  void installApplication(in wstring title, in wstring uri, in wstring iconUri, in wstring iconData);
+  
+  /**
+   * Checks is a web app is already installed
+   *
+   * @param uri the uri of the web app
+   * @return true if the web app is installed, false if it's not installed
+   */
+  boolean isApplicationInstalled(in wstring uri);
+};
+
new file mode 100644
--- /dev/null
+++ b/toolkit/components/webapps/nsWebappsSupport.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Webapp code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "AndroidBridge.h"
+#include "nsCRTGlue.h"
+#include "nsWebappsSupport.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS1(nsWebappsSupport, nsIWebappsSupport)
+
+NS_IMETHODIMP
+nsWebappsSupport::InstallApplication(const PRUnichar *aTitle, const PRUnichar *aURI, const PRUnichar *aIconURI, const PRUnichar *aIconData)
+{
+  ALOG("in nsWebappsSupport::InstallApplication()\n");
+  AndroidBridge::AutoLocalJNIFrame jniFrame;
+  JNIEnv *jEnv = GetJNIForThread();
+  jclass jGeckoAppShellClass = GetGeckoAppShellClass();
+  
+  if (!jEnv || !jGeckoAppShellClass)
+    return NS_ERROR_FAILURE;
+    
+  jmethodID jInstallWebApplication = jEnv->GetStaticMethodID(jGeckoAppShellClass, "installWebApplication", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+  jstring jstrURI = jEnv->NewString(aURI, NS_strlen(aURI));
+  jstring jstrTitle = jEnv->NewString(aTitle, NS_strlen(aTitle));
+  jstring jstrIconData = jEnv->NewString(aIconData, NS_strlen(aIconData));
+  
+  if (!jstrURI || !jstrTitle || !jstrIconData)
+    return NS_ERROR_FAILURE;
+    
+  jEnv->CallStaticVoidMethod(jGeckoAppShellClass, jInstallWebApplication, jstrURI, jstrTitle, jstrIconData);
+  return NS_OK;
+}
+
+/*
+ * we have no way to know if an application is installed, so pretend it's not installed
+ */
+NS_IMETHODIMP
+nsWebappsSupport::IsApplicationInstalled(const PRUnichar *aURI, PRBool *_retval)
+{
+  *_retval = PR_FALSE;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/toolkit/components/webapps/nsWebappsSupport.h
@@ -0,0 +1,56 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Webapp code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Fabrice Desré <fabrice@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nsWebappsSupport_h__
+#define nsWebappsSupport_h__
+
+#include "nsIWebappsSupport.h"
+
+class nsWebappsSupport : public nsIWebappsSupport
+{
+public:
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIWEBAPPSSUPPORT
+
+  nsWebappsSupport() {};
+  ~nsWebappsSupport() {};
+
+};
+
+#endif // nsWebappsSupport_h__
+
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -572,8 +572,13 @@ mozilla_AndroidBridge_AttachThread(PRBoo
 {
     return AndroidBridge::Bridge()->AttachThread(asDaemon);
 }
 
 extern "C" JNIEnv * GetJNIForThread()
 {
     return mozilla::AndroidBridge::JNIForThread();
 }
+
+jclass GetGeckoAppShellClass()
+{
+    return mozilla::AndroidBridge::GetGeckoAppShellClass();
+}
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -85,16 +85,20 @@ public:
         return sBridge->mJNIEnv;
     }
 
     static JNIEnv *JNIForThread() {
         if (NS_LIKELY(sBridge))
           return sBridge->AttachThread();
         return nsnull;
     }
+    
+    static jclass GetGeckoAppShellClass() {
+        return sBridge->mGeckoAppShellClass;
+    }
 
     // The bridge needs to be constructed via ConstructBridge first,
     // and then once the Gecko main thread is spun up (Gecko side),
     // SetMainThread should be called which will create the JNIEnv for
     // us to use.  toolkit/xre/nsAndroidStartup.cpp calls
     // SetMainThread.
     PRBool SetMainThread(void *thr);
 
@@ -231,10 +235,11 @@ protected:
     jclass jEGLContextClass;
     jclass jEGL10Class;
 };
 
 }
 
 extern "C" JNIEnv * GetJNIForThread();
 extern PRBool mozilla_AndroidBridge_SetMainThread(void *);
+extern jclass GetGeckoAppShellClass();
 
 #endif /* AndroidBridge_h__ */
--- a/widget/src/android/nsAppShell.cpp
+++ b/widget/src/android/nsAppShell.cpp
@@ -124,17 +124,16 @@ void
 nsAppShell::ScheduleNativeEventCallback()
 {
     EVLOG("nsAppShell::ScheduleNativeEventCallback pth: %p thread: %p main: %d", (void*) pthread_self(), (void*) NS_GetCurrentThread(), NS_IsMainThread());
 
     // this is valid to be called from any thread, so do so.
     PostEvent(new AndroidGeckoEvent(AndroidGeckoEvent::NATIVE_POKE));
 }
 
-
 PRBool
 nsAppShell::ProcessNextNativeEvent(PRBool mayWait)
 {
     EVLOG("nsAppShell::ProcessNextNativeEvent %d", mayWait);
 
     PR_Lock(mCondLock);
 
     nsAutoPtr<AndroidGeckoEvent> curEvent;