bug 565138 - Implement extloader backend for Android r=vlad
authorBrad Lassey <blassey@mozilla.com>
Mon, 14 Jun 2010 15:04:16 -0400
changeset 43601 0d15abb54498f3995ab60c99bc73b73a3cc19964
parent 43600 729483f7e2ff10c77edf42675926277c183dccd4
child 43602 33fabdd9b3b9679d7883f0ed75d765396622ebeb
push id13800
push userblassey@mozilla.com
push dateMon, 14 Jun 2010 19:55:59 +0000
treeherdermozilla-central@0d15abb54498 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs565138
milestone1.9.3a6pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 565138 - Implement extloader backend for Android r=vlad
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
toolkit/components/downloads/src/nsDownloadManager.cpp
toolkit/xre/nsAndroidStartup.cpp
uriloader/exthandler/Makefile.in
uriloader/exthandler/android/nsAndroidHandlerApp.cpp
uriloader/exthandler/android/nsAndroidHandlerApp.h
uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
uriloader/exthandler/android/nsMIMEInfoAndroid.h
uriloader/exthandler/android/nsOSHelperAppService.cpp
uriloader/exthandler/android/nsOSHelperAppService.h
widget/src/android/AndroidBridge.cpp
widget/src/android/AndroidBridge.h
widget/src/android/AndroidJavaWrappers.cpp
widget/src/android/AndroidJavaWrappers.h
xpcom/io/nsLocalFileUnix.cpp
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -71,16 +71,28 @@ abstract public class GeckoApp
         Intent i = getIntent();
         String env = i.getStringExtra("env0");
         Log.i("GeckoApp", "env0: "+ env);
         for (int c = 1; env != null; c++) {
             GeckoAppShell.putenv(env);
             env = i.getStringExtra("env" + c);
             Log.i("GeckoApp", "env"+ c +": "+ env);
         }
