|
1 /* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #include "nsMIMEInfoAndroid.h" |
|
6 #include "AndroidBridge.h" |
|
7 #include "nsAndroidHandlerApp.h" |
|
8 #include "nsArrayUtils.h" |
|
9 #include "nsISupportsUtils.h" |
|
10 #include "nsStringEnumerator.h" |
|
11 #include "nsNetUtil.h" |
|
12 |
|
13 using namespace mozilla::widget::android; |
|
14 |
|
15 NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo) |
|
16 |
|
17 NS_IMETHODIMP |
|
18 nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile) |
|
19 { |
|
20 return LaunchWithFile(aFile); |
|
21 } |
|
22 |
|
23 NS_IMETHODIMP |
|
24 nsMIMEInfoAndroid::LoadUriInternal(nsIURI * aURI) |
|
25 { |
|
26 nsCString uriSpec; |
|
27 aURI->GetSpec(uriSpec); |
|
28 |
|
29 nsCString uriScheme; |
|
30 aURI->GetScheme(uriScheme); |
|
31 |
|
32 nsAutoString mimeType; |
|
33 if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) { |
|
34 mimeType = EmptyString(); |
|
35 } else { |
|
36 mimeType = NS_ConvertUTF8toUTF16(mType); |
|
37 } |
|
38 |
|
39 if (GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), mimeType)) { |
|
40 return NS_OK; |
|
41 } |
|
42 return NS_ERROR_FAILURE; |
|
43 } |
|
44 |
|
45 bool |
|
46 nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType, |
|
47 nsMIMEInfoAndroid** aMimeInfo) |
|
48 { |
|
49 nsRefPtr<nsMIMEInfoAndroid> info = new nsMIMEInfoAndroid(aMimeType); |
|
50 mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge(); |
|
51 // we don't have access to the bridge, so just assume we can handle |
|
52 // the mime type for now and let the system deal with it |
|
53 if (!bridge){ |
|
54 info.forget(aMimeInfo); |
|
55 return false; |
|
56 } |
|
57 |
|
58 nsIHandlerApp* systemDefault = nullptr; |
|
59 |
|
60 if (!IsUTF8(aMimeType, true)) |
|
61 return false; |
|
62 |
|
63 NS_ConvertUTF8toUTF16 mimeType(aMimeType); |
|
64 |
|
65 bridge->GetHandlersForMimeType(mimeType, |
|
66 info->mHandlerApps, &systemDefault); |
|
67 |
|
68 if (systemDefault) |
|
69 info->mPrefApp = systemDefault; |
|
70 |
|
71 nsAutoCString fileExt; |
|
72 bridge->GetExtensionFromMimeType(aMimeType, fileExt); |
|
73 info->SetPrimaryExtension(fileExt); |
|
74 |
|
75 uint32_t len; |
|
76 info->mHandlerApps->GetLength(&len); |
|
77 if (len == 1) { |
|
78 info.forget(aMimeInfo); |
|
79 return false; |
|
80 } |
|
81 |
|
82 info.forget(aMimeInfo); |
|
83 return true; |
|
84 } |
|
85 |
|
86 bool |
|
87 nsMIMEInfoAndroid::GetMimeInfoForFileExt(const nsACString& aFileExt, |
|
88 nsMIMEInfoAndroid **aMimeInfo) |
|
89 { |
|
90 nsCString mimeType; |
|
91 if (mozilla::AndroidBridge::Bridge()) |
|
92 mozilla::AndroidBridge::Bridge()-> |
|
93 GetMimeTypeFromExtensions(aFileExt, mimeType); |
|
94 |
|
95 // "*/*" means that the bridge didn't know. |
|
96 if (mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator())) |
|
97 return false; |
|
98 |
|
99 bool found = GetMimeInfoForMimeType(mimeType, aMimeInfo); |
|
100 (*aMimeInfo)->SetPrimaryExtension(aFileExt); |
|
101 return found; |
|
102 } |
|
103 |
|
104 /** |
|
105 * Returns MIME info for the aURL, which may contain the whole URL or only a protocol |
|
106 */ |
|
107 nsresult |
|
108 nsMIMEInfoAndroid::GetMimeInfoForURL(const nsACString &aURL, |
|
109 bool *found, |
|
110 nsIHandlerInfo **info) |
|
111 { |
|
112 nsMIMEInfoAndroid *mimeinfo = new nsMIMEInfoAndroid(aURL); |
|
113 NS_ADDREF(*info = mimeinfo); |
|
114 *found = true; |
|
115 |
|
116 mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge(); |
|
117 if (!bridge) { |
|
118 // we don't have access to the bridge, so just assume we can handle |
|
119 // the protocol for now and let the system deal with it |
|
120 return NS_OK; |
|
121 } |
|
122 |
|
123 nsIHandlerApp* systemDefault = nullptr; |
|
124 bridge->GetHandlersForURL(NS_ConvertUTF8toUTF16(aURL), |
|
125 mimeinfo->mHandlerApps, &systemDefault); |
|
126 |
|
127 if (systemDefault) |
|
128 mimeinfo->mPrefApp = systemDefault; |
|
129 |
|
130 |
|
131 nsAutoCString fileExt; |
|
132 nsAutoCString mimeType; |
|
133 mimeinfo->GetType(mimeType); |
|
134 bridge->GetExtensionFromMimeType(mimeType, fileExt); |
|
135 mimeinfo->SetPrimaryExtension(fileExt); |
|
136 |
|
137 uint32_t len; |
|
138 mimeinfo->mHandlerApps->GetLength(&len); |
|
139 if (len == 1) { |
|
140 // Code that calls this requires an object regardless if the OS has |
|
141 // something for us, so we return the empty object. |
|
142 *found = false; |
|
143 return NS_OK; |
|
144 } |
|
145 |
|
146 return NS_OK; |
|
147 } |
|
148 |
|
149 NS_IMETHODIMP |
|
150 nsMIMEInfoAndroid::GetType(nsACString& aType) |
|
151 { |
|
152 aType.Assign(mType); |
|
153 return NS_OK; |
|
154 } |
|
155 |
|
156 NS_IMETHODIMP |
|
157 nsMIMEInfoAndroid::GetDescription(nsAString& aDesc) |
|
158 { |
|
159 aDesc.Assign(mDescription); |
|
160 return NS_OK; |
|
161 } |
|
162 |
|
163 NS_IMETHODIMP |
|
164 nsMIMEInfoAndroid::SetDescription(const nsAString& aDesc) |
|
165 { |
|
166 mDescription.Assign(aDesc); |
|
167 return NS_OK; |
|
168 } |
|
169 |
|
170 NS_IMETHODIMP |
|
171 nsMIMEInfoAndroid::GetPreferredApplicationHandler(nsIHandlerApp** aApp) |
|
172 { |
|
173 *aApp = mPrefApp; |
|
174 NS_IF_ADDREF(*aApp); |
|
175 return NS_OK; |
|
176 } |
|
177 |
|
178 NS_IMETHODIMP |
|
179 nsMIMEInfoAndroid::SetPreferredApplicationHandler(nsIHandlerApp* aApp) |
|
180 { |
|
181 mPrefApp = aApp; |
|
182 return NS_OK; |
|
183 } |
|
184 |
|
185 NS_IMETHODIMP |
|
186 nsMIMEInfoAndroid::GetPossibleApplicationHandlers(nsIMutableArray **aHandlerApps) |
|
187 { |
|
188 if (!mHandlerApps) |
|
189 mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID); |
|
190 |
|
191 if (!mHandlerApps) |
|
192 return NS_ERROR_OUT_OF_MEMORY; |
|
193 |
|
194 *aHandlerApps = mHandlerApps; |
|
195 NS_IF_ADDREF(*aHandlerApps); |
|
196 return NS_OK; |
|
197 } |
|
198 |
|
199 NS_IMETHODIMP |
|
200 nsMIMEInfoAndroid::GetHasDefaultHandler(bool* aHasDefault) |
|
201 { |
|
202 uint32_t len; |
|
203 *aHasDefault = false; |
|
204 if (!mHandlerApps) |
|
205 return NS_OK; |
|
206 |
|
207 if (NS_FAILED(mHandlerApps->GetLength(&len))) |
|
208 return NS_OK; |
|
209 |
|
210 if (len == 0) |
|
211 return NS_OK; |
|
212 |
|
213 *aHasDefault = true; |
|
214 return NS_OK; |
|
215 } |
|
216 |
|
217 NS_IMETHODIMP |
|
218 nsMIMEInfoAndroid::GetDefaultDescription(nsAString& aDesc) |
|
219 { |
|
220 aDesc.Assign(EmptyString()); |
|
221 return NS_OK; |
|
222 } |
|
223 |
|
224 NS_IMETHODIMP |
|
225 nsMIMEInfoAndroid::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor* req) |
|
226 { |
|
227 return mPrefApp->LaunchWithURI(aURI, req); |
|
228 } |
|
229 |
|
230 NS_IMETHODIMP |
|
231 nsMIMEInfoAndroid::GetPreferredAction(nsHandlerInfoAction* aPrefAction) |
|
232 { |
|
233 *aPrefAction = mPrefAction; |
|
234 return NS_OK; |
|
235 } |
|
236 |
|
237 NS_IMETHODIMP |
|
238 nsMIMEInfoAndroid::SetPreferredAction(nsHandlerInfoAction aPrefAction) |
|
239 { |
|
240 mPrefAction = aPrefAction; |
|
241 return NS_OK; |
|
242 } |
|
243 |
|
244 NS_IMETHODIMP |
|
245 nsMIMEInfoAndroid::GetAlwaysAskBeforeHandling(bool* aAlwaysAsk) |
|
246 { |
|
247 *aAlwaysAsk = mAlwaysAsk; |
|
248 return NS_OK; |
|
249 } |
|
250 |
|
251 NS_IMETHODIMP |
|
252 nsMIMEInfoAndroid::SetAlwaysAskBeforeHandling(bool aAlwaysAsk) |
|
253 { |
|
254 mAlwaysAsk = aAlwaysAsk; |
|
255 return NS_OK; |
|
256 } |
|
257 |
|
258 NS_IMETHODIMP |
|
259 nsMIMEInfoAndroid::GetFileExtensions(nsIUTF8StringEnumerator** aResult) |
|
260 { |
|
261 return NS_NewUTF8StringEnumerator(aResult, &mExtensions, this); |
|
262 } |
|
263 |
|
264 NS_IMETHODIMP |
|
265 nsMIMEInfoAndroid::SetFileExtensions(const nsACString & aExtensions) |
|
266 { |
|
267 mExtensions.Clear(); |
|
268 nsCString extList(aExtensions); |
|
269 |
|
270 int32_t breakLocation = -1; |
|
271 while ( (breakLocation = extList.FindChar(',')) != -1) |
|
272 { |
|
273 mExtensions.AppendElement(Substring(extList.get(), extList.get() + breakLocation)); |
|
274 extList.Cut(0, breakLocation + 1); |
|
275 } |
|
276 if (!extList.IsEmpty()) |
|
277 mExtensions.AppendElement(extList); |
|
278 return NS_OK; |
|
279 } |
|
280 |
|
281 NS_IMETHODIMP |
|
282 nsMIMEInfoAndroid::ExtensionExists(const nsACString & aExtension, bool *aRetVal) |
|
283 { |
|
284 NS_ASSERTION(!aExtension.IsEmpty(), "no extension"); |
|
285 |
|
286 nsCString mimeType; |
|
287 if (mozilla::AndroidBridge::Bridge()) { |
|
288 mozilla::AndroidBridge::Bridge()-> |
|
289 GetMimeTypeFromExtensions(aExtension, mimeType); |
|
290 } |
|
291 |
|
292 // "*/*" means the bridge didn't find anything (i.e., extension doesn't exist). |
|
293 *aRetVal = !mimeType.Equals(nsDependentCString("*/*"), nsCaseInsensitiveCStringComparator()); |
|
294 return NS_OK; |
|
295 } |
|
296 |
|
297 NS_IMETHODIMP |
|
298 nsMIMEInfoAndroid::AppendExtension(const nsACString & aExtension) |
|
299 { |
|
300 mExtensions.AppendElement(aExtension); |
|
301 return NS_OK; |
|
302 } |
|
303 |
|
304 NS_IMETHODIMP |
|
305 nsMIMEInfoAndroid::GetPrimaryExtension(nsACString & aPrimaryExtension) |
|
306 { |
|
307 if (!mExtensions.Length()) |
|
308 return NS_ERROR_NOT_INITIALIZED; |
|
309 |
|
310 aPrimaryExtension = mExtensions[0]; |
|
311 return NS_OK; |
|
312 } |
|
313 |
|
314 NS_IMETHODIMP |
|
315 nsMIMEInfoAndroid::SetPrimaryExtension(const nsACString & aExtension) |
|
316 { |
|
317 uint32_t extCount = mExtensions.Length(); |
|
318 uint8_t i; |
|
319 bool found = false; |
|
320 for (i=0; i < extCount; i++) { |
|
321 const nsCString& ext = mExtensions[i]; |
|
322 if (ext.Equals(aExtension, nsCaseInsensitiveCStringComparator())) { |
|
323 found = true; |
|
324 break; |
|
325 } |
|
326 } |
|
327 if (found) { |
|
328 mExtensions.RemoveElementAt(i); |
|
329 } |
|
330 |
|
331 mExtensions.InsertElementAt(0, aExtension); |
|
332 |
|
333 return NS_OK; |
|
334 } |
|
335 |
|
336 NS_IMETHODIMP |
|
337 nsMIMEInfoAndroid::GetMIMEType(nsACString & aMIMEType) |
|
338 { |
|
339 aMIMEType.Assign(mType); |
|
340 return NS_OK; |
|
341 } |
|
342 |
|
343 NS_IMETHODIMP |
|
344 nsMIMEInfoAndroid::Equals(nsIMIMEInfo *aMIMEInfo, bool *aRetVal) |
|
345 { |
|
346 if (!aMIMEInfo) return NS_ERROR_NULL_POINTER; |
|
347 |
|
348 nsAutoCString type; |
|
349 nsresult rv = aMIMEInfo->GetMIMEType(type); |
|
350 if (NS_FAILED(rv)) return rv; |
|
351 |
|
352 *aRetVal = mType.Equals(type); |
|
353 |
|
354 return NS_OK; |
|
355 } |
|
356 |
|
357 NS_IMETHODIMP |
|
358 nsMIMEInfoAndroid::GetPossibleLocalHandlers(nsIArray * *aPossibleLocalHandlers) |
|
359 { |
|
360 return NS_ERROR_NOT_IMPLEMENTED; |
|
361 } |
|
362 |
|
363 NS_IMETHODIMP |
|
364 nsMIMEInfoAndroid::LaunchWithFile(nsIFile *aFile) |
|
365 { |
|
366 nsCOMPtr<nsIURI> uri; |
|
367 NS_NewFileURI(getter_AddRefs(uri), aFile); |
|
368 return LoadUriInternal(uri); |
|
369 } |
|
370 |
|
371 nsMIMEInfoAndroid::nsMIMEInfoAndroid(const nsACString& aMIMEType) : |
|
372 mType(aMIMEType), mAlwaysAsk(true), |
|
373 mPrefAction(nsIMIMEInfo::useHelperApp) |
|
374 { |
|
375 mPrefApp = new nsMIMEInfoAndroid::SystemChooser(this); |
|
376 nsresult rv; |
|
377 mHandlerApps = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); |
|
378 mHandlerApps->AppendElement(mPrefApp, false); |
|
379 } |
|
380 |
|
381 NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid::SystemChooser, nsIHandlerApp) |
|
382 |
|
383 |
|
384 nsresult nsMIMEInfoAndroid::SystemChooser::GetName(nsAString & aName) { |
|
385 aName.Assign(NS_LITERAL_STRING("Android chooser")); |
|
386 return NS_OK; |
|
387 } |
|
388 |
|
389 nsresult |
|
390 nsMIMEInfoAndroid::SystemChooser::SetName(const nsAString&) { |
|
391 return NS_OK; |
|
392 } |
|
393 |
|
394 nsresult |
|
395 nsMIMEInfoAndroid::SystemChooser::GetDetailedDescription(nsAString & aDesc) { |
|
396 aDesc.Assign(NS_LITERAL_STRING("Android's default handler application chooser")); |
|
397 return NS_OK; |
|
398 } |
|
399 |
|
400 nsresult |
|
401 nsMIMEInfoAndroid::SystemChooser::SetDetailedDescription(const nsAString&) { |
|
402 return NS_OK; |
|
403 } |
|
404 |
|
405 nsresult |
|
406 nsMIMEInfoAndroid::SystemChooser::Equals(nsIHandlerApp *aHandlerApp, bool *aRetVal) { |
|
407 nsCOMPtr<nsMIMEInfoAndroid::SystemChooser> info = do_QueryInterface(aHandlerApp); |
|
408 if (info) |
|
409 return mOuter->Equals(info->mOuter, aRetVal); |
|
410 *aRetVal = false; |
|
411 return NS_OK; |
|
412 } |
|
413 |
|
414 nsresult |
|
415 nsMIMEInfoAndroid::SystemChooser::LaunchWithURI(nsIURI* aURI, nsIInterfaceRequestor*) |
|
416 { |
|
417 return mOuter->LoadUriInternal(aURI); |
|
418 } |