summaryrefslogtreecommitdiffstats
path: root/uriloader/exthandler/android
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /uriloader/exthandler/android
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'uriloader/exthandler/android')
-rw-r--r--uriloader/exthandler/android/nsAndroidHandlerApp.cpp86
-rw-r--r--uriloader/exthandler/android/nsAndroidHandlerApp.h33
-rw-r--r--uriloader/exthandler/android/nsExternalURLHandlerService.cpp21
-rw-r--r--uriloader/exthandler/android/nsExternalURLHandlerService.h22
-rw-r--r--uriloader/exthandler/android/nsMIMEInfoAndroid.cpp414
-rw-r--r--uriloader/exthandler/android/nsMIMEInfoAndroid.h62
-rw-r--r--uriloader/exthandler/android/nsOSHelperAppService.cpp70
-rw-r--r--uriloader/exthandler/android/nsOSHelperAppService.h38
8 files changed, 746 insertions, 0 deletions
diff --git a/uriloader/exthandler/android/nsAndroidHandlerApp.cpp b/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
new file mode 100644
index 0000000000..de9f6be509
--- /dev/null
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
@@ -0,0 +1,86 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/java/GeckoAppShellWrappers.h"
+#include "nsAndroidHandlerApp.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(nsAndroidHandlerApp, nsIHandlerApp, nsISharingHandlerApp)
+
+nsAndroidHandlerApp::nsAndroidHandlerApp(const nsAString& aName,
+ const nsAString& aDescription,
+ const nsAString& aPackageName,
+ const nsAString& aClassName,
+ const nsACString& aMimeType,
+ const nsAString& aAction)
+ : mName(aName),
+ mDescription(aDescription),
+ mPackageName(aPackageName),
+ mClassName(aClassName),
+ mMimeType(aMimeType),
+ mAction(aAction) {}
+
+nsAndroidHandlerApp::~nsAndroidHandlerApp() {}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::GetName(nsAString& aName) {
+ aName.Assign(mName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::SetName(const nsAString& aName) {
+ mName.Assign(aName);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::GetDetailedDescription(nsAString& aDescription) {
+ aDescription.Assign(mDescription);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::SetDetailedDescription(const nsAString& aDescription) {
+ mDescription.Assign(aDescription);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::Equals(nsIHandlerApp* aHandlerApp, bool* aRetval) {
+ *aRetval = false;
+ if (!aHandlerApp) {
+ return NS_OK;
+ }
+
+ nsAutoString name;
+ nsAutoString detailedDescription;
+ aHandlerApp->GetName(name);
+ aHandlerApp->GetDetailedDescription(detailedDescription);
+
+ *aRetval = name.Equals(mName) && detailedDescription.Equals(mDescription);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::LaunchWithURI(
+ nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
+ nsCString uriSpec;
+ aURI->GetSpec(uriSpec);
+ return java::GeckoAppShell::OpenUriExternal(uriSpec, mMimeType, mPackageName,
+ mClassName, mAction, u""_ns)
+ ? NS_OK
+ : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsAndroidHandlerApp::Share(const nsAString& data, const nsAString& title) {
+ return java::GeckoAppShell::OpenUriExternal(data, mMimeType, mPackageName,
+ mClassName, mAction, u""_ns)
+ ? NS_OK
+ : NS_ERROR_FAILURE;
+}
diff --git a/uriloader/exthandler/android/nsAndroidHandlerApp.h b/uriloader/exthandler/android/nsAndroidHandlerApp.h
new file mode 100644
index 0000000000..dab4042fd8
--- /dev/null
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.h
@@ -0,0 +1,33 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsAndroidHandlerApp_h
+#define nsAndroidHandlerApp_h
+
+#include "nsMIMEInfoImpl.h"
+#include "nsISharingHandlerApp.h"
+
+class nsAndroidHandlerApp : public nsISharingHandlerApp {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIHANDLERAPP
+ NS_DECL_NSISHARINGHANDLERAPP
+
+ nsAndroidHandlerApp(const nsAString& aName, const nsAString& aDescription,
+ const nsAString& aPackageName,
+ const nsAString& aClassName, const nsACString& aMimeType,
+ const nsAString& aAction);
+
+ private:
+ virtual ~nsAndroidHandlerApp();
+
+ nsString mName;
+ nsString mDescription;
+ nsString mPackageName;
+ nsString mClassName;
+ nsCString mMimeType;
+ nsString mAction;
+};
+#endif
diff --git a/uriloader/exthandler/android/nsExternalURLHandlerService.cpp b/uriloader/exthandler/android/nsExternalURLHandlerService.cpp
new file mode 100644
index 0000000000..60ccbbdfe9
--- /dev/null
+++ b/uriloader/exthandler/android/nsExternalURLHandlerService.cpp
@@ -0,0 +1,21 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsExternalURLHandlerService.h"
+#include "nsMIMEInfoAndroid.h"
+
+NS_IMPL_ISUPPORTS(nsExternalURLHandlerService, nsIExternalURLHandlerService)
+
+nsExternalURLHandlerService::nsExternalURLHandlerService() {}
+
+nsExternalURLHandlerService::~nsExternalURLHandlerService() {}
+
+NS_IMETHODIMP
+nsExternalURLHandlerService::GetURLHandlerInfoFromOS(nsIURI* aURL, bool* found,
+ nsIHandlerInfo** info) {
+ // We don't want to get protocol handlers from the OS in GV; the app
+ // should take care of that in NavigationDelegate.onLoadRequest().
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
diff --git a/uriloader/exthandler/android/nsExternalURLHandlerService.h b/uriloader/exthandler/android/nsExternalURLHandlerService.h
new file mode 100644
index 0000000000..18389c5286
--- /dev/null
+++ b/uriloader/exthandler/android/nsExternalURLHandlerService.h
@@ -0,0 +1,22 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef NSEXTERNALURLHANDLERSERVICE_H
+#define NSEXTERNALURLHANDLERSERVICE_H
+
+#include "nsIExternalURLHandlerService.h"
+
+class nsExternalURLHandlerService final : public nsIExternalURLHandlerService {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIEXTERNALURLHANDLERSERVICE
+
+ nsExternalURLHandlerService();
+
+ private:
+ ~nsExternalURLHandlerService();
+};
+
+#endif // NSEXTERNALURLHANDLERSERVICE_H
diff --git a/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
new file mode 100644
index 0000000000..6d361d32c2
--- /dev/null
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
@@ -0,0 +1,414 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "nsMIMEInfoAndroid.h"
+#include "AndroidBridge.h"
+#include "nsAndroidHandlerApp.h"
+#include "nsArrayUtils.h"
+#include "nsISupportsUtils.h"
+#include "nsStringEnumerator.h"
+#include "nsNetUtil.h"
+#include "mozilla/Utf8.h"
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile) {
+ return LaunchWithFile(aFile);
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LoadUriInternal(nsIURI* aURI) {
+ nsCString uriSpec;
+ aURI->GetSpec(uriSpec);
+
+ nsCString uriScheme;
+ aURI->GetScheme(uriScheme);
+
+ nsAutoString mimeType;
+ if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) {
+ mimeType.Truncate();
+ } else {
+ CopyUTF8toUTF16(mType, mimeType);
+ }
+
+ if (java::GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec),
+ mimeType, u""_ns, u""_ns, u""_ns,
+ u""_ns)) {
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+bool nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
+ nsMIMEInfoAndroid** aMimeInfo) {
+ RefPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType);
+ mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
+ // we don't have access to the bridge, so just assume we can handle
+ // the mime type for now and let the system deal with it
+ if (!bridge) {
+ info.forget(aMimeInfo);
+ return false;
+ }
+
+ nsIHandlerApp* systemDefault = nullptr;
+
+ if (!IsUtf8(aMimeType)) return false;
+
+ NS_ConvertUTF8toUTF16 mimeType(aMimeType);
+
+ bridge->GetHandlersForMimeType(mimeType, info->mHandlerApps, &systemDefault);
+
+ if (systemDefault) info->mPrefApp = systemDefault;
+
+ nsAutoCString fileExt;
+ bridge->GetExtensionFromMimeType(aMimeType, fileExt);
+ info->SetPrimaryExtension(fileExt);
+
+ uint32_t len;
+ info->mHandlerApps->GetLength(&len);
+ if (len == 1) {
+ info.forget(aMimeInfo);
+ return false;
+ }
+
+ info.forget(aMimeInfo);
+ return true;
+}
+
+bool nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt,
+ nsMIMEInfoAndroid** aMimeInfo) {
+ nsCString mimeType;
+ if (mozilla::AndroidBridge::Bridge())
+ mozilla::AndroidBridge::Bridge()->GetMimeTypeFromExtensions(aFileExt,
+ mimeType);
+
+ // "*/*" means that the bridge didn't know.
+ if (mimeType.Equals(nsDependentCString("*/*"),
+ nsCaseInsensitiveCStringComparator))
+ return false;
+
+ bool found = GetMimeInfoForMimeType(mimeType, aMimeInfo);
+ (*aMimeInfo)->SetPrimaryExtension(aFileExt);
+ return found;
+}
+
+/**
+ * Returns MIME info for the aURL, which may contain the whole URL or only a
+ * protocol
+ */
+nsresult nsMIMEInfoAndroid::GetMimeInfoForURL(const nsACString& aURL,
+ bool* found,
+ nsIHandlerInfo** info) {
+ nsMIMEInfoAndroid* mimeinfo = new nsMIMEInfoAndroid(aURL);
+ NS_ADDREF(*info = mimeinfo);
+ *found = true;
+
+ mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
+ if (!bridge) {
+ // we don't have access to the bridge, so just assume we can handle
+ // the protocol for now and let the system deal with it
+ return NS_OK;
+ }
+
+ nsIHandlerApp* systemDefault = nullptr;
+ bridge->GetHandlersForURL(NS_ConvertUTF8toUTF16(aURL), mimeinfo->mHandlerApps,
+ &systemDefault);
+
+ if (systemDefault) mimeinfo->mPrefApp = systemDefault;
+
+ nsAutoCString fileExt;
+ nsAutoCString mimeType;
+ mimeinfo->GetType(mimeType);
+ bridge->GetExtensionFromMimeType(mimeType, fileExt);
+ mimeinfo->SetPrimaryExtension(fileExt);
+
+ uint32_t len;
+ mimeinfo->mHandlerApps->GetLength(&len);
+ if (len == 1) {
+ // Code that calls this requires an object regardless if the OS has
+ // something for us, so we return the empty object.
+ *found = false;
+ return NS_OK;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetType(nsACString& aType) {
+ aType.Assign(mType);
+ 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;
+ NS_IF_ADDREF(*aApp);
+ 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(bool* aHasDefault) {
+ uint32_t len;
+ *aHasDefault = false;
+ if (!mHandlerApps) return NS_OK;
+
+ if (NS_FAILED(mHandlerApps->GetLength(&len))) return NS_OK;
+
+ if (len == 0) return NS_OK;
+
+ *aHasDefault = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc) {
+ aDesc.Assign(u""_ns);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchWithURI(
+ nsIURI* aURI, mozilla::dom::BrowsingContext* aBrowsingContext) {
+ return mPrefApp->LaunchWithURI(aURI, aBrowsingContext);
+}
+
+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(bool* aAlwaysAsk) {
+ *aAlwaysAsk = mAlwaysAsk;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetAlwaysAskBeforeHandling(bool 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();
+ nsACString::const_iterator start, end;
+ aExtensions.BeginReading(start);
+ aExtensions.EndReading(end);
+ while (start != end) {
+ nsACString::const_iterator cursor = start;
+ mozilla::Unused << FindCharInReadable(',', cursor, end);
+ AddUniqueExtension(Substring(start, cursor));
+ // If a comma was found, skip it for the next search.
+ start = cursor != end ? ++cursor : cursor;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::ExtensionExists(const nsACString& aExtension,
+ bool* aRetVal) {
+ NS_ASSERTION(!aExtension.IsEmpty(), "no extension");
+
+ nsCString mimeType;
+ if (mozilla::AndroidBridge::Bridge()) {
+ mozilla::AndroidBridge::Bridge()->GetMimeTypeFromExtensions(aExtension,
+ mimeType);
+ }
+
+ // "*/*" means the bridge didn't find anything (i.e., extension doesn't
+ // exist).
+ *aRetVal = !mimeType.Equals(nsDependentCString("*/*"),
+ nsCaseInsensitiveCStringComparator);
+ return NS_OK;
+}
+
+void nsMIMEInfoAndroid::AddUniqueExtension(const nsACString& aExtension) {
+ if (!aExtension.IsEmpty() &&
+ !mExtensions.Contains(aExtension,
+ nsCaseInsensitiveCStringArrayComparator())) {
+ mExtensions.AppendElement(aExtension);
+ }
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::AppendExtension(const nsACString& aExtension) {
+ MOZ_ASSERT(!aExtension.IsEmpty(), "No extension");
+ AddUniqueExtension(aExtension);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPrimaryExtension(nsACString& aPrimaryExtension) {
+ if (!mExtensions.Length()) {
+ aPrimaryExtension.Truncate();
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+ aPrimaryExtension = mExtensions[0];
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::SetPrimaryExtension(const nsACString& aExtension) {
+ if (MOZ_UNLIKELY(aExtension.IsEmpty())) {
+ // Don't assert since Java may return an empty extension for unknown types.
+ return NS_ERROR_INVALID_ARG;
+ }
+ int32_t i = mExtensions.IndexOf(aExtension, 0,
+ nsCaseInsensitiveCStringArrayComparator());
+ if (i != -1) {
+ mExtensions.RemoveElementAt(i);
+ }
+ mExtensions.InsertElementAt(0, aExtension);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetMIMEType(nsACString& aMIMEType) {
+ aMIMEType.Assign(mType);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::Equals(nsIMIMEInfo* aMIMEInfo, bool* aRetVal) {
+ if (!aMIMEInfo) return NS_ERROR_NULL_POINTER;
+
+ nsAutoCString type;
+ nsresult rv = aMIMEInfo->GetMIMEType(type);
+ if (NS_FAILED(rv)) return rv;
+
+ *aRetVal = mType.Equals(type);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::GetPossibleLocalHandlers(nsIArray** aPossibleLocalHandlers) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::LaunchWithFile(nsIFile* aFile) {
+ nsCOMPtr<nsIURI> uri;
+ NS_NewFileURI(getter_AddRefs(uri), aFile);
+ return LoadUriInternal(uri);
+}
+
+NS_IMETHODIMP
+nsMIMEInfoAndroid::IsCurrentAppOSDefault(bool* aRetVal) {
+ // FIXME: this should in theory be meaningfully implemented. However, android
+ // implements its own version of nsIHandlerApp instances which internally
+ // have package and class names - but do not expose those. So to meaningfully
+ // compare the handler app would require access to those and knowing what
+ // our own package/class names are, and it's not clear how to do that.
+ // It also seems less important to do this right on Android, given that
+ // Android UI normally limits what apps you can associate with what files, so
+ // it shouldn't be possible to get into the same kind of loop as on desktop.
+ *aRetVal = false;
+ return NS_OK;
+}
+
+nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType)
+ : mType(aMIMEType),
+ mAlwaysAsk(true),
+ mPrefAction(nsIMIMEInfo::useHelperApp) {
+ mPrefApp = new nsMIMEInfoAndroid::SystemChooser(this);
+ nsresult rv;
+ mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
+ mHandlerApps->AppendElement(mPrefApp);
+}
+
+#define SYSTEMCHOOSER_NAME u"Android chooser"
+#define SYSTEMCHOOSER_DESCRIPTION \
+ u"Android's default handler application chooser"
+
+NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid::SystemChooser, nsIHandlerApp)
+
+nsresult nsMIMEInfoAndroid::SystemChooser::GetName(nsAString& aName) {
+ aName.AssignLiteral(SYSTEMCHOOSER_NAME);
+ return NS_OK;
+}
+
+nsresult nsMIMEInfoAndroid::SystemChooser::SetName(const nsAString&) {
+ return NS_OK;
+}
+
+nsresult nsMIMEInfoAndroid::SystemChooser::GetDetailedDescription(
+ nsAString& aDesc) {
+ aDesc.AssignLiteral(SYSTEMCHOOSER_DESCRIPTION);
+ return NS_OK;
+}
+
+nsresult nsMIMEInfoAndroid::SystemChooser::SetDetailedDescription(
+ const nsAString&) {
+ return NS_OK;
+}
+
+nsresult nsMIMEInfoAndroid::SystemChooser::Equals(nsIHandlerApp* aHandlerApp,
+ bool* aRetVal) {
+ *aRetVal = false;
+ if (!aHandlerApp) {
+ return NS_OK;
+ }
+
+ nsAutoString name;
+ nsAutoString detailedDescription;
+ aHandlerApp->GetName(name);
+ aHandlerApp->GetDetailedDescription(detailedDescription);
+
+ *aRetVal = name.Equals(SYSTEMCHOOSER_NAME) &&
+ detailedDescription.Equals(SYSTEMCHOOSER_DESCRIPTION);
+ return NS_OK;
+}
+
+nsresult nsMIMEInfoAndroid::SystemChooser::LaunchWithURI(
+ nsIURI* aURI, mozilla::dom::BrowsingContext*) {
+ return mOuter->LoadUriInternal(aURI);
+}
diff --git a/uriloader/exthandler/android/nsMIMEInfoAndroid.h b/uriloader/exthandler/android/nsMIMEInfoAndroid.h
new file mode 100644
index 0000000000..bdac8f97f9
--- /dev/null
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.h
@@ -0,0 +1,62 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsMIMEInfoAndroid_h
+#define nsMIMEInfoAndroid_h
+
+#include "nsMIMEInfoImpl.h"
+#include "nsIMutableArray.h"
+#include "nsAndroidHandlerApp.h"
+
+class nsMIMEInfoAndroid final : public nsIMIMEInfo {
+ public:
+ [[nodiscard]] static bool GetMimeInfoForMimeType(
+ const nsACString& aMimeType, nsMIMEInfoAndroid** aMimeInfo);
+ [[nodiscard]] static bool GetMimeInfoForFileExt(
+ const nsACString& aFileExt, nsMIMEInfoAndroid** aMimeInfo);
+
+ [[nodiscard]] static nsresult GetMimeInfoForURL(const nsACString& aURL,
+ bool* found,
+ nsIHandlerInfo** info);
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIMIMEINFO
+ NS_DECL_NSIHANDLERINFO
+
+ explicit nsMIMEInfoAndroid(const nsACString& aMIMEType);
+
+ private:
+ ~nsMIMEInfoAndroid() {}
+
+ /**
+ * Internal helper to avoid adding duplicates.
+ */
+ void AddUniqueExtension(const nsACString& aExtension);
+
+ [[nodiscard]] virtual nsresult LaunchDefaultWithFile(nsIFile* aFile);
+ [[nodiscard]] virtual nsresult LoadUriInternal(nsIURI* aURI);
+ nsCOMPtr<nsIMutableArray> mHandlerApps;
+ nsCString mType;
+ nsTArray<nsCString> mExtensions;
+ bool mAlwaysAsk;
+ nsHandlerInfoAction mPrefAction;
+ nsString mDescription;
+ nsCOMPtr<nsIHandlerApp> mPrefApp;
+
+ public:
+ class SystemChooser final : public nsIHandlerApp {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIHANDLERAPP
+ explicit SystemChooser(nsMIMEInfoAndroid* aOuter) : mOuter(aOuter) {}
+
+ private:
+ ~SystemChooser() {}
+
+ nsMIMEInfoAndroid* mOuter;
+ };
+};
+
+#endif /* nsMIMEInfoAndroid_h */
diff --git a/uriloader/exthandler/android/nsOSHelperAppService.cpp b/uriloader/exthandler/android/nsOSHelperAppService.cpp
new file mode 100644
index 0000000000..9849b66075
--- /dev/null
+++ b/uriloader/exthandler/android/nsOSHelperAppService.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsOSHelperAppService.h"
+#include "nsMIMEInfoAndroid.h"
+#include "AndroidBridge.h"
+
+nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() {}
+
+nsOSHelperAppService::~nsOSHelperAppService() {}
+
+nsresult nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
+ const nsACString& aFileExt,
+ bool* aFound,
+ nsIMIMEInfo** aMIMEInfo) {
+ RefPtr<nsMIMEInfoAndroid> mimeInfo;
+ *aFound = false;
+ if (!aMIMEType.IsEmpty())
+ *aFound = nsMIMEInfoAndroid::GetMimeInfoForMimeType(
+ aMIMEType, getter_AddRefs(mimeInfo));
+ if (!*aFound)
+ *aFound = nsMIMEInfoAndroid::GetMimeInfoForFileExt(
+ aFileExt, getter_AddRefs(mimeInfo));
+
+ // Code that calls this requires an object regardless if the OS has
+ // something for us, so we return the empty object.
+ if (!*aFound) mimeInfo = new nsMIMEInfoAndroid(aMIMEType);
+
+ mimeInfo.forget(aMIMEInfo);
+ return NS_OK;
+}
+
+nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme,
+ bool* aExists) {
+ // Support any URI barring a couple schemes we use in testing; let the
+ // app decide what to do with them.
+ nsAutoCString scheme(aScheme);
+ *aExists =
+ !scheme.Equals("unsupported"_ns) && !scheme.Equals("unknownextproto"_ns);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsOSHelperAppService::GetApplicationDescription(const nsACString& aScheme,
+ nsAString& _retval) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsOSHelperAppService::IsCurrentAppOSDefaultForProtocol(
+ const nsACString& aScheme, bool* _retval) {
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+nsresult nsOSHelperAppService::GetProtocolHandlerInfoFromOS(
+ const nsACString& aScheme, bool* found, nsIHandlerInfo** info) {
+ // We don't want to get protocol handlers from the OS in GV; the app
+ // should take care of that in NavigationDelegate.onLoadRequest().
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsIHandlerApp* nsOSHelperAppService::CreateAndroidHandlerApp(
+ const nsAString& aName, const nsAString& aDescription,
+ const nsAString& aPackageName, const nsAString& aClassName,
+ const nsACString& aMimeType, const nsAString& aAction) {
+ return new nsAndroidHandlerApp(aName, aDescription, aPackageName, aClassName,
+ aMimeType, aAction);
+}
diff --git a/uriloader/exthandler/android/nsOSHelperAppService.h b/uriloader/exthandler/android/nsOSHelperAppService.h
new file mode 100644
index 0000000000..a333c4bcd3
--- /dev/null
+++ b/uriloader/exthandler/android/nsOSHelperAppService.h
@@ -0,0 +1,38 @@
+/* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsOSHelperAppService_h
+#define nsOSHelperAppService_h
+
+#include "nsCExternalHandlerService.h"
+#include "nsExternalHelperAppService.h"
+
+class nsOSHelperAppService : public nsExternalHelperAppService {
+ public:
+ nsOSHelperAppService();
+ virtual ~nsOSHelperAppService();
+
+ nsresult GetMIMEInfoFromOS(const nsACString& aMIMEType,
+ const nsACString& aFileExt, bool* aFound,
+ nsIMIMEInfo** aMIMEInfo) override;
+
+ [[nodiscard]] nsresult OSProtocolHandlerExists(const char* aScheme,
+ bool* aExists) override;
+
+ NS_IMETHOD GetProtocolHandlerInfoFromOS(const nsACString& aScheme,
+ bool* found,
+ nsIHandlerInfo** _retval) override;
+ NS_IMETHOD GetApplicationDescription(const nsACString& aScheme,
+ nsAString& _retval) override;
+ NS_IMETHOD IsCurrentAppOSDefaultForProtocol(const nsACString& aScheme,
+ bool* _retval) override;
+
+ static nsIHandlerApp* CreateAndroidHandlerApp(
+ const nsAString& aName, const nsAString& aDescription,
+ const nsAString& aPackageName, const nsAString& aClassName,
+ const nsACString& aMimeType, const nsAString& aAction = u""_ns);
+};
+
+#endif /* nsOSHelperAppService_h */