Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c++; c-basic-offset: 4; 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/. */
6 #include "mozilla/Hal.h"
7 #include "nsIFile.h"
8 #include "nsString.h"
10 #include "AndroidBridge.h"
11 #include "AndroidGraphicBuffer.h"
13 #include <jni.h>
14 #include <pthread.h>
15 #include <dlfcn.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <sched.h>
20 #include "nsAppShell.h"
21 #include "nsWindow.h"
22 #include <android/log.h>
23 #include "nsIObserverService.h"
24 #include "mozilla/Services.h"
25 #include "nsThreadUtils.h"
27 #ifdef MOZ_CRASHREPORTER
28 #include "nsICrashReporter.h"
29 #include "nsExceptionHandler.h"
30 #endif
32 #include "mozilla/unused.h"
34 #include "mozilla/dom/SmsMessage.h"
35 #include "mozilla/dom/mobilemessage/Constants.h"
36 #include "mozilla/dom/mobilemessage/Types.h"
37 #include "mozilla/dom/mobilemessage/PSms.h"
38 #include "mozilla/dom/mobilemessage/SmsParent.h"
39 #include "mozilla/layers/APZCTreeManager.h"
40 #include "nsIMobileMessageDatabaseService.h"
41 #include "nsPluginInstanceOwner.h"
42 #include "nsSurfaceTexture.h"
43 #include "GeckoProfiler.h"
44 #include "nsMemoryPressure.h"
46 using namespace mozilla;
47 using namespace mozilla::dom;
48 using namespace mozilla::dom::mobilemessage;
49 using namespace mozilla::layers;
50 using namespace mozilla::widget::android;
52 /* Forward declare all the JNI methods as extern "C" */
54 extern "C" {
55 /*
56 * Incoming JNI methods
57 */
59 NS_EXPORT void JNICALL
60 Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass jc)
61 {
62 AndroidBridge::ConstructBridge(jenv);
63 }
65 NS_EXPORT void JNICALL
66 Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *jenv, jclass jc, jobject event)
67 {
68 // poke the appshell
69 if (nsAppShell::gAppShell)
70 nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeFromJavaObject(jenv, event));
71 }
73 NS_EXPORT void JNICALL
74 Java_org_mozilla_gecko_GeckoAppShell_processNextNativeEvent(JNIEnv *jenv, jclass, jboolean mayWait)
75 {
76 // poke the appshell
77 if (nsAppShell::gAppShell)
78 nsAppShell::gAppShell->ProcessNextNativeEvent(mayWait != JNI_FALSE);
79 }
81 NS_EXPORT void JNICALL
82 Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv *jenv, jclass, jobject obj)
83 {
84 AndroidBridge::Bridge()->SetLayerClient(jenv, obj);
85 }
87 NS_EXPORT void JNICALL
88 Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc)
89 {
90 if (nsAppShell::gAppShell)
91 nsAppShell::gAppShell->OnResume();
92 }
94 NS_EXPORT void JNICALL
95 Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *jenv, jclass, jstring jStackTrace)
96 {
97 #ifdef MOZ_CRASHREPORTER
98 const nsJNIString stackTrace16(jStackTrace, jenv);
99 const NS_ConvertUTF16toUTF8 stackTrace8(stackTrace16);
100 CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("JavaStackTrace"), stackTrace8);
101 #endif // MOZ_CRASHREPORTER
103 abort();
104 }
106 NS_EXPORT void JNICALL
107 Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass,
108 jdouble aLevel,
109 jboolean aCharging,
110 jdouble aRemainingTime)
111 {
112 class NotifyBatteryChangeRunnable : public nsRunnable {
113 public:
114 NotifyBatteryChangeRunnable(double aLevel, bool aCharging, double aRemainingTime)
115 : mLevel(aLevel)
116 , mCharging(aCharging)
117 , mRemainingTime(aRemainingTime)
118 {}
120 NS_IMETHODIMP Run() {
121 hal::NotifyBatteryChange(hal::BatteryInformation(mLevel, mCharging, mRemainingTime));
122 return NS_OK;
123 }
125 private:
126 double mLevel;
127 bool mCharging;
128 double mRemainingTime;
129 };
131 nsCOMPtr<nsIRunnable> runnable = new NotifyBatteryChangeRunnable(aLevel, aCharging, aRemainingTime);
132 NS_DispatchToMainThread(runnable);
133 }
135 #ifdef MOZ_WEBSMS_BACKEND
137 NS_EXPORT void JNICALL
138 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived(JNIEnv* jenv, jclass,
139 jstring aSender,
140 jstring aBody,
141 jint aMessageClass,
142 jlong aTimestamp)
143 {
144 class NotifySmsReceivedRunnable : public nsRunnable {
145 public:
146 NotifySmsReceivedRunnable(const SmsMessageData& aMessageData)
147 : mMessageData(aMessageData)
148 {}
150 NS_IMETHODIMP Run() {
151 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
152 if (!obs) {
153 return NS_OK;
154 }
156 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
157 obs->NotifyObservers(message, kSmsReceivedObserverTopic, nullptr);
158 return NS_OK;
159 }
161 private:
162 SmsMessageData mMessageData;
163 };
165 // TODO Need to correct the message `threadId` parameter value. Bug 859098
166 SmsMessageData message(0, 0, eDeliveryState_Received, eDeliveryStatus_Success,
167 nsJNIString(aSender, jenv), EmptyString(),
168 nsJNIString(aBody, jenv),
169 static_cast<MessageClass>(aMessageClass),
170 aTimestamp, false);
172 nsCOMPtr<nsIRunnable> runnable = new NotifySmsReceivedRunnable(message);
173 NS_DispatchToMainThread(runnable);
174 }
176 NS_EXPORT void JNICALL
177 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent(JNIEnv* jenv, jclass,
178 jint aId,
179 jstring aReceiver,
180 jstring aBody,
181 jlong aTimestamp,
182 jint aRequestId)
183 {
184 class NotifySmsSentRunnable : public nsRunnable {
185 public:
186 NotifySmsSentRunnable(const SmsMessageData& aMessageData,
187 int32_t aRequestId)
188 : mMessageData(aMessageData)
189 , mRequestId(aRequestId)
190 {}
192 NS_IMETHODIMP Run() {
193 /*
194 * First, we are going to notify all SmsManager that a message has
195 * been sent. Then, we will notify the SmsRequest object about it.
196 */
197 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
198 if (!obs) {
199 return NS_OK;
200 }
202 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
203 obs->NotifyObservers(message, kSmsSentObserverTopic, nullptr);
205 nsCOMPtr<nsIMobileMessageCallback> request =
206 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
207 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
209 request->NotifyMessageSent(message);
210 return NS_OK;
211 }
213 private:
214 SmsMessageData mMessageData;
215 int32_t mRequestId;
216 };
218 // TODO Need to add the message `messageClass` parameter value. Bug 804476
219 // TODO Need to correct the message `threadId` parameter value. Bug 859098
220 SmsMessageData message(aId, 0, eDeliveryState_Sent, eDeliveryStatus_Pending,
221 EmptyString(), nsJNIString(aReceiver, jenv),
222 nsJNIString(aBody, jenv), eMessageClass_Normal,
223 aTimestamp, true);
225 nsCOMPtr<nsIRunnable> runnable = new NotifySmsSentRunnable(message, aRequestId);
226 NS_DispatchToMainThread(runnable);
227 }
229 NS_EXPORT void JNICALL
230 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery(JNIEnv* jenv, jclass,
231 jint aId,
232 jint aDeliveryStatus,
233 jstring aReceiver,
234 jstring aBody,
235 jlong aTimestamp)
236 {
237 class NotifySmsDeliveredRunnable : public nsRunnable {
238 public:
239 NotifySmsDeliveredRunnable(const SmsMessageData& aMessageData)
240 : mMessageData(aMessageData)
241 {}
243 NS_IMETHODIMP Run() {
244 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
245 if (!obs) {
246 return NS_OK;
247 }
249 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
250 const char* topic = (mMessageData.deliveryStatus() == eDeliveryStatus_Success)
251 ? kSmsDeliverySuccessObserverTopic
252 : kSmsDeliveryErrorObserverTopic;
253 obs->NotifyObservers(message, topic, nullptr);
255 return NS_OK;
256 }
258 private:
259 SmsMessageData mMessageData;
260 };
262 // TODO Need to add the message `messageClass` parameter value. Bug 804476
263 // TODO Need to correct the message `threadId` parameter value. Bug 859098
264 SmsMessageData message(aId, 0, eDeliveryState_Sent,
265 static_cast<DeliveryStatus>(aDeliveryStatus),
266 EmptyString(), nsJNIString(aReceiver, jenv),
267 nsJNIString(aBody, jenv), eMessageClass_Normal,
268 aTimestamp, true);
270 nsCOMPtr<nsIRunnable> runnable = new NotifySmsDeliveredRunnable(message);
271 NS_DispatchToMainThread(runnable);
272 }
274 NS_EXPORT void JNICALL
275 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed(JNIEnv* jenv, jclass,
276 jint aError,
277 jint aRequestId)
278 {
279 class NotifySmsSendFailedRunnable : public nsRunnable {
280 public:
281 NotifySmsSendFailedRunnable(int32_t aError,
282 int32_t aRequestId)
283 : mError(aError)
284 , mRequestId(aRequestId)
285 {}
287 NS_IMETHODIMP Run() {
288 nsCOMPtr<nsIMobileMessageCallback> request =
289 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
290 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
292 request->NotifySendMessageFailed(mError);
293 return NS_OK;
294 }
296 private:
297 int32_t mError;
298 int32_t mRequestId;
299 };
302 nsCOMPtr<nsIRunnable> runnable =
303 new NotifySmsSendFailedRunnable(aError, aRequestId);
304 NS_DispatchToMainThread(runnable);
305 }
307 NS_EXPORT void JNICALL
308 Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms(JNIEnv* jenv, jclass,
309 jint aId,
310 jint aDeliveryStatus,
311 jstring aReceiver,
312 jstring aSender,
313 jstring aBody,
314 jlong aTimestamp,
315 jint aRequestId)
316 {
317 class NotifyGetSmsRunnable : public nsRunnable {
318 public:
319 NotifyGetSmsRunnable(const SmsMessageData& aMessageData,
320 int32_t aRequestId)
321 : mMessageData(aMessageData)
322 , mRequestId(aRequestId)
323 {}
325 NS_IMETHODIMP Run() {
326 nsCOMPtr<nsIMobileMessageCallback> request =
327 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
328 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
330 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
331 request->NotifyMessageGot(message);
332 return NS_OK;
333 }
335 private:
336 SmsMessageData mMessageData;
337 int32_t mRequestId;
338 };
340 nsJNIString receiver = nsJNIString(aReceiver, jenv);
341 DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received
342 : eDeliveryState_Sent;
344 // TODO Need to add the message `read` parameter value. Bug 748391
345 // TODO Need to add the message `messageClass` parameter value. Bug 804476
346 // TODO Need to correct the message `threadId` parameter value. Bug 859098
347 SmsMessageData message(aId, 0, state,
348 static_cast<DeliveryStatus>(aDeliveryStatus),
349 nsJNIString(aSender, jenv), receiver,
350 nsJNIString(aBody, jenv), eMessageClass_Normal,
351 aTimestamp, true);
353 nsCOMPtr<nsIRunnable> runnable = new NotifyGetSmsRunnable(message, aRequestId);
354 NS_DispatchToMainThread(runnable);
355 }
357 NS_EXPORT void JNICALL
358 Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed(JNIEnv* jenv, jclass,
359 jint aError,
360 jint aRequestId)
361 {
362 class NotifyGetSmsFailedRunnable : public nsRunnable {
363 public:
364 NotifyGetSmsFailedRunnable(int32_t aError,
365 int32_t aRequestId)
366 : mError(aError)
367 , mRequestId(aRequestId)
368 {}
370 NS_IMETHODIMP Run() {
371 nsCOMPtr<nsIMobileMessageCallback> request =
372 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
373 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
375 request->NotifyGetMessageFailed(mError);
376 return NS_OK;
377 }
379 private:
380 int32_t mError;
381 int32_t mRequestId;
382 };
385 nsCOMPtr<nsIRunnable> runnable =
386 new NotifyGetSmsFailedRunnable(aError, aRequestId);
387 NS_DispatchToMainThread(runnable);
388 }
390 NS_EXPORT void JNICALL
391 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted(JNIEnv* jenv, jclass,
392 jboolean aDeleted,
393 jint aRequestId)
394 {
395 class NotifySmsDeletedRunnable : public nsRunnable {
396 public:
397 NotifySmsDeletedRunnable(bool aDeleted, int32_t aRequestId)
398 : mDeleted(aDeleted)
399 , mRequestId(aRequestId)
400 {}
402 NS_IMETHODIMP Run() {
403 nsCOMPtr<nsIMobileMessageCallback> request =
404 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
405 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
407 // For android, we support only single SMS deletion.
408 request->NotifyMessageDeleted(&mDeleted, 1);
409 return NS_OK;
410 }
412 private:
413 bool mDeleted;
414 int32_t mRequestId;
415 };
418 nsCOMPtr<nsIRunnable> runnable =
419 new NotifySmsDeletedRunnable(aDeleted, aRequestId);
420 NS_DispatchToMainThread(runnable);
421 }
423 NS_EXPORT void JNICALL
424 Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed(JNIEnv* jenv, jclass,
425 jint aError,
426 jint aRequestId)
427 {
428 class NotifySmsDeleteFailedRunnable : public nsRunnable {
429 public:
430 NotifySmsDeleteFailedRunnable(int32_t aError,
431 int32_t aRequestId)
432 : mError(aError)
433 , mRequestId(aRequestId)
434 {}
436 NS_IMETHODIMP Run() {
437 nsCOMPtr<nsIMobileMessageCallback> request =
438 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
439 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
441 request->NotifyDeleteMessageFailed(mError);
442 return NS_OK;
443 }
445 private:
446 int32_t mError;
447 int32_t mRequestId;
448 };
451 nsCOMPtr<nsIRunnable> runnable =
452 new NotifySmsDeleteFailedRunnable(aError, aRequestId);
453 NS_DispatchToMainThread(runnable);
454 }
456 NS_EXPORT void JNICALL
457 Java_org_mozilla_gecko_GeckoSmsManager_notifyNoMessageInList(JNIEnv* jenv, jclass,
458 jint aRequestId)
459 {
460 class NotifyNoMessageInListRunnable : public nsRunnable {
461 public:
462 NotifyNoMessageInListRunnable(int32_t aRequestId)
463 : mRequestId(aRequestId)
464 {}
466 NS_IMETHODIMP Run() {
467 nsCOMPtr<nsIMobileMessageCallback> request =
468 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
469 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
471 request->NotifyNoMessageInList();
472 return NS_OK;
473 }
475 private:
476 int32_t mRequestId;
477 };
480 nsCOMPtr<nsIRunnable> runnable =
481 new NotifyNoMessageInListRunnable(aRequestId);
482 NS_DispatchToMainThread(runnable);
483 }
485 NS_EXPORT void JNICALL
486 Java_org_mozilla_gecko_GeckoSmsManager_notifyListCreated(JNIEnv* jenv, jclass,
487 jint aListId,
488 jint aMessageId,
489 jint aDeliveryStatus,
490 jstring aReceiver,
491 jstring aSender,
492 jstring aBody,
493 jlong aTimestamp,
494 jint aRequestId)
495 {
496 class NotifyCreateMessageListRunnable : public nsRunnable {
497 public:
498 NotifyCreateMessageListRunnable(int32_t aListId,
499 const SmsMessageData& aMessageData,
500 int32_t aRequestId)
501 : mListId(aListId)
502 , mMessageData(aMessageData)
503 , mRequestId(aRequestId)
504 {}
506 NS_IMETHODIMP Run() {
507 nsCOMPtr<nsIMobileMessageCallback> request =
508 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
509 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
511 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
512 request->NotifyMessageListCreated(mListId, message);
513 return NS_OK;
514 }
516 private:
517 int32_t mListId;
518 SmsMessageData mMessageData;
519 int32_t mRequestId;
520 };
523 nsJNIString receiver = nsJNIString(aReceiver, jenv);
524 DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received
525 : eDeliveryState_Sent;
527 // TODO Need to add the message `read` parameter value. Bug 748391
528 // TODO Need to add the message `messageClass` parameter value. Bug 804476
529 // TODO Need to correct the message `threadId` parameter value. Bug 859098
530 SmsMessageData message(aMessageId, 0, state,
531 static_cast<DeliveryStatus>(aDeliveryStatus),
532 nsJNIString(aSender, jenv), receiver,
533 nsJNIString(aBody, jenv), eMessageClass_Normal,
534 aTimestamp, true);
536 nsCOMPtr<nsIRunnable> runnable =
537 new NotifyCreateMessageListRunnable(aListId, message, aRequestId);
538 NS_DispatchToMainThread(runnable);
539 }
541 NS_EXPORT void JNICALL
542 Java_org_mozilla_gecko_GeckoSmsManager_notifyGotNextMessage(JNIEnv* jenv, jclass,
543 jint aMessageId,
544 jint aDeliveryStatus,
545 jstring aReceiver,
546 jstring aSender,
547 jstring aBody,
548 jlong aTimestamp,
549 jint aRequestId)
550 {
551 class NotifyGotNextMessageRunnable : public nsRunnable {
552 public:
553 NotifyGotNextMessageRunnable(const SmsMessageData& aMessageData,
554 int32_t aRequestId)
555 : mMessageData(aMessageData)
556 , mRequestId(aRequestId)
557 {}
559 NS_IMETHODIMP Run() {
560 nsCOMPtr<nsIMobileMessageCallback> request =
561 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
562 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
564 nsCOMPtr<nsIDOMMozSmsMessage> message = new SmsMessage(mMessageData);
565 request->NotifyNextMessageInListGot(message);
566 return NS_OK;
567 }
569 private:
570 SmsMessageData mMessageData;
571 int32_t mRequestId;
572 };
575 nsJNIString receiver = nsJNIString(aReceiver, jenv);
576 DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received
577 : eDeliveryState_Sent;
579 // TODO Need to add the message `read` parameter value. Bug 748391
580 // TODO Need to add the message `messageClass` parameter value. Bug 804476
581 // TODO Need to correct the message `threadId` parameter value. Bug 859098
582 SmsMessageData message(aMessageId, 0, state,
583 static_cast<DeliveryStatus>(aDeliveryStatus),
584 nsJNIString(aSender, jenv), receiver,
585 nsJNIString(aBody, jenv), eMessageClass_Normal,
586 aTimestamp, true);
588 nsCOMPtr<nsIRunnable> runnable =
589 new NotifyGotNextMessageRunnable(message, aRequestId);
590 NS_DispatchToMainThread(runnable);
591 }
593 NS_EXPORT void JNICALL
594 Java_org_mozilla_gecko_GeckoSmsManager_notifyReadingMessageListFailed(JNIEnv* jenv, jclass,
595 jint aError,
596 jint aRequestId)
597 {
598 class NotifyReadListFailedRunnable : public nsRunnable {
599 public:
600 NotifyReadListFailedRunnable(int32_t aError,
601 int32_t aRequestId)
602 : mError(aError)
603 , mRequestId(aRequestId)
604 {}
606 NS_IMETHODIMP Run() {
607 nsCOMPtr<nsIMobileMessageCallback> request =
608 AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId);
609 NS_ENSURE_TRUE(request, NS_ERROR_FAILURE);
611 request->NotifyReadMessageListFailed(mError);
612 return NS_OK;
613 }
615 private:
616 int32_t mError;
617 int32_t mRequestId;
618 };
621 nsCOMPtr<nsIRunnable> runnable =
622 new NotifyReadListFailedRunnable(aError, aRequestId);
623 NS_DispatchToMainThread(runnable);
624 }
626 #endif // MOZ_WEBSMS_BACKEND
628 NS_EXPORT void JNICALL
629 Java_org_mozilla_gecko_GeckoAppShell_scheduleComposite(JNIEnv*, jclass)
630 {
631 nsWindow::ScheduleComposite();
632 }
634 NS_EXPORT void JNICALL
635 Java_org_mozilla_gecko_GeckoAppShell_scheduleResumeComposition(JNIEnv*, jclass, jint width, jint height)
636 {
637 nsWindow::ScheduleResumeComposition(width, height);
638 }
640 NS_EXPORT float JNICALL
641 Java_org_mozilla_gecko_GeckoAppShell_computeRenderIntegrity(JNIEnv*, jclass)
642 {
643 return nsWindow::ComputeRenderIntegrity();
644 }
646 NS_EXPORT void JNICALL
647 Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult(JNIEnv* jenv, jclass, jstring filePath, jlong callback)
648 {
649 class NotifyFilePickerResultRunnable : public nsRunnable {
650 public:
651 NotifyFilePickerResultRunnable(nsString& fileDir, long callback) :
652 mFileDir(fileDir), mCallback(callback) {}
654 NS_IMETHODIMP Run() {
655 nsFilePickerCallback* handler = (nsFilePickerCallback*)mCallback;
656 handler->handleResult(mFileDir);
657 handler->Release();
658 return NS_OK;
659 }
660 private:
661 nsString mFileDir;
662 long mCallback;
663 };
664 nsString path = nsJNIString(filePath, jenv);
666 nsCOMPtr<nsIRunnable> runnable =
667 new NotifyFilePickerResultRunnable(path, (long)callback);
668 NS_DispatchToMainThread(runnable);
669 }
671 static int
672 NextPowerOfTwo(int value) {
673 // code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html
674 if (0 == value--) {
675 return 1;
676 }
677 value = (value >> 1) | value;
678 value = (value >> 2) | value;
679 value = (value >> 4) | value;
680 value = (value >> 8) | value;
681 value = (value >> 16) | value;
682 return value + 1;
683 }
685 #define MAX_LOCK_ATTEMPTS 10
687 static bool LockWindowWithRetry(void* window, unsigned char** bits, int* width, int* height, int* format, int* stride)
688 {
689 int count = 0;
691 while (count < MAX_LOCK_ATTEMPTS) {
692 if (AndroidBridge::Bridge()->LockWindow(window, bits, width, height, format, stride))
693 return true;
695 count++;
696 usleep(500);
697 }
699 return false;
700 }
702 NS_EXPORT jobject JNICALL
703 Java_org_mozilla_gecko_GeckoAppShell_getSurfaceBits(JNIEnv* jenv, jclass, jobject surface)
704 {
705 static jclass jSurfaceBitsClass = nullptr;
706 static jmethodID jSurfaceBitsCtor = 0;
707 static jfieldID jSurfaceBitsWidth, jSurfaceBitsHeight, jSurfaceBitsFormat, jSurfaceBitsBuffer;
709 jobject surfaceBits = nullptr;
710 unsigned char* bitsCopy = nullptr;
711 int dstWidth, dstHeight, dstSize;
713 void* window = AndroidBridge::Bridge()->AcquireNativeWindow(jenv, surface);
714 if (!window)
715 return nullptr;
717 unsigned char* bits;
718 int srcWidth, srcHeight, format, srcStride;
720 // So we lock/unlock once here in order to get whatever is currently the front buffer. It sucks.
721 if (!LockWindowWithRetry(window, &bits, &srcWidth, &srcHeight, &format, &srcStride))
722 return nullptr;
724 AndroidBridge::Bridge()->UnlockWindow(window);
726 // This is lock will result in the front buffer, since the last unlock rotated it to the back. Probably.
727 if (!LockWindowWithRetry(window, &bits, &srcWidth, &srcHeight, &format, &srcStride))
728 return nullptr;
730 // These are from android.graphics.PixelFormat
731 int bpp;
732 switch (format) {
733 case 1: // RGBA_8888
734 bpp = 4;
735 break;
736 case 4: // RGB_565
737 bpp = 2;
738 break;
739 default:
740 goto cleanup;
741 }
743 dstWidth = NextPowerOfTwo(srcWidth);
744 dstHeight = NextPowerOfTwo(srcHeight);
745 dstSize = dstWidth * dstHeight * bpp;
747 bitsCopy = (unsigned char*)malloc(dstSize);
748 bzero(bitsCopy, dstSize);
749 for (int i = 0; i < srcHeight; i++) {
750 memcpy(bitsCopy + ((dstHeight - i - 1) * dstWidth * bpp), bits + (i * srcStride * bpp), srcStride * bpp);
751 }
753 if (!jSurfaceBitsClass) {
754 jSurfaceBitsClass = (jclass)jenv->NewGlobalRef(jenv->FindClass("org/mozilla/gecko/SurfaceBits"));
755 jSurfaceBitsCtor = jenv->GetMethodID(jSurfaceBitsClass, "<init>", "()V");
757 jSurfaceBitsWidth = jenv->GetFieldID(jSurfaceBitsClass, "width", "I");
758 jSurfaceBitsHeight = jenv->GetFieldID(jSurfaceBitsClass, "height", "I");
759 jSurfaceBitsFormat = jenv->GetFieldID(jSurfaceBitsClass, "format", "I");
760 jSurfaceBitsBuffer = jenv->GetFieldID(jSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;");
761 }
763 surfaceBits = jenv->NewObject(jSurfaceBitsClass, jSurfaceBitsCtor);
764 jenv->SetIntField(surfaceBits, jSurfaceBitsWidth, dstWidth);
765 jenv->SetIntField(surfaceBits, jSurfaceBitsHeight, dstHeight);
766 jenv->SetIntField(surfaceBits, jSurfaceBitsFormat, format);
767 jenv->SetObjectField(surfaceBits, jSurfaceBitsBuffer, jenv->NewDirectByteBuffer(bitsCopy, dstSize));
769 cleanup:
770 AndroidBridge::Bridge()->UnlockWindow(window);
771 AndroidBridge::Bridge()->ReleaseNativeWindow(window);
773 return surfaceBits;
774 }
776 NS_EXPORT void JNICALL
777 Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view)
778 {
779 class ExitFullScreenRunnable : public nsRunnable {
780 public:
781 ExitFullScreenRunnable(jobject view) : mView(view) {}
783 NS_IMETHODIMP Run() {
784 JNIEnv* env = AndroidBridge::GetJNIEnv();
785 nsPluginInstanceOwner::ExitFullScreen(mView);
786 env->DeleteGlobalRef(mView);
787 return NS_OK;
788 }
790 private:
791 jobject mView;
792 };
794 nsCOMPtr<nsIRunnable> runnable = new ExitFullScreenRunnable(jenv->NewGlobalRef(view));
795 NS_DispatchToMainThread(runnable);
796 }
798 NS_EXPORT jobject JNICALL
799 Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(JNIEnv* jenv, jclass, jobject queue)
800 {
801 static jclass jMessageQueueCls = nullptr;
802 static jfieldID jMessagesField;
803 static jmethodID jNextMethod;
804 if (!jMessageQueueCls) {
805 jMessageQueueCls = (jclass) jenv->NewGlobalRef(jenv->FindClass("android/os/MessageQueue"));
806 jNextMethod = jenv->GetMethodID(jMessageQueueCls, "next", "()Landroid/os/Message;");
807 jMessagesField = jenv->GetFieldID(jMessageQueueCls, "mMessages", "Landroid/os/Message;");
808 }
810 if (!jMessageQueueCls || !jNextMethod)
811 return nullptr;
813 if (jMessagesField) {
814 jobject msg = jenv->GetObjectField(queue, jMessagesField);
815 // if queue.mMessages is null, queue.next() will block, which we don't want
816 // It turns out to be an order of magnitude more performant to do this extra check here and
817 // block less vs. one fewer checks here and more blocking.
818 if (!msg) {
819 return nullptr;
820 }
821 }
822 return jenv->CallObjectMethod(queue, jNextMethod);
823 }
825 NS_EXPORT void JNICALL
826 Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id)
827 {
828 nsSurfaceTexture* st = nsSurfaceTexture::Find(id);
829 if (!st) {
830 __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find nsSurfaceTexture with id %d", id);
831 return;
832 }
834 st->NotifyFrameAvailable();
835 }
837 NS_EXPORT void JNICALL
838 Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv* jenv, jclass)
839 {
840 NS_DispatchMemoryPressure(MemPressure_New);
841 }
843 NS_EXPORT jdouble JNICALL
844 Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
845 {
846 return profiler_time();
847 }
849 NS_EXPORT void JNICALL
850 Java_org_mozilla_gecko_gfx_NativePanZoomController_abortAnimation(JNIEnv* env, jobject instance)
851 {
852 APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
853 if (controller) {
854 // TODO: Pass in correct values for presShellId and viewId.
855 controller->CancelAnimation(ScrollableLayerGuid(nsWindow::RootLayerTreeId(), 0, 0));
856 }
857 }
859 NS_EXPORT void JNICALL
860 Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance)
861 {
862 if (!AndroidBridge::Bridge()) {
863 return;
864 }
866 NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(instance);
867 if (oldRef && !oldRef->isNull()) {
868 MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
869 delete oldRef;
870 }
871 }
873 NS_EXPORT void JNICALL
874 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
875 {
876 APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
877 if (controller) {
878 AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event);
879 const MultiTouchInput& input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow());
880 delete wrapper;
881 if (input.mType >= 0) {
882 controller->ReceiveInputEvent(input, nullptr);
883 }
884 }
885 }
887 NS_EXPORT void JNICALL
888 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(JNIEnv* env, jobject instance, jobject event)
889 {
890 // FIXME implement this
891 }
893 NS_EXPORT jlong JNICALL
894 Java_org_mozilla_gecko_gfx_NativePanZoomController_runDelayedCallback(JNIEnv* env, jobject instance)
895 {
896 if (!AndroidBridge::Bridge()) {
897 return -1;
898 }
900 return AndroidBridge::Bridge()->RunDelayedTasks();
901 }
903 NS_EXPORT void JNICALL
904 Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject instance)
905 {
906 if (!AndroidBridge::Bridge()) {
907 return;
908 }
910 NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(nullptr);
911 if (!oldRef || oldRef->isNull()) {
912 MOZ_ASSERT(false, "Clearing a non-existent NPZC");
913 } else {
914 delete oldRef;
915 }
916 }
918 NS_EXPORT void JNICALL
919 Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
920 {
921 APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
922 if (controller) {
923 // TODO: Pass in correct values for presShellId and viewId.
924 controller->ContentReceivedTouch(ScrollableLayerGuid(nsWindow::RootLayerTreeId(), 0, 0), prevented);
925 }
926 }
928 NS_EXPORT jboolean JNICALL
929 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
930 {
931 // FIXME implement this
932 return true;
933 }
935 NS_EXPORT void JNICALL
936 Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv* env, jobject instance, jint overscrollMode)
937 {
938 // FIXME implement this
939 }
941 NS_EXPORT jint JNICALL
942 Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env, jobject instance)
943 {
944 // FIXME implement this
945 return 0;
946 }
948 NS_EXPORT jboolean JNICALL
949 Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass, jboolean aUnwind)
950 {
951 if (profiler_is_active()) {
952 // Don't proceed if profiler is already running
953 return JNI_FALSE;
954 }
955 // WARNING: we are on the ANR reporter thread at this point and it is
956 // generally unsafe to use the profiler from off the main thread. However,
957 // the risk here is limited because for most users, the profiler is not run
958 // elsewhere. See the discussion in Bug 863777, comment 13
959 const char *NATIVE_STACK_FEATURES[] =
960 {"leaf", "threads", "privacy"};
961 const char *NATIVE_STACK_UNWIND_FEATURES[] =
962 {"leaf", "threads", "privacy", "stackwalk"};
964 const char **features = NATIVE_STACK_FEATURES;
965 size_t features_size = sizeof(NATIVE_STACK_FEATURES);
966 if (aUnwind) {
967 features = NATIVE_STACK_UNWIND_FEATURES;
968 features_size = sizeof(NATIVE_STACK_UNWIND_FEATURES);
969 // We want the new unwinder if the unwind mode has not been set yet
970 putenv("MOZ_PROFILER_NEW=1");
971 }
973 const char *NATIVE_STACK_THREADS[] =
974 {"GeckoMain", "Compositor"};
975 // Buffer one sample and let the profiler wait a long time
976 profiler_start(100, 10000, features, features_size / sizeof(char*),
977 NATIVE_STACK_THREADS, sizeof(NATIVE_STACK_THREADS) / sizeof(char*));
978 return JNI_TRUE;
979 }
981 NS_EXPORT jstring JNICALL
982 Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv* jenv, jclass)
983 {
984 if (!profiler_is_active()) {
985 // Maybe profiler support is disabled?
986 return nullptr;
987 }
988 char *profile = profiler_get_profile();
989 while (profile && !strlen(profile)) {
990 // no sample yet?
991 sched_yield();
992 profile = profiler_get_profile();
993 }
994 jstring result = nullptr;
995 if (profile) {
996 result = jenv->NewStringUTF(profile);
997 free(profile);
998 }
999 return result;
1000 }
1002 NS_EXPORT void JNICALL
1003 Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv* jenv, jclass)
1004 {
1005 if (!profiler_is_active()) {
1006 // Maybe profiler support is disabled?
1007 return;
1008 }
1009 mozilla_sampler_stop();
1010 }
1012 }