+        String tmpdir = System.getProperty("java.io.tmpdir");
+        if (tmpdir == null) {
+          try {
+            File f = Environment.getDownloadCacheDirectory();
+            dalvik.system.TemporaryDirectory.setUpDirectory(f);
+            tmpdir = f.getPath();
+          } catch (Exception e) {
+            Log.e("GeckoApp", "error setting up tmp dir" + e);
+          }
+        }
+        GeckoAppShell.putenv("TMPDIR=" + tmpdir);
+
         GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
                                i.getStringExtra("args"),
                                i.getDataString());
     }
 
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -1,9 +1,9 @@
-/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
+/* -*- Mode: Java; 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/
  *
@@ -50,16 +50,19 @@ import android.view.inputmethod.*;
 import android.content.*;
 import android.graphics.*;
 import android.widget.*;
 import android.hardware.*;
 import android.location.*;
 
 import android.util.*;
 import android.content.DialogInterface; 
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
 
 class GeckoAppShell
 {
     static {
         sGeckoRunning = false;
     }
 
     // static members only
@@ -230,9 +233,44 @@ class GeckoAppShell
             System.exit(0);
         }
 
     }
     static void scheduleRestart() {
         Log.i("GeckoAppJava", "scheduling restart");
         gRestartScheduled = true;        
     }
+    
+    static String[] getHandlersForMimeType(String aMimeType) {
+        PackageManager pm = 
+            GeckoApp.surfaceView.getContext().getPackageManager();
+        Intent intent = new Intent();
+        intent.setType(aMimeType);
+        List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
+        int numAttr = 2;
+        String[] ret = new String[list.size() * numAttr];
+        for (int i = 0; i < list.size(); i++) {
+          ret[i * numAttr] = list.get(i).loadLabel(pm).toString();
+          if (list.get(i).isDefault)
+              ret[i * numAttr + 1] = "default";
+          else
+              ret[i * numAttr + 1] = "";
+        }
+        return ret;
+    }
+
+    static String getMimeTypeFromExtension(String aFileExt) {
+        return android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(aFileExt);
+    }
+
+    static boolean openUriExternal(String aUriSpec, String aMimeType) {
+        // XXX: It's not clear if we should set the action to view or leave it open
+        Intent intent = new Intent(Intent.ACTION_VIEW);
+        intent.setDataAndType(android.net.Uri.parse(aUriSpec), aMimeType);
+        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        try {
+            GeckoApp.surfaceView.getContext().startActivity(intent);
+            return true;
+        } catch(ActivityNotFoundException e) {
+            return false;
+        }
+    }
 }
--- a/toolkit/components/downloads/src/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/src/nsDownloadManager.cpp
@@ -1176,16 +1176,30 @@ nsDownloadManager::GetDefaultDownloadsDi
     // As maemo does not follow the XDG "standard" (as usually desktop
     // Linux distros do) neither has a working $HOME/Desktop folder
     // for us to fallback into, "$HOME/MyDocs/.documents/" is the folder
     // we found most apropriate to be the default target folder for downloads
     // on the platform.
     rv = dirService->Get(NS_UNIX_XDG_DOCUMENTS_DIR,
                          NS_GET_IID(nsILocalFile),
                          getter_AddRefs(downloadDir));
+#elif defined(ANDROID)
+    // Android doesn't have a $HOME directory, and by default we only have
+    // write access to /data/data/org.mozilla.{$APP} and /sdcard
+    char* sdcard = getenv("EXTERNAL_STORAGE");
+    if (sdcard) {
+      rv = NS_NewNativeLocalFile(nsDependentCString(sdcard),
+                                 PR_TRUE, getter_AddRefs(downloadDir));
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = downloadDir->Append(NS_LITERAL_STRING("download"));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+      rv = NS_ERROR_FAILURE;
+    }
 #else
   rv = dirService->Get(NS_UNIX_DEFAULT_DOWNLOAD_DIR,
                        NS_GET_IID(nsILocalFile),
                        getter_AddRefs(downloadDir));
   // fallback to Home/Downloads
   if (NS_FAILED(rv)) {
     rv = dirService->Get(NS_UNIX_HOME_DIR,
                          NS_GET_IID(nsILocalFile),
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -104,18 +104,16 @@ GeckoStart(void *data)
                          getter_AddRefs(xreDir));
     if (NS_FAILED(rv)) {
         LOG("Failed to create nsIFile for xreDirectory");
         return 0;
     }
 
     appData->xreDirectory = xreDir.get();
 
-    // SpecialSystemDirectory.cpp sets its TMPDIR from this env var
-    setenv("TMPDIR", "/data/data/org.mozilla." MOZ_APP_NAME, 1);
 
     nsTArray<char *> targs;
     char *arg = strtok(static_cast<char *>(data), " ");
     while (arg) {
         targs.AppendElement(arg);
         arg = strtok(NULL, " ");
     }
     targs.AppendElement(static_cast<char *>(nsnull));
--- a/uriloader/exthandler/Makefile.in
+++ b/uriloader/exthandler/Makefile.in
@@ -55,21 +55,25 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 OSDIR		= win
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 OSDIR		= mac
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
 OSDIR		= beos
 else
+ifeq ($(MOZ_WIDGET_TOOLKIT),android)
+OSDIR		= android
+else
 OSDIR		= unix
 endif
 endif
 endif
 endif
+endif
 
 VPATH		:= $(srcdir) $(srcdir)/$(OSDIR)
 
 MODULE = exthandler
 LIBRARY_NAME    = exthandler_s
 LIBXUL_LIBRARY  = 1
 
 
@@ -85,16 +89,21 @@ endif
 
 LOCAL_INCLUDES = -I$(srcdir)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 OSHELPER	+= nsGNOMERegistry.cpp
 OSHELPER  += nsMIMEInfoUnix.cpp
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),android)
+OSHELPER += nsMIMEInfoAndroid.cpp
+OSHELPER += nsAndroidHandlerApp.cpp
+endif
+
 ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
 OSHELPER += nsGNOMERegistry.cpp
 OSHELPER += nsMIMEInfoUnix.cpp
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),beos)
 OSHELPER  += nsMIMEInfoBeOS.cpp
 endif
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: c++; c-basic-offset: 2; 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 Android 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):
+ *   Brad Lassey <blassey@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 "nsAndroidHandlerApp.h"
+
+NS_IMPL_ISUPPORTS1(nsAndroidHandlerApp, nsIHandlerApp)
+
+
+nsAndroidHandlerApp::nsAndroidHandlerApp(nsAString& aName,
+                                         nsAString& aDescription) :
+mName(aName), mDescription(aDescription)
+{
+}
+
+nsAndroidHandlerApp::~nsAndroidHandlerApp()
+{
+}
+
+nsresult nsAndroidHandlerApp::GetName(nsAString & aName)
+{
+  aName.Assign(mName);
+  return NS_OK;
+}
+
+nsresult nsAndroidHandlerApp::SetName(const nsAString & aName)
+{
+  mName.Assign(aName);
+  return NS_OK;
+}
+
+nsresult nsAndroidHandlerApp::GetDetailedDescription(nsAString & aDescription)
+{
+  aDescription.Assign(mDescription);
+  return NS_OK;
+}
+
+nsresult nsAndroidHandlerApp::SetDetailedDescription(const nsAString & aDescription)
+{
+  mDescription.Assign(aDescription);
+
+  return NS_OK;
+}
+
+nsresult nsAndroidHandlerApp::Equals(nsIHandlerApp *aHandlerApp, PRBool *aRetval)
+{
+  nsCOMPtr<nsAndroidHandlerApp> aApp = do_QueryInterface(aHandlerApp);
+  *aRetval = aApp && aApp->mName.Equals(mName) &&
+    aApp->mDescription.Equals(mDescription);
+  return NS_OK;
+}
+
+nsresult nsAndroidHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
+{
+  nsCAutoString uristr;
+  aURI->GetAsciiSpec(uristr);
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.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 Android 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):
+ *   Brad Lassey <blassey@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 nsAndroidHandlerApp_h
+#define nsAndroidHandlerApp_h
+
+#include "nsMIMEInfoImpl.h"
+
+class nsAndroidHandlerApp : public nsIHandlerApp {
+public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIHANDLERAPP
+    public:
+    nsAndroidHandlerApp(nsAString& aName, nsAString& aDescription);
+    virtual ~nsAndroidHandlerApp();
+
+private:
+    nsString mName;
+    nsString mDescription;
+
+};
+#endif
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
@@ -0,0 +1,378 @@
+/* -*- Mode: c++; c-basic-offset: 2; 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 Android 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):
+ *   Michael Wu <mwu@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 "nsMIMEInfoAndroid.h"
+#include "AndroidBridge.h"
+#include "nsAndroidHandlerApp.h"
+#include "nsArrayUtils.h"
+#include "nsISupportsUtils.h"
+#include "nsStringEnumerator.h"
+#include "nsNetUtil.h"
+
+NS_IMPL_ISUPPORTS1(nsMIMEInfoAndroid, nsIMIMEInfo)
+
+nsMIMEInfoAndroid::~nsMIMEInfoAndroid()
+{
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
+{
+  LaunchWithFile(aFile);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI)
+{
+  nsCString uriSpec;
+  aURI->GetSpec(uriSpec);
+  return mozilla::AndroidBridge::Bridge()->
+    OpenUriExternal(uriSpec, mMimeType) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+already_AddRefed<nsIMIMEInfo>
+nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType)
+{
+  mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
+  nsStringArray stringArray;
+  bridge->GetHandlersForMimeType(nsCAutoString(aMimeType).get(), &stringArray);
+  
+  nsString empty = EmptyString();
+  PRInt32 len = stringArray.Count();
+  if (len == 0)
+    return nsnull;
+  nsCOMPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
+  for (jsize i = 0; i < len; i+=2) {
+    nsAndroidHandlerApp* app = new nsAndroidHandlerApp(*stringArray[i], empty);
+    info->mHandlerApps->AppendElement(app, PR_FALSE);
+    if (stringArray[i + 1] > 0)
+      info->mPrefApp = app;
+  }
+  nsCOMPtr<nsIMIMEInfo> ret = do_QueryInterface(info);
+  return ret.forget();
+}
+
+already_AddRefed<nsIMIMEInfo>
+nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt)
+{
+  nsCString mimeType;
+  mozilla::AndroidBridge::Bridge()->GetMimeTypeFromExtension(nsCString(aFileExt), mimeType);
+
+  return GetMimeInfoForMimeType(mimeType);
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetType(nsACString& aType)
+{
+  aType.Assign(mMimeType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetDescription(nsAString& aDesc)
+{
+  aDesc.Assign(mDescription);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetDescription(const nsAString& aDesc)
+{
+  mDescription.Assign(aDesc);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPreferredApplicationHandler(nsIHandlerApp** aApp)
+{
+  *aApp = mPrefApp;
+  if (*aApp) {
+    nsAutoString appName;
+    (*aApp)->GetName(appName);
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetPreferredApplicationHandler(nsIHandlerApp* aApp)
+{
+  mPrefApp = aApp;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPossibleApplicationHandlers(nsIMutableArray **aHandlerApps)
+{
+  if (!mHandlerApps)
+    mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID);
+
+  if (!mHandlerApps)
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  *aHandlerApps = mHandlerApps;
+  NS_IF_ADDREF(*aHandlerApps);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetHasDefaultHandler(PRBool* aHasDefault)
+{
+  PRUint32 len;
+  *aHasDefault = PR_FALSE;
+  if (!mHandlerApps)
+    return NS_OK;
+
+  if (NS_FAILED(mHandlerApps->GetLength(&len)))
+    return NS_OK;
+
+  if (len == 0)
+    return NS_OK;
+
+  *aHasDefault = PR_TRUE;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc)
+{
+  aDesc.Assign(EmptyString());
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* req)
+{
+  return mPrefApp->LaunchWithURI(aURI, req);
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPreferredAction(nsHandlerInfoAction* aPrefAction)
+{
+  *aPrefAction = mPrefAction;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetPreferredAction(nsHandlerInfoAction aPrefAction)
+{
+  mPrefAction = aPrefAction;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetAlwaysAskBeforeHandling(PRBool* aAlwaysAsk)
+{
+  *aAlwaysAsk = mAlwaysAsk;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetAlwaysAskBeforeHandling(PRBool aAlwaysAsk)
+{
+  mAlwaysAsk = aAlwaysAsk;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetFileExtensions(nsIUTF8StringEnumerator** aResult)
+{
+  return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this);
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetFileExtensions(const nsACString & aExtensions)
+{
+  mExtensions.Clear();
+  nsCString extList(aExtensions);
+
+  PRInt32 breakLocation = -1;
+  while ( (breakLocation = extList.FindChar(',')) != -1)
+  {
+    mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation));
+    extList.Cut(0, breakLocation + 1);
+  }
+  if (!extList.IsEmpty())
+    mExtensions.AppendElement(extList);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::ExtensionExists(const nsACString & aExtension, PRBool *aRetVal)
+{
+  NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
+  PRBool found = PR_FALSE;
+  PRUint32 extCount = mExtensions.Length();
+  if (extCount < 1) return NS_OK;
+
+  for (PRUint8 i=0; i < extCount; i++) {
+    const nsCString& ext = mExtensions[i];
+    if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
+      found = PR_TRUE;
+      break;
+    }
+  }
+
+  *aRetVal = found;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::AppendExtension(const nsACString & aExtension)
+{
+  mExtensions.AppendElement(aExtension);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPrimaryExtension(nsACString & aPrimaryExtension)
+{
+  if (!mExtensions.Length())
+    return NS_ERROR_NOT_INITIALIZED;
+
+  aPrimaryExtension = mExtensions[0];
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetPrimaryExtension(const nsACString & aExtension)
+{
+  NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
+  PRUint32 extCount = mExtensions.Length();
+  PRUint8 i;
+  PRBool found = PR_FALSE;
+  for (i=0; i < extCount; i++) {
+    const nsCString& ext = mExtensions[i];
+    if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) {
+      found = PR_TRUE;
+      break;
+    }
+  }
+  if (found) {
+    mExtensions.RemoveElementAt(i);
+  }
+
+  mExtensions.InsertElementAt(0, aExtension);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetMIMEType(nsACString & aMIMEType)
+{
+  aMIMEType.Assign(mMimeType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::Equals(nsIMIMEInfo *aMIMEInfo, PRBool *aRetVal)
+{
+  if (!aMIMEInfo) return NS_ERROR_NULL_POINTER;
+
+  nsCAutoString type;
+  nsresult rv = aMIMEInfo->GetMIMEType(type);
+  if (NS_FAILED(rv)) return rv;
+
+  *aRetVal = mMimeType.Equals(type);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchWithFile(nsIFile *aFile)
+{
+  nsIURI* uri;
+  NS_NewFileURI(&uri, aFile);
+  LoadUriInternal(uri);
+  return NS_OK;
+}
+
+nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType) :
+  mMimeType(aMIMEType), mAlwaysAsk(PR_TRUE), 
+  mPrefAction(nsIMIMEInfo::useHelperApp), 
+  mSystemChooser(this)
+{
+  mPrefApp = &mSystemChooser;
+  nsresult rv;
+  mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+  mHandlerApps->AppendElement(mPrefApp, PR_FALSE);
+}
+
+NS_IMPL_ISUPPORTS1(nsMIMEInfoAndroid::SystemChooser, nsIHandlerApp)
+
+
+nsresult nsMIMEInfoAndroid::SystemChooser::GetName(nsAString & aName) {
+  aName.Assign(NS_LITERAL_STRING("Android chooser"));
+  return NS_OK;
+}
+
+nsresult
+nsMIMEInfoAndroid::SystemChooser::SetName(const nsAString&) {
+  return NS_OK;
+}
+
+nsresult
+nsMIMEInfoAndroid::SystemChooser::GetDetailedDescription(nsAString & aDesc) {
+  aDesc.Assign(NS_LITERAL_STRING("Android's default handler application chooser"));
+  return NS_OK;
+}
+
+nsresult
+nsMIMEInfoAndroid::SystemChooser::SetDetailedDescription(const nsAString&) {
+  return NS_OK;
+}
+
+nsresult
+nsMIMEInfoAndroid::SystemChooser::Equals(nsIHandlerApp *aHandlerApp, PRBool *aRetVal) {
+  nsCOMPtr<nsMIMEInfoAndroid::SystemChooser> info = do_QueryInterface(aHandlerApp);
+  if (info)
+    return mOuter->Equals(info->mOuter, aRetVal);
+  *aRetVal = PR_FALSE;
+  return NS_OK;
+}
+
+nsresult
+nsMIMEInfoAndroid::SystemChooser::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor*)
+{
+  return mOuter->LoadUriInternal(aURI);
+}
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.h
@@ -0,0 +1,81 @@
+/* -*- Mode: c++; c-basic-offset: 2; 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 Android 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):
+ *   Michael Wu <mwu@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 nsMIMEInfoAndroid_h
+#define nsMIMEInfoAndroid_h
+
+#include "nsMIMEInfoImpl.h"
+#include "nsIMutableArray.h"
+#include "nsAndroidHandlerApp.h"
+class nsMIMEInfoAndroid : public nsIMIMEInfo
+{
+public:
+  static already_AddRefed<nsIMIMEInfo> GetMimeInfoForMimeType(const nsACString& aMimeType);
+  static already_AddRefed<nsIMIMEInfo> GetMimeInfoForFileExt(const nsACString& aFileExt);
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMIMEINFO
+  NS_DECL_NSIHANDLERINFO
+private:
+  nsMIMEInfoAndroid(const nsACString& aMIMEType);
+  virtual ~nsMIMEInfoAndroid();
+
+protected:
+  virtual NS_HIDDEN_(nsresult) LaunchDefaultWithFile(nsIFile* aFile);
+  virtual NS_HIDDEN_(nsresult) LoadUriInternal(nsIURI *aURI);
+  nsCOMPtr<nsIMutableArray> mHandlerApps;
+  nsCString mMimeType;
+  nsTArray<nsCString> mExtensions;
+  PRBool mAlwaysAsk;
+  nsHandlerInfoAction mPrefAction;
+  nsString mDescription;
+  nsCOMPtr<nsIHandlerApp> mPrefApp;
+  
+  class SystemChooser : public nsIHandlerApp {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIHANDLERAPP
+    SystemChooser(nsMIMEInfoAndroid* aOuter): mOuter(aOuter) {};
+    
+  private:
+    nsMIMEInfoAndroid* mOuter;
+    
+  };
+  SystemChooser mSystemChooser;
+};
+
+#endif /* nsMIMEInfoAndroid_h */
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsOSHelperAppService.cpp
@@ -0,0 +1,71 @@
+/* -*- 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 Android 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):
+ *   Michael Wu <mwu@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 "nsOSHelperAppService.h"
+#include "nsMIMEInfoAndroid.h"
+
+nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService()
+{
+}
+
+nsOSHelperAppService::~nsOSHelperAppService()
+{
+}
+
+already_AddRefed<nsIMIMEInfo>
+nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
+                                        const nsACString& aFileExt,
+                                        PRBool* aFound)
+{
+    *aFound = PR_FALSE;
+    already_AddRefed<nsIMIMEInfo> mimeInfo = 
+            nsMIMEInfoAndroid::GetMimeInfoForMimeType(aMIMEType);
+    if (!mimeInfo.get())
+            mimeInfo = nsMIMEInfoAndroid::GetMimeInfoForFileExt(aFileExt);
+
+    *aFound = !!mimeInfo.get();
+    
+    return mimeInfo;
+}
+
+nsresult
+nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
+                                              PRBool* aExists)
+{
+    *aExists = PR_FALSE;
+    return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/uriloader/exthandler/android/nsOSHelperAppService.h
@@ -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 Android 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):
+ *   Michael Wu <mwu@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 nsOSHelperAppService_h
+#define nsOSHelperAppService_h
+
+#include "nsCExternalHandlerService.h"
+#include "nsExternalHelperAppService.h"
+
+class nsOSHelperAppService : public nsExternalHelperAppService
+{
+public:
+    nsOSHelperAppService();
+    virtual ~nsOSHelperAppService();
+
+    virtual already_AddRefed<nsIMIMEInfo>
+    GetMIMEInfoFromOS(const nsACString& aMIMEType,
+                      const nsACString& aFileExt,
+                      PRBool* aFound);
+
+    virtual NS_HIDDEN_(nsresult)
+    OSProtocolHandlerExists(const char* aScheme,
+                            PRBool* aExists);
+};
+
+#endif /* nsOSHelperAppService_h */
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -92,17 +92,19 @@ AndroidBridge::Init(JNIEnv *jEnv,
     mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
 
     jShowIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showIME", "(I)V");
     jEnableAccelerometer = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableAccelerometer", "(Z)V");
     jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
     jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
     jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
     jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
-
+    jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;)[Ljava/lang/String;");
+    jOpenUriExternal = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;)Z");
+    jGetMimeTypeFromExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtension", "(Ljava/lang/String;)Ljava/lang/String;");
     InitAndroidJavaWrappers(jEnv);
 
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return PR_TRUE;
 }
