michael@0: /* -*- Mode: c++; c-basic-offset: 4; 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: michael@0: #include "mozilla/Hal.h" michael@0: #include "nsIFile.h" michael@0: #include "nsString.h" michael@0: michael@0: #include "AndroidBridge.h" michael@0: #include "AndroidGraphicBuffer.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsAppShell.h" michael@0: #include "nsWindow.h" michael@0: #include michael@0: #include "nsIObserverService.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: #ifdef MOZ_CRASHREPORTER michael@0: #include "nsICrashReporter.h" michael@0: #include "nsExceptionHandler.h" michael@0: #endif michael@0: michael@0: #include "mozilla/unused.h" michael@0: michael@0: #include "mozilla/dom/SmsMessage.h" michael@0: #include "mozilla/dom/mobilemessage/Constants.h" michael@0: #include "mozilla/dom/mobilemessage/Types.h" michael@0: #include "mozilla/dom/mobilemessage/PSms.h" michael@0: #include "mozilla/dom/mobilemessage/SmsParent.h" michael@0: #include "mozilla/layers/APZCTreeManager.h" michael@0: #include "nsIMobileMessageDatabaseService.h" michael@0: #include "nsPluginInstanceOwner.h" michael@0: #include "nsSurfaceTexture.h" michael@0: #include "GeckoProfiler.h" michael@0: #include "nsMemoryPressure.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::dom::mobilemessage; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget::android; michael@0: michael@0: /* Forward declare all the JNI methods as extern "C" */ michael@0: michael@0: extern "C" { michael@0: /* michael@0: * Incoming JNI methods michael@0: */ michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass jc) michael@0: { michael@0: AndroidBridge::ConstructBridge(jenv); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *jenv, jclass jc, jobject event) michael@0: { michael@0: // poke the appshell michael@0: if (nsAppShell::gAppShell) michael@0: nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeFromJavaObject(jenv, event)); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_processNextNativeEvent(JNIEnv *jenv, jclass, jboolean mayWait) michael@0: { michael@0: // poke the appshell michael@0: if (nsAppShell::gAppShell) michael@0: nsAppShell::gAppShell->ProcessNextNativeEvent(mayWait != JNI_FALSE); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_setLayerClient(JNIEnv *jenv, jclass, jobject obj) michael@0: { michael@0: AndroidBridge::Bridge()->SetLayerClient(jenv, obj); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *jenv, jclass jc) michael@0: { michael@0: if (nsAppShell::gAppShell) michael@0: nsAppShell::gAppShell->OnResume(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *jenv, jclass, jstring jStackTrace) michael@0: { michael@0: #ifdef MOZ_CRASHREPORTER michael@0: const nsJNIString stackTrace16(jStackTrace, jenv); michael@0: const NS_ConvertUTF16toUTF8 stackTrace8(stackTrace16); michael@0: CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("JavaStackTrace"), stackTrace8); michael@0: #endif // MOZ_CRASHREPORTER michael@0: michael@0: abort(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, michael@0: jdouble aLevel, michael@0: jboolean aCharging, michael@0: jdouble aRemainingTime) michael@0: { michael@0: class NotifyBatteryChangeRunnable : public nsRunnable { michael@0: public: michael@0: NotifyBatteryChangeRunnable(double aLevel, bool aCharging, double aRemainingTime) michael@0: : mLevel(aLevel) michael@0: , mCharging(aCharging) michael@0: , mRemainingTime(aRemainingTime) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: hal::NotifyBatteryChange(hal::BatteryInformation(mLevel, mCharging, mRemainingTime)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: double mLevel; michael@0: bool mCharging; michael@0: double mRemainingTime; michael@0: }; michael@0: michael@0: nsCOMPtr runnable = new NotifyBatteryChangeRunnable(aLevel, aCharging, aRemainingTime); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: #ifdef MOZ_WEBSMS_BACKEND michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsReceived(JNIEnv* jenv, jclass, michael@0: jstring aSender, michael@0: jstring aBody, michael@0: jint aMessageClass, michael@0: jlong aTimestamp) michael@0: { michael@0: class NotifySmsReceivedRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsReceivedRunnable(const SmsMessageData& aMessageData) michael@0: : mMessageData(aMessageData) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr obs = services::GetObserverService(); michael@0: if (!obs) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: obs->NotifyObservers(message, kSmsReceivedObserverTopic, nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SmsMessageData mMessageData; michael@0: }; michael@0: michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(0, 0, eDeliveryState_Received, eDeliveryStatus_Success, michael@0: nsJNIString(aSender, jenv), EmptyString(), michael@0: nsJNIString(aBody, jenv), michael@0: static_cast(aMessageClass), michael@0: aTimestamp, false); michael@0: michael@0: nsCOMPtr runnable = new NotifySmsReceivedRunnable(message); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSent(JNIEnv* jenv, jclass, michael@0: jint aId, michael@0: jstring aReceiver, michael@0: jstring aBody, michael@0: jlong aTimestamp, michael@0: jint aRequestId) michael@0: { michael@0: class NotifySmsSentRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsSentRunnable(const SmsMessageData& aMessageData, michael@0: int32_t aRequestId) michael@0: : mMessageData(aMessageData) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: /* michael@0: * First, we are going to notify all SmsManager that a message has michael@0: * been sent. Then, we will notify the SmsRequest object about it. michael@0: */ michael@0: nsCOMPtr obs = services::GetObserverService(); michael@0: if (!obs) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: obs->NotifyObservers(message, kSmsSentObserverTopic, nullptr); michael@0: michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifyMessageSent(message); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SmsMessageData mMessageData; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: // TODO Need to add the message `messageClass` parameter value. Bug 804476 michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(aId, 0, eDeliveryState_Sent, eDeliveryStatus_Pending, michael@0: EmptyString(), nsJNIString(aReceiver, jenv), michael@0: nsJNIString(aBody, jenv), eMessageClass_Normal, michael@0: aTimestamp, true); michael@0: michael@0: nsCOMPtr runnable = new NotifySmsSentRunnable(message, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDelivery(JNIEnv* jenv, jclass, michael@0: jint aId, michael@0: jint aDeliveryStatus, michael@0: jstring aReceiver, michael@0: jstring aBody, michael@0: jlong aTimestamp) michael@0: { michael@0: class NotifySmsDeliveredRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsDeliveredRunnable(const SmsMessageData& aMessageData) michael@0: : mMessageData(aMessageData) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr obs = services::GetObserverService(); michael@0: if (!obs) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: const char* topic = (mMessageData.deliveryStatus() == eDeliveryStatus_Success) michael@0: ? kSmsDeliverySuccessObserverTopic michael@0: : kSmsDeliveryErrorObserverTopic; michael@0: obs->NotifyObservers(message, topic, nullptr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SmsMessageData mMessageData; michael@0: }; michael@0: michael@0: // TODO Need to add the message `messageClass` parameter value. Bug 804476 michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(aId, 0, eDeliveryState_Sent, michael@0: static_cast(aDeliveryStatus), michael@0: EmptyString(), nsJNIString(aReceiver, jenv), michael@0: nsJNIString(aBody, jenv), eMessageClass_Normal, michael@0: aTimestamp, true); michael@0: michael@0: nsCOMPtr runnable = new NotifySmsDeliveredRunnable(message); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsSendFailed(JNIEnv* jenv, jclass, michael@0: jint aError, michael@0: jint aRequestId) michael@0: { michael@0: class NotifySmsSendFailedRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsSendFailedRunnable(int32_t aError, michael@0: int32_t aRequestId) michael@0: : mError(aError) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifySendMessageFailed(mError); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mError; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifySmsSendFailedRunnable(aError, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSms(JNIEnv* jenv, jclass, michael@0: jint aId, michael@0: jint aDeliveryStatus, michael@0: jstring aReceiver, michael@0: jstring aSender, michael@0: jstring aBody, michael@0: jlong aTimestamp, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyGetSmsRunnable : public nsRunnable { michael@0: public: michael@0: NotifyGetSmsRunnable(const SmsMessageData& aMessageData, michael@0: int32_t aRequestId) michael@0: : mMessageData(aMessageData) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: request->NotifyMessageGot(message); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SmsMessageData mMessageData; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: nsJNIString receiver = nsJNIString(aReceiver, jenv); michael@0: DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received michael@0: : eDeliveryState_Sent; michael@0: michael@0: // TODO Need to add the message `read` parameter value. Bug 748391 michael@0: // TODO Need to add the message `messageClass` parameter value. Bug 804476 michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(aId, 0, state, michael@0: static_cast(aDeliveryStatus), michael@0: nsJNIString(aSender, jenv), receiver, michael@0: nsJNIString(aBody, jenv), eMessageClass_Normal, michael@0: aTimestamp, true); michael@0: michael@0: nsCOMPtr runnable = new NotifyGetSmsRunnable(message, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyGetSmsFailed(JNIEnv* jenv, jclass, michael@0: jint aError, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyGetSmsFailedRunnable : public nsRunnable { michael@0: public: michael@0: NotifyGetSmsFailedRunnable(int32_t aError, michael@0: int32_t aRequestId) michael@0: : mError(aError) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifyGetMessageFailed(mError); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mError; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyGetSmsFailedRunnable(aError, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleted(JNIEnv* jenv, jclass, michael@0: jboolean aDeleted, michael@0: jint aRequestId) michael@0: { michael@0: class NotifySmsDeletedRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsDeletedRunnable(bool aDeleted, int32_t aRequestId) michael@0: : mDeleted(aDeleted) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: // For android, we support only single SMS deletion. michael@0: request->NotifyMessageDeleted(&mDeleted, 1); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: bool mDeleted; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifySmsDeletedRunnable(aDeleted, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifySmsDeleteFailed(JNIEnv* jenv, jclass, michael@0: jint aError, michael@0: jint aRequestId) michael@0: { michael@0: class NotifySmsDeleteFailedRunnable : public nsRunnable { michael@0: public: michael@0: NotifySmsDeleteFailedRunnable(int32_t aError, michael@0: int32_t aRequestId) michael@0: : mError(aError) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifyDeleteMessageFailed(mError); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mError; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifySmsDeleteFailedRunnable(aError, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyNoMessageInList(JNIEnv* jenv, jclass, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyNoMessageInListRunnable : public nsRunnable { michael@0: public: michael@0: NotifyNoMessageInListRunnable(int32_t aRequestId) michael@0: : mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifyNoMessageInList(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyNoMessageInListRunnable(aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyListCreated(JNIEnv* jenv, jclass, michael@0: jint aListId, michael@0: jint aMessageId, michael@0: jint aDeliveryStatus, michael@0: jstring aReceiver, michael@0: jstring aSender, michael@0: jstring aBody, michael@0: jlong aTimestamp, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyCreateMessageListRunnable : public nsRunnable { michael@0: public: michael@0: NotifyCreateMessageListRunnable(int32_t aListId, michael@0: const SmsMessageData& aMessageData, michael@0: int32_t aRequestId) michael@0: : mListId(aListId) michael@0: , mMessageData(aMessageData) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: request->NotifyMessageListCreated(mListId, message); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mListId; michael@0: SmsMessageData mMessageData; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsJNIString receiver = nsJNIString(aReceiver, jenv); michael@0: DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received michael@0: : eDeliveryState_Sent; michael@0: michael@0: // TODO Need to add the message `read` parameter value. Bug 748391 michael@0: // TODO Need to add the message `messageClass` parameter value. Bug 804476 michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(aMessageId, 0, state, michael@0: static_cast(aDeliveryStatus), michael@0: nsJNIString(aSender, jenv), receiver, michael@0: nsJNIString(aBody, jenv), eMessageClass_Normal, michael@0: aTimestamp, true); michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyCreateMessageListRunnable(aListId, message, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyGotNextMessage(JNIEnv* jenv, jclass, michael@0: jint aMessageId, michael@0: jint aDeliveryStatus, michael@0: jstring aReceiver, michael@0: jstring aSender, michael@0: jstring aBody, michael@0: jlong aTimestamp, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyGotNextMessageRunnable : public nsRunnable { michael@0: public: michael@0: NotifyGotNextMessageRunnable(const SmsMessageData& aMessageData, michael@0: int32_t aRequestId) michael@0: : mMessageData(aMessageData) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr message = new SmsMessage(mMessageData); michael@0: request->NotifyNextMessageInListGot(message); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: SmsMessageData mMessageData; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsJNIString receiver = nsJNIString(aReceiver, jenv); michael@0: DeliveryState state = receiver.IsEmpty() ? eDeliveryState_Received michael@0: : eDeliveryState_Sent; michael@0: michael@0: // TODO Need to add the message `read` parameter value. Bug 748391 michael@0: // TODO Need to add the message `messageClass` parameter value. Bug 804476 michael@0: // TODO Need to correct the message `threadId` parameter value. Bug 859098 michael@0: SmsMessageData message(aMessageId, 0, state, michael@0: static_cast(aDeliveryStatus), michael@0: nsJNIString(aSender, jenv), receiver, michael@0: nsJNIString(aBody, jenv), eMessageClass_Normal, michael@0: aTimestamp, true); michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyGotNextMessageRunnable(message, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoSmsManager_notifyReadingMessageListFailed(JNIEnv* jenv, jclass, michael@0: jint aError, michael@0: jint aRequestId) michael@0: { michael@0: class NotifyReadListFailedRunnable : public nsRunnable { michael@0: public: michael@0: NotifyReadListFailedRunnable(int32_t aError, michael@0: int32_t aRequestId) michael@0: : mError(aError) michael@0: , mRequestId(aRequestId) michael@0: {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsCOMPtr request = michael@0: AndroidBridge::Bridge()->DequeueSmsRequest(mRequestId); michael@0: NS_ENSURE_TRUE(request, NS_ERROR_FAILURE); michael@0: michael@0: request->NotifyReadMessageListFailed(mError); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: int32_t mError; michael@0: int32_t mRequestId; michael@0: }; michael@0: michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyReadListFailedRunnable(aError, aRequestId); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: #endif // MOZ_WEBSMS_BACKEND michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_scheduleComposite(JNIEnv*, jclass) michael@0: { michael@0: nsWindow::ScheduleComposite(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_scheduleResumeComposition(JNIEnv*, jclass, jint width, jint height) michael@0: { michael@0: nsWindow::ScheduleResumeComposition(width, height); michael@0: } michael@0: michael@0: NS_EXPORT float JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_computeRenderIntegrity(JNIEnv*, jclass) michael@0: { michael@0: return nsWindow::ComputeRenderIntegrity(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_notifyFilePickerResult(JNIEnv* jenv, jclass, jstring filePath, jlong callback) michael@0: { michael@0: class NotifyFilePickerResultRunnable : public nsRunnable { michael@0: public: michael@0: NotifyFilePickerResultRunnable(nsString& fileDir, long callback) : michael@0: mFileDir(fileDir), mCallback(callback) {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: nsFilePickerCallback* handler = (nsFilePickerCallback*)mCallback; michael@0: handler->handleResult(mFileDir); michael@0: handler->Release(); michael@0: return NS_OK; michael@0: } michael@0: private: michael@0: nsString mFileDir; michael@0: long mCallback; michael@0: }; michael@0: nsString path = nsJNIString(filePath, jenv); michael@0: michael@0: nsCOMPtr runnable = michael@0: new NotifyFilePickerResultRunnable(path, (long)callback); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: static int michael@0: NextPowerOfTwo(int value) { michael@0: // code taken from http://acius2.blogspot.com/2007/11/calculating-next-power-of-2.html michael@0: if (0 == value--) { michael@0: return 1; michael@0: } michael@0: value = (value >> 1) | value; michael@0: value = (value >> 2) | value; michael@0: value = (value >> 4) | value; michael@0: value = (value >> 8) | value; michael@0: value = (value >> 16) | value; michael@0: return value + 1; michael@0: } michael@0: michael@0: #define MAX_LOCK_ATTEMPTS 10 michael@0: michael@0: static bool LockWindowWithRetry(void* window, unsigned char** bits, int* width, int* height, int* format, int* stride) michael@0: { michael@0: int count = 0; michael@0: michael@0: while (count < MAX_LOCK_ATTEMPTS) { michael@0: if (AndroidBridge::Bridge()->LockWindow(window, bits, width, height, format, stride)) michael@0: return true; michael@0: michael@0: count++; michael@0: usleep(500); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: NS_EXPORT jobject JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_getSurfaceBits(JNIEnv* jenv, jclass, jobject surface) michael@0: { michael@0: static jclass jSurfaceBitsClass = nullptr; michael@0: static jmethodID jSurfaceBitsCtor = 0; michael@0: static jfieldID jSurfaceBitsWidth, jSurfaceBitsHeight, jSurfaceBitsFormat, jSurfaceBitsBuffer; michael@0: michael@0: jobject surfaceBits = nullptr; michael@0: unsigned char* bitsCopy = nullptr; michael@0: int dstWidth, dstHeight, dstSize; michael@0: michael@0: void* window = AndroidBridge::Bridge()->AcquireNativeWindow(jenv, surface); michael@0: if (!window) michael@0: return nullptr; michael@0: michael@0: unsigned char* bits; michael@0: int srcWidth, srcHeight, format, srcStride; michael@0: michael@0: // So we lock/unlock once here in order to get whatever is currently the front buffer. It sucks. michael@0: if (!LockWindowWithRetry(window, &bits, &srcWidth, &srcHeight, &format, &srcStride)) michael@0: return nullptr; michael@0: michael@0: AndroidBridge::Bridge()->UnlockWindow(window); michael@0: michael@0: // This is lock will result in the front buffer, since the last unlock rotated it to the back. Probably. michael@0: if (!LockWindowWithRetry(window, &bits, &srcWidth, &srcHeight, &format, &srcStride)) michael@0: return nullptr; michael@0: michael@0: // These are from android.graphics.PixelFormat michael@0: int bpp; michael@0: switch (format) { michael@0: case 1: // RGBA_8888 michael@0: bpp = 4; michael@0: break; michael@0: case 4: // RGB_565 michael@0: bpp = 2; michael@0: break; michael@0: default: michael@0: goto cleanup; michael@0: } michael@0: michael@0: dstWidth = NextPowerOfTwo(srcWidth); michael@0: dstHeight = NextPowerOfTwo(srcHeight); michael@0: dstSize = dstWidth * dstHeight * bpp; michael@0: michael@0: bitsCopy = (unsigned char*)malloc(dstSize); michael@0: bzero(bitsCopy, dstSize); michael@0: for (int i = 0; i < srcHeight; i++) { michael@0: memcpy(bitsCopy + ((dstHeight - i - 1) * dstWidth * bpp), bits + (i * srcStride * bpp), srcStride * bpp); michael@0: } michael@0: michael@0: if (!jSurfaceBitsClass) { michael@0: jSurfaceBitsClass = (jclass)jenv->NewGlobalRef(jenv->FindClass("org/mozilla/gecko/SurfaceBits")); michael@0: jSurfaceBitsCtor = jenv->GetMethodID(jSurfaceBitsClass, "", "()V"); michael@0: michael@0: jSurfaceBitsWidth = jenv->GetFieldID(jSurfaceBitsClass, "width", "I"); michael@0: jSurfaceBitsHeight = jenv->GetFieldID(jSurfaceBitsClass, "height", "I"); michael@0: jSurfaceBitsFormat = jenv->GetFieldID(jSurfaceBitsClass, "format", "I"); michael@0: jSurfaceBitsBuffer = jenv->GetFieldID(jSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;"); michael@0: } michael@0: michael@0: surfaceBits = jenv->NewObject(jSurfaceBitsClass, jSurfaceBitsCtor); michael@0: jenv->SetIntField(surfaceBits, jSurfaceBitsWidth, dstWidth); michael@0: jenv->SetIntField(surfaceBits, jSurfaceBitsHeight, dstHeight); michael@0: jenv->SetIntField(surfaceBits, jSurfaceBitsFormat, format); michael@0: jenv->SetObjectField(surfaceBits, jSurfaceBitsBuffer, jenv->NewDirectByteBuffer(bitsCopy, dstSize)); michael@0: michael@0: cleanup: michael@0: AndroidBridge::Bridge()->UnlockWindow(window); michael@0: AndroidBridge::Bridge()->ReleaseNativeWindow(window); michael@0: michael@0: return surfaceBits; michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jclass, jobject view) michael@0: { michael@0: class ExitFullScreenRunnable : public nsRunnable { michael@0: public: michael@0: ExitFullScreenRunnable(jobject view) : mView(view) {} michael@0: michael@0: NS_IMETHODIMP Run() { michael@0: JNIEnv* env = AndroidBridge::GetJNIEnv(); michael@0: nsPluginInstanceOwner::ExitFullScreen(mView); michael@0: env->DeleteGlobalRef(mView); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: jobject mView; michael@0: }; michael@0: michael@0: nsCOMPtr runnable = new ExitFullScreenRunnable(jenv->NewGlobalRef(view)); michael@0: NS_DispatchToMainThread(runnable); michael@0: } michael@0: michael@0: NS_EXPORT jobject JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(JNIEnv* jenv, jclass, jobject queue) michael@0: { michael@0: static jclass jMessageQueueCls = nullptr; michael@0: static jfieldID jMessagesField; michael@0: static jmethodID jNextMethod; michael@0: if (!jMessageQueueCls) { michael@0: jMessageQueueCls = (jclass) jenv->NewGlobalRef(jenv->FindClass("android/os/MessageQueue")); michael@0: jNextMethod = jenv->GetMethodID(jMessageQueueCls, "next", "()Landroid/os/Message;"); michael@0: jMessagesField = jenv->GetFieldID(jMessageQueueCls, "mMessages", "Landroid/os/Message;"); michael@0: } michael@0: michael@0: if (!jMessageQueueCls || !jNextMethod) michael@0: return nullptr; michael@0: michael@0: if (jMessagesField) { michael@0: jobject msg = jenv->GetObjectField(queue, jMessagesField); michael@0: // if queue.mMessages is null, queue.next() will block, which we don't want michael@0: // It turns out to be an order of magnitude more performant to do this extra check here and michael@0: // block less vs. one fewer checks here and more blocking. michael@0: if (!msg) { michael@0: return nullptr; michael@0: } michael@0: } michael@0: return jenv->CallObjectMethod(queue, jNextMethod); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id) michael@0: { michael@0: nsSurfaceTexture* st = nsSurfaceTexture::Find(id); michael@0: if (!st) { michael@0: __android_log_print(ANDROID_LOG_ERROR, "GeckoJNI", "Failed to find nsSurfaceTexture with id %d", id); michael@0: return; michael@0: } michael@0: michael@0: st->NotifyFrameAvailable(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_GeckoAppShell_dispatchMemoryPressure(JNIEnv* jenv, jclass) michael@0: { michael@0: NS_DispatchMemoryPressure(MemPressure_New); michael@0: } michael@0: michael@0: NS_EXPORT jdouble JNICALL michael@0: Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc) michael@0: { michael@0: return profiler_time(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_abortAnimation(JNIEnv* env, jobject instance) michael@0: { michael@0: APZCTreeManager *controller = nsWindow::GetAPZCTreeManager(); michael@0: if (controller) { michael@0: // TODO: Pass in correct values for presShellId and viewId. michael@0: controller->CancelAnimation(ScrollableLayerGuid(nsWindow::RootLayerTreeId(), 0, 0)); michael@0: } michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance) michael@0: { michael@0: if (!AndroidBridge::Bridge()) { michael@0: return; michael@0: } michael@0: michael@0: NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(instance); michael@0: if (oldRef && !oldRef->isNull()) { michael@0: MOZ_ASSERT(false, "Registering a new NPZC when we already have one"); michael@0: delete oldRef; michael@0: } michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event) michael@0: { michael@0: APZCTreeManager *controller = nsWindow::GetAPZCTreeManager(); michael@0: if (controller) { michael@0: AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event); michael@0: const MultiTouchInput& input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow()); michael@0: delete wrapper; michael@0: if (input.mType >= 0) { michael@0: controller->ReceiveInputEvent(input, nullptr); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_handleMotionEvent(JNIEnv* env, jobject instance, jobject event) michael@0: { michael@0: // FIXME implement this michael@0: } michael@0: michael@0: NS_EXPORT jlong JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_runDelayedCallback(JNIEnv* env, jobject instance) michael@0: { michael@0: if (!AndroidBridge::Bridge()) { michael@0: return -1; michael@0: } michael@0: michael@0: return AndroidBridge::Bridge()->RunDelayedTasks(); michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject instance) michael@0: { michael@0: if (!AndroidBridge::Bridge()) { michael@0: return; michael@0: } michael@0: michael@0: NativePanZoomController* oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(nullptr); michael@0: if (!oldRef || oldRef->isNull()) { michael@0: MOZ_ASSERT(false, "Clearing a non-existent NPZC"); michael@0: } else { michael@0: delete oldRef; michael@0: } michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented) michael@0: { michael@0: APZCTreeManager *controller = nsWindow::GetAPZCTreeManager(); michael@0: if (controller) { michael@0: // TODO: Pass in correct values for presShellId and viewId. michael@0: controller->ContentReceivedTouch(ScrollableLayerGuid(nsWindow::RootLayerTreeId(), 0, 0), prevented); michael@0: } michael@0: } michael@0: michael@0: NS_EXPORT jboolean JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance) michael@0: { michael@0: // FIXME implement this michael@0: return true; michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_setOverScrollMode(JNIEnv* env, jobject instance, jint overscrollMode) michael@0: { michael@0: // FIXME implement this michael@0: } michael@0: michael@0: NS_EXPORT jint JNICALL michael@0: Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv* env, jobject instance) michael@0: { michael@0: // FIXME implement this michael@0: return 0; michael@0: } michael@0: michael@0: NS_EXPORT jboolean JNICALL michael@0: Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass, jboolean aUnwind) michael@0: { michael@0: if (profiler_is_active()) { michael@0: // Don't proceed if profiler is already running michael@0: return JNI_FALSE; michael@0: } michael@0: // WARNING: we are on the ANR reporter thread at this point and it is michael@0: // generally unsafe to use the profiler from off the main thread. However, michael@0: // the risk here is limited because for most users, the profiler is not run michael@0: // elsewhere. See the discussion in Bug 863777, comment 13 michael@0: const char *NATIVE_STACK_FEATURES[] = michael@0: {"leaf", "threads", "privacy"}; michael@0: const char *NATIVE_STACK_UNWIND_FEATURES[] = michael@0: {"leaf", "threads", "privacy", "stackwalk"}; michael@0: michael@0: const char **features = NATIVE_STACK_FEATURES; michael@0: size_t features_size = sizeof(NATIVE_STACK_FEATURES); michael@0: if (aUnwind) { michael@0: features = NATIVE_STACK_UNWIND_FEATURES; michael@0: features_size = sizeof(NATIVE_STACK_UNWIND_FEATURES); michael@0: // We want the new unwinder if the unwind mode has not been set yet michael@0: putenv("MOZ_PROFILER_NEW=1"); michael@0: } michael@0: michael@0: const char *NATIVE_STACK_THREADS[] = michael@0: {"GeckoMain", "Compositor"}; michael@0: // Buffer one sample and let the profiler wait a long time michael@0: profiler_start(100, 10000, features, features_size / sizeof(char*), michael@0: NATIVE_STACK_THREADS, sizeof(NATIVE_STACK_THREADS) / sizeof(char*)); michael@0: return JNI_TRUE; michael@0: } michael@0: michael@0: NS_EXPORT jstring JNICALL michael@0: Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv* jenv, jclass) michael@0: { michael@0: if (!profiler_is_active()) { michael@0: // Maybe profiler support is disabled? michael@0: return nullptr; michael@0: } michael@0: char *profile = profiler_get_profile(); michael@0: while (profile && !strlen(profile)) { michael@0: // no sample yet? michael@0: sched_yield(); michael@0: profile = profiler_get_profile(); michael@0: } michael@0: jstring result = nullptr; michael@0: if (profile) { michael@0: result = jenv->NewStringUTF(profile); michael@0: free(profile); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: NS_EXPORT void JNICALL michael@0: Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv* jenv, jclass) michael@0: { michael@0: if (!profiler_is_active()) { michael@0: // Maybe profiler support is disabled? michael@0: return; michael@0: } michael@0: mozilla_sampler_stop(); michael@0: } michael@0: michael@0: }