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 #ifndef AndroidBridge_h__
7 #define AndroidBridge_h__
9 #include <jni.h>
10 #include <android/log.h>
11 #include <cstdlib>
12 #include <pthread.h>
14 #include "nsCOMPtr.h"
15 #include "nsCOMArray.h"
17 #include "GeneratedJNIWrappers.h"
19 #include "nsIMutableArray.h"
20 #include "nsIMIMEInfo.h"
21 #include "nsColor.h"
22 #include "gfxRect.h"
24 #include "nsIAndroidBridge.h"
25 #include "nsIMobileMessageCallback.h"
27 #include "mozilla/Likely.h"
28 #include "mozilla/StaticPtr.h"
29 #include "mozilla/layers/GeckoContentController.h"
30 #include "mozilla/TimeStamp.h"
32 // Some debug #defines
33 // #define DEBUG_ANDROID_EVENTS
34 // #define DEBUG_ANDROID_WIDGET
36 class nsWindow;
37 class nsIDOMMozSmsMessage;
38 class nsIObserver;
40 /* See the comment in AndroidBridge about this function before using it */
41 extern "C" JNIEnv * GetJNIForThread();
43 extern bool mozilla_AndroidBridge_SetMainThread(pthread_t);
45 namespace base {
46 class Thread;
47 } // end namespace base
49 typedef void* EGLSurface;
51 namespace mozilla {
53 namespace hal {
54 class BatteryInformation;
55 class NetworkInformation;
56 } // namespace hal
58 namespace dom {
59 namespace mobilemessage {
60 struct SmsFilterData;
61 struct SmsSegmentInfoData;
62 } // namespace mobilemessage
63 } // namespace dom
65 namespace layers {
66 class CompositorParent;
67 } // namespace layers
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;
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 };
94 class DelayedTask {
95 public:
96 DelayedTask(Task* aTask, int aDelayMs) {
97 mTask = aTask;
98 mRunTime = TimeStamp::Now() + TimeDuration::FromMilliseconds(aDelayMs);
99 }
101 bool IsEarlierThan(DelayedTask *aOther) {
102 return mRunTime < aOther->mRunTime;
103 }
105 int64_t MillisecondsToRunTime() {
106 TimeDuration timeLeft = mRunTime - TimeStamp::Now();
107 return (int64_t)timeLeft.ToMilliseconds();
108 }
110 Task* GetTask() {
111 return mTask;
112 }
114 private:
115 Task* mTask;
116 TimeStamp mRunTime;
117 };
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 };
130 enum {
131 LAYER_CLIENT_TYPE_NONE = 0,
132 LAYER_CLIENT_TYPE_GL = 2 // AndroidGeckoGLLayerClient
133 };
135 static void ConstructBridge(JNIEnv *jEnv);
137 static AndroidBridge *Bridge() {
138 return sBridge.get();
139 }
141 static JavaVM *GetVM() {
142 MOZ_ASSERT(sBridge);
143 return sBridge->mJavaVM;
144 }
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 }
156 static bool HasEnv() {
157 return sBridge && sBridge->mJNIEnv;
158 }
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 }
170 static bool ThrowException(JNIEnv *aEnv, const char *aMessage) {
171 return ThrowException(aEnv, "java/lang/Exception", aMessage);
172 }
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 }
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);
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);
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();
203 bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, mozilla::ParentLayerRect& aCompositionBounds, mozilla::CSSToParentLayerScale& aZoom);
205 void SetLayerClient(JNIEnv* env, jobject jobj);
206 mozilla::widget::android::GeckoLayerClient* GetLayerClient() { return mLayerClient; }
208 bool GetHandlersForURL(const nsAString& aURL,
209 nsIMutableArray* handlersArray = nullptr,
210 nsIHandlerApp **aDefaultApp = nullptr,
211 const nsAString& aAction = EmptyString());
213 bool GetHandlersForMimeType(const nsAString& aMimeType,
214 nsIMutableArray* handlersArray = nullptr,
215 nsIHandlerApp **aDefaultApp = nullptr,
216 const nsAString& aAction = EmptyString());
218 void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType);
219 void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt);
221 bool GetClipboardText(nsAString& aText);
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);
230 int GetDPI();
231 int GetScreenDepth();
233 void ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions);
234 void ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType);
235 void ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback);
237 void Vibrate(const nsTArray<uint32_t>& aPattern);
239 void GetSystemColors(AndroidSystemColors *aColors);
241 void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf);
243 // Switch Java to composite with the Gecko Compositor thread
244 void RegisterCompositor(JNIEnv* env = nullptr);
245 EGLSurface CreateEGLSurfaceForCompositor();
247 bool GetStaticStringField(const char *classID, const char *field, nsAString &result, JNIEnv* env = nullptr);
249 bool GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env = nullptr);
251 // These next four functions are for native Bitmap access in Android 2.2+
252 bool HasNativeBitmapAccess();
254 bool ValidateBitmap(jobject bitmap, int width, int height);
256 void *LockBitmap(jobject bitmap);
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);
263 void UnlockBitmap(jobject bitmap);
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 };
272 bool HasNativeWindowAccess();
274 void *AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface);
275 void ReleaseNativeWindow(void *window);
277 void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface);
278 void ReleaseNativeWindowForSurfaceTexture(void *window);
280 bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride);
281 bool UnlockWindow(void *window);
283 void HandleGeckoMessage(JSContext* cx, JS::HandleObject message);
285 bool InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps);
287 void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
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);
300 void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
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);
311 void AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen);
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();
319 int GetAPIVersion() { return mAPIVersion; }
320 bool IsHoneycomb() { return mAPIVersion >= 11 && mAPIVersion <= 13; }
322 void ScheduleComposite();
324 nsresult GetProxyForURI(const nsACString & aSpec,
325 const nsACString & aScheme,
326 const nsACString & aHost,
327 const int32_t aPort,
328 nsACString & aResult);
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);
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);
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;
350 // the global JavaVM
351 JavaVM *mJavaVM;
353 // the JNIEnv for the main thread
354 JNIEnv *mJNIEnv;
355 pthread_t mThread;
357 mozilla::widget::android::GeckoLayerClient *mLayerClient;
359 // the android.telephony.SmsMessage class
360 jclass mAndroidSmsMessageClass;
362 AndroidBridge();
363 ~AndroidBridge();
365 void InitStubs(JNIEnv *jEnv);
366 bool Init(JNIEnv *jEnv);
368 bool mOpenedGraphicsLibraries;
369 void OpenGraphicsLibraries();
370 void* GetNativeSurface(JNIEnv* env, jobject surface);
372 bool mHasNativeBitmapAccess;
373 bool mHasNativeWindowAccess;
374 bool mHasNativeWindowFallback;
376 int mAPIVersion;
378 bool QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut);
380 // other things
381 jmethodID jNotifyAppShellReady;
382 jmethodID jGetOutstandingDrawEvents;
383 jmethodID jPostToJavaThread;
384 jmethodID jCreateSurface;
385 jmethodID jShowSurface;
386 jmethodID jHideSurface;
387 jmethodID jDestroySurface;
389 jmethodID jCalculateLength;
391 // For native surface stuff
392 jclass jSurfaceClass;
393 jfieldID jSurfacePointerField;
395 jclass jLayerView;
397 jfieldID jEGLSurfacePointerField;
398 mozilla::widget::android::GLController *mGLControllerObj;
400 // some convinient types to have around
401 jclass jStringClass;
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);
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);
413 int (* ANativeWindow_lock)(void *window, void *outBuffer, void *inOutDirtyBounds);
414 int (* ANativeWindow_unlockAndPost)(void *window);
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);
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;
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 };
453 class AutoJObject {
454 public:
455 AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr)
456 {
457 mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv();
458 }
460 AutoJObject(JNIEnv* aJNIEnv, jobject aObject)
461 {
462 mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv();
463 mObject = aObject;
464 }
466 ~AutoJObject() {
467 if (mObject)
468 mJNIEnv->DeleteLocalRef(mObject);
469 }
471 jobject operator=(jobject aObject)
472 {
473 if (mObject) {
474 mJNIEnv->DeleteLocalRef(mObject);
475 }
476 return mObject = aObject;
477 }
479 operator jobject() {
480 return mObject;
481 }
482 private:
483 JNIEnv* mJNIEnv;
484 jobject mObject;
485 };
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 }
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 }
507 ~AutoLocalJNIFrame() {
508 if (mHasFrameBeenPushed) {
509 Pop();
510 }
511 }
513 JNIEnv* GetEnv() {
514 return mJNIEnv;
515 }
517 bool CheckForException() {
518 if (mJNIEnv->ExceptionCheck()) {
519 AndroidBridge::HandleUncaughtException(mJNIEnv);
520 return true;
521 }
522 return false;
523 }
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 }
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 }
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 }
554 const int mEntries;
555 JNIEnv* const mJNIEnv;
556 bool mHasFrameBeenPushed;
557 };
559 }
561 #define NS_ANDROIDBRIDGE_CID \
562 { 0x0FE2321D, 0xEBD9, 0x467D, \
563 { 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } }
565 class nsAndroidBridge MOZ_FINAL : public nsIAndroidBridge
566 {
567 public:
568 NS_DECL_ISUPPORTS
569 NS_DECL_NSIANDROIDBRIDGE
571 nsAndroidBridge();
573 private:
574 ~nsAndroidBridge();
576 protected:
577 };
579 #endif /* AndroidBridge_h__ */