@@ -208,16 +210,59 @@ AndroidBridge::ScheduleRestart()
 void
 AndroidBridge::NotifyXreExit()
 {
     ALOG("xre exiting");
     mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
 }
 
 void
+AndroidBridge::GetHandlersForMimeType(const char *aMimeType, nsStringArray* aStringArray)
+{
+    AutoLocalJNIFrame jniFrame;
+    NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
+    jstring jstr = mJNIEnv->NewString(wMimeType.get(), wMimeType.Length());
+    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, 
+                                                  jGetHandlersForMimeType, 
+                                                  jstr);
+    jobjectArray arr = static_cast<jobjectArray>(obj);
+    jsize len = mJNIEnv->GetArrayLength(arr);
+    for (jsize i = 0; i < len; i+=2) {
+        jstring jstr = static_cast<jstring>(mJNIEnv->GetObjectArrayElement(arr, i));
+        nsJNIString jniStr(jstr);
+        aStringArray->AppendString(jniStr);
+    } 
+}
+
+PRBool
+AndroidBridge::OpenUriExternal(nsCString& aUriSpec, nsCString& aMimeType) 
+{
+    AutoLocalJNIFrame jniFrame;
+    NS_ConvertUTF8toUTF16 wUriSpec(aUriSpec);
+    NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
+    jstring jstrUri = mJNIEnv->NewString(wUriSpec.get(), wUriSpec.Length());
+    jstring jstrType = mJNIEnv->NewString(wMimeType.get(), wMimeType.Length());
+    return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass,
+                                            jOpenUriExternal,
+                                            jstrUri, jstrType);
+}
+
+void
+AndroidBridge::GetMimeTypeFromExtension(const nsCString& aFileExt, nsCString& aMimeType) {
+    AutoLocalJNIFrame jniFrame;
+    NS_ConvertUTF8toUTF16 wFileExt(aFileExt);
+    jstring jstrExt = mJNIEnv->NewString(wFileExt.get(), wFileExt.Length());
+    jstring jstrType =  static_cast<jstring>(mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass,
+                                                                             jGetMimeTypeFromExtension,
+                                                                             jstrExt));
+    nsJNIString jniStr(jstrType);
+    aMimeType.Assign(NS_ConvertUTF16toUTF8(jniStr.get()));
+}
+
+void
 AndroidBridge::SetSurfaceView(jobject obj)
 {
     mSurfaceView.Init(obj);
 }
 
 // Available for places elsewhere in the code to link to.
 PRBool
 mozilla_AndroidBridge_SetMainThread(void *thr)
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -41,16 +41,18 @@
 #include <jni.h>
 #include <android/log.h>
 
 #include "nsCOMPtr.h"
 #include "nsIRunnable.h"
 
 #include "AndroidJavaWrappers.h"
 
