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: #ifndef AndroidBridge_h__ michael@0: #define AndroidBridge_h__ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCOMArray.h" michael@0: michael@0: #include "GeneratedJNIWrappers.h" michael@0: michael@0: #include "nsIMutableArray.h" michael@0: #include "nsIMIMEInfo.h" michael@0: #include "nsColor.h" michael@0: #include "gfxRect.h" michael@0: michael@0: #include "nsIAndroidBridge.h" michael@0: #include "nsIMobileMessageCallback.h" michael@0: michael@0: #include "mozilla/Likely.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/layers/GeckoContentController.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: michael@0: // Some debug #defines michael@0: // #define DEBUG_ANDROID_EVENTS michael@0: // #define DEBUG_ANDROID_WIDGET michael@0: michael@0: class nsWindow; michael@0: class nsIDOMMozSmsMessage; michael@0: class nsIObserver; michael@0: michael@0: /* See the comment in AndroidBridge about this function before using it */ michael@0: extern "C" JNIEnv * GetJNIForThread(); michael@0: michael@0: extern bool mozilla_AndroidBridge_SetMainThread(pthread_t); michael@0: michael@0: namespace base { michael@0: class Thread; michael@0: } // end namespace base michael@0: michael@0: typedef void* EGLSurface; michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace hal { michael@0: class BatteryInformation; michael@0: class NetworkInformation; michael@0: } // namespace hal michael@0: michael@0: namespace dom { michael@0: namespace mobilemessage { michael@0: struct SmsFilterData; michael@0: struct SmsSegmentInfoData; michael@0: } // namespace mobilemessage michael@0: } // namespace dom michael@0: michael@0: namespace layers { michael@0: class CompositorParent; michael@0: } // namespace layers michael@0: michael@0: // The order and number of the members in this structure must correspond michael@0: // to the attrsAppearance array in GeckoAppShell.getSystemColors() michael@0: typedef struct AndroidSystemColors { michael@0: nscolor textColorPrimary; michael@0: nscolor textColorPrimaryInverse; michael@0: nscolor textColorSecondary; michael@0: nscolor textColorSecondaryInverse; michael@0: nscolor textColorTertiary; michael@0: nscolor textColorTertiaryInverse; michael@0: nscolor textColorHighlight; michael@0: nscolor colorForeground; michael@0: nscolor colorBackground; michael@0: nscolor panelColorForeground; michael@0: nscolor panelColorBackground; michael@0: } AndroidSystemColors; michael@0: michael@0: class nsFilePickerCallback : nsISupports { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: virtual void handleResult(nsAString& filePath) = 0; michael@0: nsFilePickerCallback() {} michael@0: protected: michael@0: virtual ~nsFilePickerCallback() {} michael@0: }; michael@0: michael@0: class DelayedTask { michael@0: public: michael@0: DelayedTask(Task* aTask, int aDelayMs) { michael@0: mTask = aTask; michael@0: mRunTime = TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs); michael@0: } michael@0: michael@0: bool IsEarlierThan(DelayedTask *aOther) { michael@0: return mRunTime < aOther->mRunTime; michael@0: } michael@0: michael@0: int64_t MillisecondsToRunTime() { michael@0: TimeDuration timeLeft = mRunTime - TimeStamp::Now(); michael@0: return (int64_t)timeLeft.ToMilliseconds(); michael@0: } michael@0: michael@0: Task* GetTask() { michael@0: return mTask; michael@0: } michael@0: michael@0: private: michael@0: Task* mTask; michael@0: TimeStamp mRunTime; michael@0: }; michael@0: michael@0: michael@0: class AndroidBridge MOZ_FINAL : public mozilla::layers::GeckoContentController michael@0: { michael@0: public: michael@0: enum { michael@0: // Values for NotifyIME, in addition to values from the Gecko michael@0: // IMEMessage enum; use negative values here to prevent conflict michael@0: NOTIFY_IME_OPEN_VKB = -2, michael@0: NOTIFY_IME_REPLY_EVENT = -1, michael@0: }; michael@0: michael@0: enum { michael@0: LAYER_CLIENT_TYPE_NONE = 0, michael@0: LAYER_CLIENT_TYPE_GL = 2 // AndroidGeckoGLLayerClient michael@0: }; michael@0: michael@0: static void ConstructBridge(JNIEnv *jEnv); michael@0: michael@0: static AndroidBridge *Bridge() { michael@0: return sBridge.get(); michael@0: } michael@0: michael@0: static JavaVM *GetVM() { michael@0: MOZ_ASSERT(sBridge); michael@0: return sBridge->mJavaVM; michael@0: } michael@0: michael@0: michael@0: static JNIEnv *GetJNIEnv() { michael@0: MOZ_ASSERT(sBridge); michael@0: if (MOZ_UNLIKELY(!pthread_equal(pthread_self(), sBridge->mThread))) { michael@0: MOZ_CRASH(); michael@0: } michael@0: MOZ_ASSERT(sBridge->mJNIEnv); michael@0: return sBridge->mJNIEnv; michael@0: } michael@0: michael@0: static bool HasEnv() { michael@0: return sBridge && sBridge->mJNIEnv; michael@0: } michael@0: michael@0: static bool ThrowException(JNIEnv *aEnv, const char *aClass, michael@0: const char *aMessage) { michael@0: MOZ_ASSERT(aEnv, "Invalid thread JNI env"); michael@0: jclass cls = aEnv->FindClass(aClass); michael@0: MOZ_ASSERT(cls, "Cannot find exception class"); michael@0: bool ret = !aEnv->ThrowNew(cls, aMessage); michael@0: aEnv->DeleteLocalRef(cls); michael@0: return ret; michael@0: } michael@0: michael@0: static bool ThrowException(JNIEnv *aEnv, const char *aMessage) { michael@0: return ThrowException(aEnv, "java/lang/Exception", aMessage); michael@0: } michael@0: michael@0: static void HandleUncaughtException(JNIEnv *aEnv) { michael@0: MOZ_ASSERT(aEnv); michael@0: if (!aEnv->ExceptionCheck()) { michael@0: return; michael@0: } michael@0: jthrowable e = aEnv->ExceptionOccurred(); michael@0: MOZ_ASSERT(e); michael@0: aEnv->ExceptionClear(); michael@0: mozilla::widget::android::GeckoAppShell::HandleUncaughtException(nullptr, e); michael@0: // Should be dead by now... michael@0: MOZ_CRASH("Failed to handle uncaught exception"); michael@0: } michael@0: michael@0: // The bridge needs to be constructed via ConstructBridge first, michael@0: // and then once the Gecko main thread is spun up (Gecko side), michael@0: // SetMainThread should be called which will create the JNIEnv for michael@0: // us to use. toolkit/xre/nsAndroidStartup.cpp calls michael@0: // SetMainThread. michael@0: bool SetMainThread(pthread_t thr); michael@0: michael@0: /* These are all implemented in Java */ michael@0: bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult); michael@0: bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult); michael@0: michael@0: nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer); michael@0: void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort); michael@0: void ContentDocumentChanged(); michael@0: bool IsContentDocumentDisplayed(); michael@0: michael@0: bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, mozilla::ParentLayerRect& aCompositionBounds, mozilla::CSSToParentLayerScale& aZoom); michael@0: michael@0: void SetLayerClient(JNIEnv* env, jobject jobj); michael@0: mozilla::widget::android::GeckoLayerClient* GetLayerClient() { return mLayerClient; } michael@0: michael@0: bool GetHandlersForURL(const nsAString& aURL, michael@0: nsIMutableArray* handlersArray = nullptr, michael@0: nsIHandlerApp **aDefaultApp = nullptr, michael@0: const nsAString& aAction = EmptyString()); michael@0: michael@0: bool GetHandlersForMimeType(const nsAString& aMimeType, michael@0: nsIMutableArray* handlersArray = nullptr, michael@0: nsIHandlerApp **aDefaultApp = nullptr, michael@0: const nsAString& aAction = EmptyString()); michael@0: michael@0: void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType); michael@0: void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt); michael@0: michael@0: bool GetClipboardText(nsAString& aText); michael@0: michael@0: void ShowAlertNotification(const nsAString& aImageUrl, michael@0: const nsAString& aAlertTitle, michael@0: const nsAString& aAlertText, michael@0: const nsAString& aAlertData, michael@0: nsIObserver *aAlertListener, michael@0: const nsAString& aAlertName); michael@0: michael@0: int GetDPI(); michael@0: int GetScreenDepth(); michael@0: michael@0: void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions); michael@0: void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType); michael@0: void ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback); michael@0: michael@0: void Vibrate(const nsTArray& aPattern); michael@0: michael@0: void GetSystemColors(AndroidSystemColors *aColors); michael@0: michael@0: void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf); michael@0: michael@0: // Switch Java to composite with the Gecko Compositor thread michael@0: void RegisterCompositor(JNIEnv* env = nullptr); michael@0: EGLSurface CreateEGLSurfaceForCompositor(); michael@0: michael@0: bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr); michael@0: michael@0: bool GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env = nullptr); michael@0: michael@0: // These next four functions are for native Bitmap access in Android 2.2+ michael@0: bool HasNativeBitmapAccess(); michael@0: michael@0: bool ValidateBitmap(jobject bitmap, int width, int height); michael@0: michael@0: void *LockBitmap(jobject bitmap); michael@0: michael@0: // Returns a global reference to the Context for Fennec's Activity. The michael@0: // caller is responsible for ensuring this doesn't leak by calling michael@0: // DeleteGlobalRef() when the context is no longer needed. michael@0: jobject GetGlobalContextRef(void); michael@0: michael@0: void UnlockBitmap(jobject bitmap); michael@0: michael@0: /* Copied from Android's native_window.h in newer (platform 9) NDK */ michael@0: enum { michael@0: WINDOW_FORMAT_RGBA_8888 = 1, michael@0: WINDOW_FORMAT_RGBX_8888 = 2, michael@0: WINDOW_FORMAT_RGB_565 = 4 michael@0: }; michael@0: michael@0: bool HasNativeWindowAccess(); michael@0: michael@0: void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface); michael@0: void ReleaseNativeWindow(void *window); michael@0: michael@0: void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface); michael@0: void ReleaseNativeWindowForSurfaceTexture(void *window); michael@0: michael@0: bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride); michael@0: bool UnlockWindow(void *window); michael@0: michael@0: void HandleGeckoMessage(JSContext* cx, JS::HandleObject message); michael@0: michael@0: bool InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps); michael@0: michael@0: void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo); michael@0: michael@0: nsresult GetSegmentInfoForText(const nsAString& aText, michael@0: nsIMobileMessageCallback* aRequest); michael@0: void SendMessage(const nsAString& aNumber, const nsAString& aText, michael@0: nsIMobileMessageCallback* aRequest); michael@0: void GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest); michael@0: void DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest); michael@0: void CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, michael@0: bool aReverse, nsIMobileMessageCallback* aRequest); michael@0: void GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest); michael@0: already_AddRefed DequeueSmsRequest(uint32_t aRequestId); michael@0: michael@0: void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo); michael@0: michael@0: void SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect); michael@0: void SetPageRect(const CSSRect& aCssPageRect); michael@0: void SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, michael@0: bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale, michael@0: LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset); michael@0: void SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, michael@0: bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, michael@0: bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset); michael@0: michael@0: void AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen); michael@0: michael@0: // These methods don't use a ScreenOrientation because it's an michael@0: // enum and that would require including the header which requires michael@0: // include IPC headers which requires including basictypes.h which michael@0: // requires a lot of changes... michael@0: uint32_t GetScreenOrientation(); michael@0: michael@0: int GetAPIVersion() { return mAPIVersion; } michael@0: bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; } michael@0: michael@0: void ScheduleComposite(); michael@0: michael@0: nsresult GetProxyForURI(const nsACString & aSpec, michael@0: const nsACString & aScheme, michael@0: const nsACString & aHost, michael@0: const int32_t aPort, michael@0: nsACString & aResult); michael@0: michael@0: // Utility methods. michael@0: static jstring NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len); michael@0: static jstring NewJavaString(JNIEnv* env, const nsAString& string); michael@0: static jstring NewJavaString(JNIEnv* env, const char* string); michael@0: static jstring NewJavaString(JNIEnv* env, const nsACString& string); michael@0: michael@0: static jstring NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len); michael@0: static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string); michael@0: static jstring NewJavaString(AutoLocalJNIFrame* frame, const char* string); michael@0: static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string); michael@0: michael@0: static jclass GetClassGlobalRef(JNIEnv* env, const char* className); michael@0: static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); michael@0: static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); michael@0: static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType); michael@0: static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType); michael@0: protected: michael@0: static StaticRefPtr sBridge; michael@0: nsTArray > mSmsRequests; michael@0: michael@0: // the global JavaVM michael@0: JavaVM *mJavaVM; michael@0: michael@0: // the JNIEnv for the main thread michael@0: JNIEnv *mJNIEnv; michael@0: pthread_t mThread; michael@0: michael@0: mozilla::widget::android::GeckoLayerClient *mLayerClient; michael@0: michael@0: // the android.telephony.SmsMessage class michael@0: jclass mAndroidSmsMessageClass; michael@0: michael@0: AndroidBridge(); michael@0: ~AndroidBridge(); michael@0: michael@0: void InitStubs(JNIEnv *jEnv); michael@0: bool Init(JNIEnv *jEnv); michael@0: michael@0: bool mOpenedGraphicsLibraries; michael@0: void OpenGraphicsLibraries(); michael@0: void* GetNativeSurface(JNIEnv* env, jobject surface); michael@0: michael@0: bool mHasNativeBitmapAccess; michael@0: bool mHasNativeWindowAccess; michael@0: bool mHasNativeWindowFallback; michael@0: michael@0: int mAPIVersion; michael@0: michael@0: bool QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut); michael@0: michael@0: // other things michael@0: jmethodID jNotifyAppShellReady; michael@0: jmethodID jGetOutstandingDrawEvents; michael@0: jmethodID jPostToJavaThread; michael@0: jmethodID jCreateSurface; michael@0: jmethodID jShowSurface; michael@0: jmethodID jHideSurface; michael@0: jmethodID jDestroySurface; michael@0: michael@0: jmethodID jCalculateLength; michael@0: michael@0: // For native surface stuff michael@0: jclass jSurfaceClass; michael@0: jfieldID jSurfacePointerField; michael@0: michael@0: jclass jLayerView; michael@0: michael@0: jfieldID jEGLSurfacePointerField; michael@0: mozilla::widget::android::GLController *mGLControllerObj; michael@0: michael@0: // some convinient types to have around michael@0: jclass jStringClass; michael@0: michael@0: // calls we've dlopened from libjnigraphics.so michael@0: int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info); michael@0: int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer); michael@0: int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap); michael@0: michael@0: void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface); michael@0: void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture); michael@0: void (*ANativeWindow_release)(void *window); michael@0: int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format); michael@0: michael@0: int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds); michael@0: int (* ANativeWindow_unlockAndPost)(void *window); michael@0: michael@0: int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block); michael@0: int (* Surface_unlockAndPost)(void* surface); michael@0: void (* Region_constructor)(void* region); michael@0: void (* Region_set)(void* region, void* rect); michael@0: michael@0: private: michael@0: mozilla::widget::android::NativePanZoomController* mNativePanZoomController; michael@0: // This will always be accessed from one thread (the APZC "controller" michael@0: // thread, which is the Java UI thread), so we don't need to do locking michael@0: // to touch it michael@0: nsTArray mDelayedTaskQueue; michael@0: michael@0: public: michael@0: mozilla::widget::android::NativePanZoomController* SetNativePanZoomController(jobject obj); michael@0: // GeckoContentController methods michael@0: void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE; michael@0: void AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId, michael@0: const uint32_t& aScrollGeneration) MOZ_OVERRIDE; michael@0: void HandleDoubleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; michael@0: void HandleSingleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; michael@0: void HandleLongTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; michael@0: void HandleLongTapUp(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; michael@0: void SendAsyncScrollDOMEvent(bool aIsRoot, michael@0: const CSSRect& aContentRect, michael@0: const CSSSize& aScrollableSize) MOZ_OVERRIDE; michael@0: void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE; michael@0: int64_t RunDelayedTasks(); michael@0: }; michael@0: michael@0: class AutoJObject { michael@0: public: michael@0: AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr) michael@0: { michael@0: mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); michael@0: } michael@0: michael@0: AutoJObject(JNIEnv* aJNIEnv, jobject aObject) michael@0: { michael@0: mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); michael@0: mObject = aObject; michael@0: } michael@0: michael@0: ~AutoJObject() { michael@0: if (mObject) michael@0: mJNIEnv->DeleteLocalRef(mObject); michael@0: } michael@0: michael@0: jobject operator=(jobject aObject) michael@0: { michael@0: if (mObject) { michael@0: mJNIEnv->DeleteLocalRef(mObject); michael@0: } michael@0: return mObject = aObject; michael@0: } michael@0: michael@0: operator jobject() { michael@0: return mObject; michael@0: } michael@0: private: michael@0: JNIEnv* mJNIEnv; michael@0: jobject mObject; michael@0: }; michael@0: michael@0: class AutoLocalJNIFrame { michael@0: public: michael@0: AutoLocalJNIFrame(int nEntries = 15) michael@0: : mEntries(nEntries) michael@0: , mJNIEnv(AndroidBridge::GetJNIEnv()) michael@0: , mHasFrameBeenPushed(false) michael@0: { michael@0: MOZ_ASSERT(mJNIEnv); michael@0: Push(); michael@0: } michael@0: michael@0: AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 15) michael@0: : mEntries(nEntries) michael@0: , mJNIEnv(aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv()) michael@0: , mHasFrameBeenPushed(false) michael@0: { michael@0: MOZ_ASSERT(mJNIEnv); michael@0: Push(); michael@0: } michael@0: michael@0: ~AutoLocalJNIFrame() { michael@0: if (mHasFrameBeenPushed) { michael@0: Pop(); michael@0: } michael@0: } michael@0: michael@0: JNIEnv* GetEnv() { michael@0: return mJNIEnv; michael@0: } michael@0: michael@0: bool CheckForException() { michael@0: if (mJNIEnv->ExceptionCheck()) { michael@0: AndroidBridge::HandleUncaughtException(mJNIEnv); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // Note! Calling Purge makes all previous local refs created in michael@0: // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down michael@0: // any local refs that you need to keep around in global refs! michael@0: void Purge() { michael@0: Pop(); michael@0: Push(); michael@0: } michael@0: michael@0: template michael@0: ReturnType Pop(ReturnType aResult = nullptr) { michael@0: MOZ_ASSERT(mHasFrameBeenPushed); michael@0: mHasFrameBeenPushed = false; michael@0: return static_cast( michael@0: mJNIEnv->PopLocalFrame(static_cast(aResult))); michael@0: } michael@0: michael@0: private: michael@0: void Push() { michael@0: MOZ_ASSERT(!mHasFrameBeenPushed); michael@0: // Make sure there is enough space to store a local ref to the michael@0: // exception. I am not completely sure this is needed, but does michael@0: // not hurt. michael@0: if (mJNIEnv->PushLocalFrame(mEntries + 1) != 0) { michael@0: CheckForException(); michael@0: return; michael@0: } michael@0: mHasFrameBeenPushed = true; michael@0: } michael@0: michael@0: const int mEntries; michael@0: JNIEnv* const mJNIEnv; michael@0: bool mHasFrameBeenPushed; michael@0: }; michael@0: michael@0: } michael@0: michael@0: #define NS_ANDROIDBRIDGE_CID \ michael@0: { 0x0FE2321D, 0xEBD9, 0x467D, \ michael@0: { 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } } michael@0: michael@0: class nsAndroidBridge MOZ_FINAL : public nsIAndroidBridge michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIANDROIDBRIDGE michael@0: michael@0: nsAndroidBridge(); michael@0: michael@0: private: michael@0: ~nsAndroidBridge(); michael@0: michael@0: protected: michael@0: }; michael@0: michael@0: #endif /* AndroidBridge_h__ */