michael@0: /* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #include "nsMIMEInfoAndroid.h" michael@0: #include "AndroidBridge.h" michael@0: #include "nsAndroidHandlerApp.h" michael@0: #include "nsArrayUtils.h" michael@0: #include "nsISupportsUtils.h" michael@0: #include "nsStringEnumerator.h" michael@0: #include "nsNetUtil.h" michael@0: michael@0: using namespace mozilla::widget::android; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo) michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile) michael@0: { michael@0: return LaunchWithFile(aFile); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI) michael@0: { michael@0: nsCString uriSpec; michael@0: aURI->GetSpec(uriSpec); michael@0: michael@0: nsCString uriScheme; michael@0: aURI->GetScheme(uriScheme); michael@0: michael@0: nsAutoString mimeType; michael@0: if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) { michael@0: mimeType = EmptyString(); michael@0: } else { michael@0: mimeType = NS_ConvertUTF8toUTF16(mType); michael@0: } michael@0: michael@0: if (GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), mimeType)) { michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: bool michael@0: nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType, michael@0: nsMIMEInfoAndroid** aMimeInfo) michael@0: { michael@0: nsRefPtr info = new nsMIMEInfoAndroid(aMimeType); michael@0: mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge(); michael@0: // we don't have access to the bridge, so just assume we can handle michael@0: // the mime type for now and let the system deal with it michael@0: if (!bridge){ michael@0: info.forget(aMimeInfo); michael@0: return false; michael@0: } michael@0: michael@0: nsIHandlerApp* systemDefault = nullptr; michael@0: michael@0: if (!IsUTF8(aMimeType, true)) michael@0: return false; michael@0: michael@0: NS_ConvertUTF8toUTF16 mimeType(aMimeType); michael@0: michael@0: bridge->GetHandlersForMimeType(mimeType, michael@0: info->mHandlerApps, &systemDefault); michael@0: michael@0: if (systemDefault) michael@0: info->mPrefApp = systemDefault; michael@0: michael@0: nsAutoCString fileExt; michael@0: bridge->GetExtensionFromMimeType(aMimeType, fileExt); michael@0: info->SetPrimaryExtension(fileExt); michael@0: michael@0: uint32_t len; michael@0: info->mHandlerApps->GetLength(&len); michael@0: if (len == 1) { michael@0: info.forget(aMimeInfo); michael@0: return false; michael@0: } michael@0: michael@0: info.forget(aMimeInfo); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt, michael@0: nsMIMEInfoAndroid **aMimeInfo) michael@0: { michael@0: nsCString mimeType; michael@0: if (mozilla::AndroidBridge::Bridge()) michael@0: mozilla::AndroidBridge::Bridge()-> michael@0: GetMimeTypeFromExtensions(aFileExt, mimeType); michael@0: michael@0: // "*/*" means that the bridge didn't know. michael@0: if (mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator())) michael@0: return false; michael@0: michael@0: bool found = GetMimeInfoForMimeType(mimeType, aMimeInfo); michael@0: (*aMimeInfo)->SetPrimaryExtension(aFileExt); michael@0: return found; michael@0: } michael@0: michael@0: /** michael@0: * Returns MIME info for the aURL, which may contain the whole URL or only a protocol michael@0: */ michael@0: nsresult michael@0: nsMIMEInfoAndroid::GetMimeInfoForURL(const nsACString &aURL, michael@0: bool *found, michael@0: nsIHandlerInfo **info) michael@0: { michael@0: nsMIMEInfoAndroid *mimeinfo = new nsMIMEInfoAndroid(aURL); michael@0: NS_ADDREF(*info = mimeinfo); michael@0: *found = true; michael@0: michael@0: mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge(); michael@0: if (!bridge) { michael@0: // we don't have access to the bridge, so just assume we can handle michael@0: // the protocol for now and let the system deal with it michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIHandlerApp* systemDefault = nullptr; michael@0: bridge->GetHandlersForURL(NS_ConvertUTF8toUTF16(aURL), michael@0: mimeinfo->mHandlerApps, &systemDefault); michael@0: michael@0: if (systemDefault) michael@0: mimeinfo->mPrefApp = systemDefault; michael@0: michael@0: michael@0: nsAutoCString fileExt; michael@0: nsAutoCString mimeType; michael@0: mimeinfo->GetType(mimeType); michael@0: bridge->GetExtensionFromMimeType(mimeType, fileExt); michael@0: mimeinfo->SetPrimaryExtension(fileExt); michael@0: michael@0: uint32_t len; michael@0: mimeinfo->mHandlerApps->GetLength(&len); michael@0: if (len == 1) { michael@0: // Code that calls this requires an object regardless if the OS has michael@0: // something for us, so we return the empty object. michael@0: *found = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetType(nsACString& aType) michael@0: { michael@0: aType.Assign(mType); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetDescription(nsAString& aDesc) michael@0: { michael@0: aDesc.Assign(mDescription); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetDescription(const nsAString& aDesc) michael@0: { michael@0: mDescription.Assign(aDesc); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetPreferredApplicationHandler(nsIHandlerApp** aApp) michael@0: { michael@0: *aApp = mPrefApp; michael@0: NS_IF_ADDREF(*aApp); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetPreferredApplicationHandler(nsIHandlerApp* aApp) michael@0: { michael@0: mPrefApp = aApp; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetPossibleApplicationHandlers(nsIMutableArray **aHandlerApps) michael@0: { michael@0: if (!mHandlerApps) michael@0: mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID); michael@0: michael@0: if (!mHandlerApps) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: *aHandlerApps = mHandlerApps; michael@0: NS_IF_ADDREF(*aHandlerApps); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetHasDefaultHandler(bool* aHasDefault) michael@0: { michael@0: uint32_t len; michael@0: *aHasDefault = false; michael@0: if (!mHandlerApps) michael@0: return NS_OK; michael@0: michael@0: if (NS_FAILED(mHandlerApps->GetLength(&len))) michael@0: return NS_OK; michael@0: michael@0: if (len == 0) michael@0: return NS_OK; michael@0: michael@0: *aHasDefault = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc) michael@0: { michael@0: aDesc.Assign(EmptyString()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* req) michael@0: { michael@0: return mPrefApp->LaunchWithURI(aURI, req); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetPreferredAction(nsHandlerInfoAction* aPrefAction) michael@0: { michael@0: *aPrefAction = mPrefAction; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetPreferredAction(nsHandlerInfoAction aPrefAction) michael@0: { michael@0: mPrefAction = aPrefAction; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetAlwaysAskBeforeHandling(bool* aAlwaysAsk) michael@0: { michael@0: *aAlwaysAsk = mAlwaysAsk; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetAlwaysAskBeforeHandling(bool aAlwaysAsk) michael@0: { michael@0: mAlwaysAsk = aAlwaysAsk; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetFileExtensions(nsIUTF8StringEnumerator** aResult) michael@0: { michael@0: return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetFileExtensions(const nsACString & aExtensions) michael@0: { michael@0: mExtensions.Clear(); michael@0: nsCString extList(aExtensions); michael@0: michael@0: int32_t breakLocation = -1; michael@0: while ( (breakLocation = extList.FindChar(',')) != -1) michael@0: { michael@0: mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation)); michael@0: extList.Cut(0, breakLocation + 1); michael@0: } michael@0: if (!extList.IsEmpty()) michael@0: mExtensions.AppendElement(extList); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::ExtensionExists(const nsACString & aExtension, bool *aRetVal) michael@0: { michael@0: NS_ASSERTION(!aExtension.IsEmpty(), "no extension"); michael@0: michael@0: nsCString mimeType; michael@0: if (mozilla::AndroidBridge::Bridge()) { michael@0: mozilla::AndroidBridge::Bridge()-> michael@0: GetMimeTypeFromExtensions(aExtension, mimeType); michael@0: } michael@0: michael@0: // "*/*" means the bridge didn't find anything (i.e., extension doesn't exist). michael@0: *aRetVal = !mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::AppendExtension(const nsACString & aExtension) michael@0: { michael@0: mExtensions.AppendElement(aExtension); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetPrimaryExtension(nsACString & aPrimaryExtension) michael@0: { michael@0: if (!mExtensions.Length()) michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: michael@0: aPrimaryExtension = mExtensions[0]; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::SetPrimaryExtension(const nsACString & aExtension) michael@0: { michael@0: uint32_t extCount = mExtensions.Length(); michael@0: uint8_t i; michael@0: bool found = false; michael@0: for (i=0; i < extCount; i++) { michael@0: const nsCString& ext = mExtensions[i]; michael@0: if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) { michael@0: found = true; michael@0: break; michael@0: } michael@0: } michael@0: if (found) { michael@0: mExtensions.RemoveElementAt(i); michael@0: } michael@0: michael@0: mExtensions.InsertElementAt(0, aExtension); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetMIMEType(nsACString & aMIMEType) michael@0: { michael@0: aMIMEType.Assign(mType); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::Equals(nsIMIMEInfo *aMIMEInfo, bool *aRetVal) michael@0: { michael@0: if (!aMIMEInfo) return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsAutoCString type; michael@0: nsresult rv = aMIMEInfo->GetMIMEType(type); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: *aRetVal = mType.Equals(type); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers) michael@0: { michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsMIMEInfoAndroid::LaunchWithFile(nsIFile *aFile) michael@0: { michael@0: nsCOMPtr uri; michael@0: NS_NewFileURI(getter_AddRefs(uri), aFile); michael@0: return LoadUriInternal(uri); michael@0: } michael@0: michael@0: nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType) : michael@0: mType(aMIMEType), mAlwaysAsk(true), michael@0: mPrefAction(nsIMIMEInfo::useHelperApp) michael@0: { michael@0: mPrefApp = new nsMIMEInfoAndroid::SystemChooser(this); michael@0: nsresult rv; michael@0: mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); michael@0: mHandlerApps->AppendElement(mPrefApp, false); michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid::SystemChooser, nsIHandlerApp) michael@0: michael@0: michael@0: nsresult nsMIMEInfoAndroid::SystemChooser::GetName(nsAString & aName) { michael@0: aName.Assign(NS_LITERAL_STRING("Android chooser")); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMIMEInfoAndroid::SystemChooser::SetName(const nsAString&) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMIMEInfoAndroid::SystemChooser::GetDetailedDescription(nsAString & aDesc) { michael@0: aDesc.Assign(NS_LITERAL_STRING("Android's default handler application chooser")); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMIMEInfoAndroid::SystemChooser::SetDetailedDescription(const nsAString&) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMIMEInfoAndroid::SystemChooser::Equals(nsIHandlerApp *aHandlerApp, bool *aRetVal) { michael@0: nsCOMPtr info = do_QueryInterface(aHandlerApp); michael@0: if (info) michael@0: return mOuter->Equals(info->mOuter, aRetVal); michael@0: *aRetVal = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: nsMIMEInfoAndroid::SystemChooser::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor*) michael@0: { michael@0: return mOuter->LoadUriInternal(aURI); michael@0: }