+#include "nsVoidArray.h"
+
 // Some debug #defines
 // #define ANDROID_DEBUG_EVENTS
 // #define ANDROID_DEBUG_WIDGET
 
 class nsWindow;
 
 namespace mozilla {
 
@@ -97,16 +99,22 @@ public:
 
     void NotifyXreExit();
 
     void ScheduleRestart();
 
     void SetSurfaceView(jobject jobj);
     AndroidGeckoSurfaceView& SurfaceView() { return mSurfaceView; }
 
+    void GetHandlersForMimeType(const char *aMimeType, nsStringArray* aStringArray);
+
+    PRBool OpenUriExternal(nsCString& aUriSpec, nsCString& aMimeType);
+
+    void GetMimeTypeFromExtension(const nsCString& aFileExt, nsCString& aMimeType);
+
     struct AutoLocalJNIFrame {
         AutoLocalJNIFrame(int nEntries = 128) : mEntries(nEntries) {
             AndroidBridge::Bridge()->JNI()->PushLocalFrame(mEntries);
         }
         // Note! Calling Purge makes all previous local refs created in
         // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down
         // any local refs that you need to keep around in global refs!
         void Purge() {
@@ -143,16 +151,19 @@ protected:
     // other things
     jmethodID jShowIME;
     jmethodID jEnableAccelerometer;
     jmethodID jEnableLocation;
     jmethodID jReturnIMEQueryResult;
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
+    jmethodID jGetHandlersForMimeType;
+    jmethodID jOpenUriExternal;
+    jmethodID jGetMimeTypeFromExtension;
 };
 
 }
 
 extern "C" JNIEnv * GetJNIForThread();
 extern PRBool mozilla_AndroidBridge_SetMainThread(void *);
 
 #endif /* AndroidBridge_h__ */
--- a/widget/src/android/AndroidJavaWrappers.cpp
+++ b/widget/src/android/AndroidJavaWrappers.cpp
@@ -403,8 +403,17 @@ AndroidRect::Init(JNIEnv *jenv, jobject 
         mBottom = jenv->GetIntField(jobj, jBottomField);
     } else {
         mTop = 0;
         mLeft = 0;
         mRight = 0;
         mBottom = 0;
     }
 }
