|
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/. */ |
|
5 |
|
6 #ifndef AndroidBridge_h__ |
|
7 #define AndroidBridge_h__ |
|
8 |
|
9 #include <jni.h> |
|
10 #include <android/log.h> |
|
11 #include <cstdlib> |
|
12 #include <pthread.h> |
|
13 |
|
14 #include "nsCOMPtr.h" |
|
15 #include "nsCOMArray.h" |
|
16 |
|
17 #include "GeneratedJNIWrappers.h" |
|
18 |
|
19 #include "nsIMutableArray.h" |
|
20 #include "nsIMIMEInfo.h" |
|
21 #include "nsColor.h" |
|
22 #include "gfxRect.h" |
|
23 |
|
24 #include "nsIAndroidBridge.h" |
|
25 #include "nsIMobileMessageCallback.h" |
|
26 |
|
27 #include "mozilla/Likely.h" |
|
28 #include "mozilla/StaticPtr.h" |
|
29 #include "mozilla/layers/GeckoContentController.h" |
|
30 #include "mozilla/TimeStamp.h" |
|
31 |
|
32 // Some debug #defines |
|
33 // #define DEBUG_ANDROID_EVENTS |
|
34 // #define DEBUG_ANDROID_WIDGET |
|
35 |
|
36 class nsWindow; |
|
37 class nsIDOMMozSmsMessage; |
|
38 class nsIObserver; |
|
39 |
|
40 /* See the comment in AndroidBridge about this function before using it */ |
|
41 extern "C" JNIEnv * GetJNIForThread(); |
|
42 |
|
43 extern bool mozilla_AndroidBridge_SetMainThread(pthread_t); |
|
44 |
|
45 namespace base { |
|
46 class Thread; |
|
47 } // end namespace base |
|
48 |
|
49 typedef void* EGLSurface; |
|
50 |
|
51 namespace mozilla { |
|
52 |
|
53 namespace hal { |
|
54 class BatteryInformation; |
|
55 class NetworkInformation; |
|
56 } // namespace hal |
|
57 |
|
58 namespace dom { |
|
59 namespace mobilemessage { |
|
60 struct SmsFilterData; |
|
61 struct SmsSegmentInfoData; |
|
62 } // namespace mobilemessage |
|
63 } // namespace dom |
|
64 |
|
65 namespace layers { |
|
66 class CompositorParent; |
|
67 } // namespace layers |
|
68 |
|
69 // The order and number of the members in this structure must correspond |
|
70 // to the attrsAppearance array in GeckoAppShell.getSystemColors() |
|
71 typedef struct AndroidSystemColors { |
|
72 nscolor textColorPrimary; |
|
73 nscolor textColorPrimaryInverse; |
|
74 nscolor textColorSecondary; |
|
75 nscolor textColorSecondaryInverse; |
|
76 nscolor textColorTertiary; |
|
77 nscolor textColorTertiaryInverse; |
|
78 nscolor textColorHighlight; |
|
79 nscolor colorForeground; |
|
80 nscolor colorBackground; |
|
81 nscolor panelColorForeground; |
|
82 nscolor panelColorBackground; |
|
83 } AndroidSystemColors; |
|
84 |
|
85 class nsFilePickerCallback : nsISupports { |
|
86 public: |
|
87 NS_DECL_THREADSAFE_ISUPPORTS |
|
88 virtual void handleResult(nsAString& filePath) = 0; |
|
89 nsFilePickerCallback() {} |
|
90 protected: |
|
91 virtual ~nsFilePickerCallback() {} |
|
92 }; |
|
93 |
|
94 class DelayedTask { |
|
95 public: |
|
96 DelayedTask(Task* aTask, int aDelayMs) { |
|
97 mTask = aTask; |
|
98 mRunTime = TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs); |
|
99 } |
|
100 |
|
101 bool IsEarlierThan(DelayedTask *aOther) { |
|
102 return mRunTime < aOther->mRunTime; |
|
103 } |
|
104 |
|
105 int64_t MillisecondsToRunTime() { |
|
106 TimeDuration timeLeft = mRunTime - TimeStamp::Now(); |
|
107 return (int64_t)timeLeft.ToMilliseconds(); |
|
108 } |
|
109 |
|
110 Task* GetTask() { |
|
111 return mTask; |
|
112 } |
|
113 |
|
114 private: |
|
115 Task* mTask; |
|
116 TimeStamp mRunTime; |
|
117 }; |
|
118 |
|
119 |
|
120 class AndroidBridge MOZ_FINAL : public mozilla::layers::GeckoContentController |
|
121 { |
|
122 public: |
|
123 enum { |
|
124 // Values for NotifyIME, in addition to values from the Gecko |
|
125 // IMEMessage enum; use negative values here to prevent conflict |
|
126 NOTIFY_IME_OPEN_VKB = -2, |
|
127 NOTIFY_IME_REPLY_EVENT = -1, |
|
128 }; |
|
129 |
|
130 enum { |
|
131 LAYER_CLIENT_TYPE_NONE = 0, |
|
132 LAYER_CLIENT_TYPE_GL = 2 // AndroidGeckoGLLayerClient |
|
133 }; |
|
134 |
|
135 static void ConstructBridge(JNIEnv *jEnv); |
|
136 |
|
137 static AndroidBridge *Bridge() { |
|
138 return sBridge.get(); |
|
139 } |
|
140 |
|
141 static JavaVM *GetVM() { |
|
142 MOZ_ASSERT(sBridge); |
|
143 return sBridge->mJavaVM; |
|
144 } |
|
145 |
|
146 |
|
147 static JNIEnv *GetJNIEnv() { |
|
148 MOZ_ASSERT(sBridge); |
|
149 if (MOZ_UNLIKELY(!pthread_equal(pthread_self(), sBridge->mThread))) { |
|
150 MOZ_CRASH(); |
|
151 } |
|
152 MOZ_ASSERT(sBridge->mJNIEnv); |
|
153 return sBridge->mJNIEnv; |
|
154 } |
|
155 |
|
156 static bool HasEnv() { |
|
157 return sBridge && sBridge->mJNIEnv; |
|
158 } |
|
159 |
|
160 static bool ThrowException(JNIEnv *aEnv, const char *aClass, |
|
161 const char *aMessage) { |
|
162 MOZ_ASSERT(aEnv, "Invalid thread JNI env"); |
|
163 jclass cls = aEnv->FindClass(aClass); |
|
164 MOZ_ASSERT(cls, "Cannot find exception class"); |
|
165 bool ret = !aEnv->ThrowNew(cls, aMessage); |
|
166 aEnv->DeleteLocalRef(cls); |
|
167 return ret; |
|
168 } |
|
169 |
|
170 static bool ThrowException(JNIEnv *aEnv, const char *aMessage) { |
|
171 return ThrowException(aEnv, "java/lang/Exception", aMessage); |
|
172 } |
|
173 |
|
174 static void HandleUncaughtException(JNIEnv *aEnv) { |
|
175 MOZ_ASSERT(aEnv); |
|
176 if (!aEnv->ExceptionCheck()) { |
|
177 return; |
|
178 } |
|
179 jthrowable e = aEnv->ExceptionOccurred(); |
|
180 MOZ_ASSERT(e); |
|
181 aEnv->ExceptionClear(); |
|
182 mozilla::widget::android::GeckoAppShell::HandleUncaughtException(nullptr, e); |
|
183 // Should be dead by now... |
|
184 MOZ_CRASH("Failed to handle uncaught exception"); |
|
185 } |
|
186 |
|
187 // The bridge needs to be constructed via ConstructBridge first, |
|
188 // and then once the Gecko main thread is spun up (Gecko side), |
|
189 // SetMainThread should be called which will create the JNIEnv for |
|
190 // us to use. toolkit/xre/nsAndroidStartup.cpp calls |
|
191 // SetMainThread. |
|
192 bool SetMainThread(pthread_t thr); |
|
193 |
|
194 /* These are all implemented in Java */ |
|
195 bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult); |
|
196 bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult); |
|
197 |
|
198 nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer); |
|
199 void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort); |
|
200 void ContentDocumentChanged(); |
|
201 bool IsContentDocumentDisplayed(); |
|
202 |
|
203 bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, mozilla::ParentLayerRect& aCompositionBounds, mozilla::CSSToParentLayerScale& aZoom); |
|
204 |
|
205 void SetLayerClient(JNIEnv* env, jobject jobj); |
|
206 mozilla::widget::android::GeckoLayerClient* GetLayerClient() { return mLayerClient; } |
|
207 |
|
208 bool GetHandlersForURL(const nsAString& aURL, |
|
209 nsIMutableArray* handlersArray = nullptr, |
|
210 nsIHandlerApp **aDefaultApp = nullptr, |
|
211 const nsAString& aAction = EmptyString()); |
|
212 |
|
213 bool GetHandlersForMimeType(const nsAString& aMimeType, |
|
214 nsIMutableArray* handlersArray = nullptr, |
|
215 nsIHandlerApp **aDefaultApp = nullptr, |
|
216 const nsAString& aAction = EmptyString()); |
|
217 |
|
218 void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType); |
|
219 void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt); |
|
220 |
|
221 bool GetClipboardText(nsAString& aText); |
|
222 |
|
223 void ShowAlertNotification(const nsAString& aImageUrl, |
|
224 const nsAString& aAlertTitle, |
|
225 const nsAString& aAlertText, |
|
226 const nsAString& aAlertData, |
|
227 nsIObserver *aAlertListener, |
|
228 const nsAString& aAlertName); |
|
229 |
|
230 int GetDPI(); |
|
231 int GetScreenDepth(); |
|
232 |
|
233 void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions); |
|
234 void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType); |
|
235 void ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback); |
|
236 |
|
237 void Vibrate(const nsTArray<uint32_t>& aPattern); |
|
238 |
|
239 void GetSystemColors(AndroidSystemColors *aColors); |
|
240 |
|
241 void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf); |
|
242 |
|
243 // Switch Java to composite with the Gecko Compositor thread |
|
244 void RegisterCompositor(JNIEnv* env = nullptr); |
|
245 EGLSurface CreateEGLSurfaceForCompositor(); |
|
246 |
|
247 bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr); |
|
248 |
|
249 bool GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env = nullptr); |
|
250 |
|
251 // These next four functions are for native Bitmap access in Android 2.2+ |
|
252 bool HasNativeBitmapAccess(); |
|
253 |
|
254 bool ValidateBitmap(jobject bitmap, int width, int height); |
|
255 |
|
256 void *LockBitmap(jobject bitmap); |
|
257 |
|
258 // Returns a global reference to the Context for Fennec's Activity. The |
|
259 // caller is responsible for ensuring this doesn't leak by calling |
|
260 // DeleteGlobalRef() when the context is no longer needed. |
|
261 jobject GetGlobalContextRef(void); |
|
262 |
|
263 void UnlockBitmap(jobject bitmap); |
|
264 |
|
265 /* Copied from Android's native_window.h in newer (platform 9) NDK */ |
|
266 enum { |
|
267 WINDOW_FORMAT_RGBA_8888 = 1, |
|
268 WINDOW_FORMAT_RGBX_8888 = 2, |
|
269 WINDOW_FORMAT_RGB_565 = 4 |
|
270 }; |
|
271 |
|
272 bool HasNativeWindowAccess(); |
|
273 |
|
274 void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface); |
|
275 void ReleaseNativeWindow(void *window); |
|
276 |
|
277 void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface); |
|
278 void ReleaseNativeWindowForSurfaceTexture(void *window); |
|
279 |
|
280 bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride); |
|
281 bool UnlockWindow(void *window); |
|
282 |
|
283 void HandleGeckoMessage(JSContext* cx, JS::HandleObject message); |
|
284 |
|
285 bool InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps); |
|
286 |
|
287 void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo); |
|
288 |
|
289 nsresult GetSegmentInfoForText(const nsAString& aText, |
|
290 nsIMobileMessageCallback* aRequest); |
|
291 void SendMessage(const nsAString& aNumber, const nsAString& aText, |
|
292 nsIMobileMessageCallback* aRequest); |
|
293 void GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest); |
|
294 void DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest); |
|
295 void CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, |
|
296 bool aReverse, nsIMobileMessageCallback* aRequest); |
|
297 void GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest); |
|
298 already_AddRefed<nsIMobileMessageCallback> DequeueSmsRequest(uint32_t aRequestId); |
|
299 |
|
300 void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo); |
|
301 |
|
302 void SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect); |
|
303 void SetPageRect(const CSSRect& aCssPageRect); |
|
304 void SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, |
|
305 bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale, |
|
306 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset); |
|
307 void SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect, |
|
308 bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution, |
|
309 bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset); |
|
310 |
|
311 void AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen); |
|
312 |
|
313 // These methods don't use a ScreenOrientation because it's an |
|
314 // enum and that would require including the header which requires |
|
315 // include IPC headers which requires including basictypes.h which |
|
316 // requires a lot of changes... |
|
317 uint32_t GetScreenOrientation(); |
|
318 |
|
319 int GetAPIVersion() { return mAPIVersion; } |
|
320 bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; } |
|
321 |
|
322 void ScheduleComposite(); |
|
323 |
|
324 nsresult GetProxyForURI(const nsACString & aSpec, |
|
325 const nsACString & aScheme, |
|
326 const nsACString & aHost, |
|
327 const int32_t aPort, |
|
328 nsACString & aResult); |
|
329 |
|
330 // Utility methods. |
|
331 static jstring NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len); |
|
332 static jstring NewJavaString(JNIEnv* env, const nsAString& string); |
|
333 static jstring NewJavaString(JNIEnv* env, const char* string); |
|
334 static jstring NewJavaString(JNIEnv* env, const nsACString& string); |
|
335 |
|
336 static jstring NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len); |
|
337 static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string); |
|
338 static jstring NewJavaString(AutoLocalJNIFrame* frame, const char* string); |
|
339 static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string); |
|
340 |
|
341 static jclass GetClassGlobalRef(JNIEnv* env, const char* className); |
|
342 static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); |
|
343 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); |
|
344 static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType); |
|
345 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType); |
|
346 protected: |
|
347 static StaticRefPtr<AndroidBridge> sBridge; |
|
348 nsTArray<nsCOMPtr<nsIMobileMessageCallback> > mSmsRequests; |
|
349 |
|
350 // the global JavaVM |
|
351 JavaVM *mJavaVM; |
|
352 |
|
353 // the JNIEnv for the main thread |
|
354 JNIEnv *mJNIEnv; |
|
355 pthread_t mThread; |
|
356 |
|
357 mozilla::widget::android::GeckoLayerClient *mLayerClient; |
|
358 |
|
359 // the android.telephony.SmsMessage class |
|
360 jclass mAndroidSmsMessageClass; |
|
361 |
|
362 AndroidBridge(); |
|
363 ~AndroidBridge(); |
|
364 |
|
365 void InitStubs(JNIEnv *jEnv); |
|
366 bool Init(JNIEnv *jEnv); |
|
367 |
|
368 bool mOpenedGraphicsLibraries; |
|
369 void OpenGraphicsLibraries(); |
|
370 void* GetNativeSurface(JNIEnv* env, jobject surface); |
|
371 |
|
372 bool mHasNativeBitmapAccess; |
|
373 bool mHasNativeWindowAccess; |
|
374 bool mHasNativeWindowFallback; |
|
375 |
|
376 int mAPIVersion; |
|
377 |
|
378 bool QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut); |
|
379 |
|
380 // other things |
|
381 jmethodID jNotifyAppShellReady; |
|
382 jmethodID jGetOutstandingDrawEvents; |
|
383 jmethodID jPostToJavaThread; |
|
384 jmethodID jCreateSurface; |
|
385 jmethodID jShowSurface; |
|
386 jmethodID jHideSurface; |
|
387 jmethodID jDestroySurface; |
|
388 |
|
389 jmethodID jCalculateLength; |
|
390 |
|
391 // For native surface stuff |
|
392 jclass jSurfaceClass; |
|
393 jfieldID jSurfacePointerField; |
|
394 |
|
395 jclass jLayerView; |
|
396 |
|
397 jfieldID jEGLSurfacePointerField; |
|
398 mozilla::widget::android::GLController *mGLControllerObj; |
|
399 |
|
400 // some convinient types to have around |
|
401 jclass jStringClass; |
|
402 |
|
403 // calls we've dlopened from libjnigraphics.so |
|
404 int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info); |
|
405 int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer); |
|
406 int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap); |
|
407 |
|
408 void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface); |
|
409 void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture); |
|
410 void (*ANativeWindow_release)(void *window); |
|
411 int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format); |
|
412 |
|
413 int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds); |
|
414 int (* ANativeWindow_unlockAndPost)(void *window); |
|
415 |
|
416 int (* Surface_lock)(void* surface, void* surfaceInfo, void* region, bool block); |
|
417 int (* Surface_unlockAndPost)(void* surface); |
|
418 void (* Region_constructor)(void* region); |
|
419 void (* Region_set)(void* region, void* rect); |
|
420 |
|
421 private: |
|
422 mozilla::widget::android::NativePanZoomController* mNativePanZoomController; |
|
423 // This will always be accessed from one thread (the APZC "controller" |
|
424 // thread, which is the Java UI thread), so we don't need to do locking |
|
425 // to touch it |
|
426 nsTArray<DelayedTask*> mDelayedTaskQueue; |
|
427 |
|
428 public: |
|
429 mozilla::widget::android::NativePanZoomController* SetNativePanZoomController(jobject obj); |
|
430 // GeckoContentController methods |
|
431 void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE; |
|
432 void AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId, |
|
433 const uint32_t& aScrollGeneration) MOZ_OVERRIDE; |
|
434 void HandleDoubleTap(const CSSPoint& aPoint, |
|
435 int32_t aModifiers, |
|
436 const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; |
|
437 void HandleSingleTap(const CSSPoint& aPoint, |
|
438 int32_t aModifiers, |
|
439 const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; |
|
440 void HandleLongTap(const CSSPoint& aPoint, |
|
441 int32_t aModifiers, |
|
442 const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; |
|
443 void HandleLongTapUp(const CSSPoint& aPoint, |
|
444 int32_t aModifiers, |
|
445 const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE; |
|
446 void SendAsyncScrollDOMEvent(bool aIsRoot, |
|
447 const CSSRect& aContentRect, |
|
448 const CSSSize& aScrollableSize) MOZ_OVERRIDE; |
|
449 void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE; |
|
450 int64_t RunDelayedTasks(); |
|
451 }; |
|
452 |
|
453 class AutoJObject { |
|
454 public: |
|
455 AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr) |
|
456 { |
|
457 mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); |
|
458 } |
|
459 |
|
460 AutoJObject(JNIEnv* aJNIEnv, jobject aObject) |
|
461 { |
|
462 mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); |
|
463 mObject = aObject; |
|
464 } |
|
465 |
|
466 ~AutoJObject() { |
|
467 if (mObject) |
|
468 mJNIEnv->DeleteLocalRef(mObject); |
|
469 } |
|
470 |
|
471 jobject operator=(jobject aObject) |
|
472 { |
|
473 if (mObject) { |
|
474 mJNIEnv->DeleteLocalRef(mObject); |
|
475 } |
|
476 return mObject = aObject; |
|
477 } |
|
478 |
|
479 operator jobject() { |
|
480 return mObject; |
|
481 } |
|
482 private: |
|
483 JNIEnv* mJNIEnv; |
|
484 jobject mObject; |
|
485 }; |
|
486 |
|
487 class AutoLocalJNIFrame { |
|
488 public: |
|
489 AutoLocalJNIFrame(int nEntries = 15) |
|
490 : mEntries(nEntries) |
|
491 , mJNIEnv(AndroidBridge::GetJNIEnv()) |
|
492 , mHasFrameBeenPushed(false) |
|
493 { |
|
494 MOZ_ASSERT(mJNIEnv); |
|
495 Push(); |
|
496 } |
|
497 |
|
498 AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 15) |
|
499 : mEntries(nEntries) |
|
500 , mJNIEnv(aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv()) |
|
501 , mHasFrameBeenPushed(false) |
|
502 { |
|
503 MOZ_ASSERT(mJNIEnv); |
|
504 Push(); |
|
505 } |
|
506 |
|
507 ~AutoLocalJNIFrame() { |
|
508 if (mHasFrameBeenPushed) { |
|
509 Pop(); |
|
510 } |
|
511 } |
|
512 |
|
513 JNIEnv* GetEnv() { |
|
514 return mJNIEnv; |
|
515 } |
|
516 |
|
517 bool CheckForException() { |
|
518 if (mJNIEnv->ExceptionCheck()) { |
|
519 AndroidBridge::HandleUncaughtException(mJNIEnv); |
|
520 return true; |
|
521 } |
|
522 return false; |
|
523 } |
|
524 |
|
525 // Note! Calling Purge makes all previous local refs created in |
|
526 // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down |
|
527 // any local refs that you need to keep around in global refs! |
|
528 void Purge() { |
|
529 Pop(); |
|
530 Push(); |
|
531 } |
|
532 |
|
533 template <typename ReturnType = jobject> |
|
534 ReturnType Pop(ReturnType aResult = nullptr) { |
|
535 MOZ_ASSERT(mHasFrameBeenPushed); |
|
536 mHasFrameBeenPushed = false; |
|
537 return static_cast<ReturnType>( |
|
538 mJNIEnv->PopLocalFrame(static_cast<jobject>(aResult))); |
|
539 } |
|
540 |
|
541 private: |
|
542 void Push() { |
|
543 MOZ_ASSERT(!mHasFrameBeenPushed); |
|
544 // Make sure there is enough space to store a local ref to the |
|
545 // exception. I am not completely sure this is needed, but does |
|
546 // not hurt. |
|
547 if (mJNIEnv->PushLocalFrame(mEntries + 1) != 0) { |
|
548 CheckForException(); |
|
549 return; |
|
550 } |
|
551 mHasFrameBeenPushed = true; |
|
552 } |
|
553 |
|
554 const int mEntries; |
|
555 JNIEnv* const mJNIEnv; |
|
556 bool mHasFrameBeenPushed; |
|
557 }; |
|
558 |
|
559 } |
|
560 |
|
561 #define NS_ANDROIDBRIDGE_CID \ |
|
562 { 0x0FE2321D, 0xEBD9, 0x467D, \ |
|
563 { 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } } |
|
564 |
|
565 class nsAndroidBridge MOZ_FINAL : public nsIAndroidBridge |
|
566 { |
|
567 public: |
|
568 NS_DECL_ISUPPORTS |
|
569 NS_DECL_NSIANDROIDBRIDGE |
|
570 |
|
571 nsAndroidBridge(); |
|
572 |
|
573 private: |
|
574 ~nsAndroidBridge(); |
|
575 |
|
576 protected: |
|
577 }; |
|
578 |
|
579 #endif /* AndroidBridge_h__ */ |