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 idunknown
push userunknown
push dateunknown
reviewersvlad
bugs565138
milestone1.9.3a6pre
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)