+
+nsJNIString::nsJNIString(jstring jstr)
+{
+    const jchar* jCharPtr = JNI()->GetStringChars(jstr, false);
+    nsresult rv;
+    Assign(jCharPtr);
+    JNI()->ReleaseStringChars(jstr, jCharPtr);
+
+}
--- a/widget/src/android/AndroidJavaWrappers.h
+++ b/widget/src/android/AndroidJavaWrappers.h
@@ -436,11 +436,17 @@ public:
         IME_BATCH_END = 0,
         IME_BATCH_BEGIN = 1,
         IME_SET_TEXT = 2,
         IME_GET_TEXT = 3,
         IME_DELETE_TEXT = 4
     };
 };
 
+class nsJNIString : public nsString
+{
+public:
+    nsJNIString(jstring jstr);
+};
+
 }
 
 #endif
--- a/xpcom/io/nsLocalFileUnix.cpp
+++ b/xpcom/io/nsLocalFileUnix.cpp
@@ -94,16 +94,21 @@
 
 #if (MOZ_PLATFORM_MAEMO == 5)
 #include <glib.h>
 #include <hildon-uri.h>
 #include <hildon-mime.h>
 #include <libosso.h>
 #endif
 
+#ifdef ANDROID
+#include "AndroidBridge.h"
+#include "nsIMIMEService.h"
+#endif
+
 #include "nsNativeCharsetUtils.h"
 #include "nsTraceRefcntImpl.h"
 
 #define ENSURE_STAT_CACHE()                     \
     PR_BEGIN_MACRO                              \
         if (!FillStatCache())                   \
              return NSRESULT_FOR_ERRNO();       \
     PR_END_MACRO
@@ -1796,16 +1801,28 @@ nsLocalFile::Launch()
       return giovfs->ShowURIForInput(mPath);
     } else if (gnomevfs) {
       /* GnomeVFS fallback */
       return gnomevfs->ShowURIForInput(mPath);
     }
     
     return NS_ERROR_FAILURE;
 #endif
+#elif defined(ANDROID)
+    // Try to get a mimetype, if this fails just use the file uri alone
+    nsresult rv;
+    nsCAutoString type;
+    nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
+    if (NS_SUCCEEDED(rv))
+        rv = mimeService->GetTypeFromFile(this, type);
+
+    nsDependentCString fileUri = NS_LITERAL_CSTRING("file://");
+    fileUri.Append(mPath);
+    mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
+    return bridge->OpenUriExternal(fileUri, type) ? NS_OK : NS_ERROR_FAILURE;
 #else
     return NS_ERROR_FAILURE;
 #endif
 }
 #endif
 
 nsresult
 NS_NewNativeLocalFile(const nsACString &path, PRBool followSymlinks, nsILocalFile **result)