Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/layers/CompositorChild.h"
7 #include "mozilla/layers/CompositorParent.h"
9 #include <android/log.h>
10 #include <dlfcn.h>
12 #include "mozilla/Hal.h"
13 #include "nsXULAppAPI.h"
14 #include <prthread.h>
15 #include "nsXPCOMStrings.h"
16 #include "AndroidBridge.h"
17 #include "AndroidJNIWrapper.h"
18 #include "AndroidBridgeUtilities.h"
19 #include "nsAppShell.h"
20 #include "nsOSHelperAppService.h"
21 #include "nsWindow.h"
22 #include "mozilla/Preferences.h"
23 #include "nsThreadUtils.h"
24 #include "nsIThreadManager.h"
25 #include "mozilla/dom/mobilemessage/PSms.h"
26 #include "gfxImageSurface.h"
27 #include "gfxPlatform.h"
28 #include "gfxContext.h"
29 #include "mozilla/gfx/2D.h"
30 #include "gfxUtils.h"
31 #include "nsPresContext.h"
32 #include "nsIDocShell.h"
33 #include "nsPIDOMWindow.h"
34 #include "mozilla/dom/ScreenOrientation.h"
35 #include "nsIDOMWindowUtils.h"
36 #include "nsIDOMClientRect.h"
37 #include "StrongPointer.h"
38 #include "mozilla/ClearOnShutdown.h"
39 #include "nsPrintfCString.h"
40 #include "NativeJSContainer.h"
41 #include "nsContentUtils.h"
42 #include "nsIScriptError.h"
44 using namespace mozilla;
45 using namespace mozilla::widget::android;
46 using namespace mozilla::gfx;
48 StaticRefPtr<AndroidBridge> AndroidBridge::sBridge;
49 static unsigned sJavaEnvThreadIndex = 0;
50 static jobject sGlobalContext = nullptr;
51 static void JavaThreadDetachFunc(void *arg);
53 // This is a dummy class that can be used in the template for android::sp
54 class AndroidRefable {
55 void incStrong(void* thing) { }
56 void decStrong(void* thing) { }
57 };
59 // This isn't in AndroidBridge.h because including StrongPointer.h there is gross
60 static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr;
62 jclass AndroidBridge::GetClassGlobalRef(JNIEnv* env, const char* className)
63 {
64 jobject classLocalRef = env->FindClass(className);
65 if (!classLocalRef) {
66 ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
67 className);
68 env->ExceptionDescribe();
69 MOZ_CRASH();
70 }
71 jobject classGlobalRef = env->NewGlobalRef(classLocalRef);
72 if (!classGlobalRef) {
73 env->ExceptionDescribe();
74 MOZ_CRASH();
75 }
76 // Local ref no longer necessary because we have a global ref.
77 env->DeleteLocalRef(classLocalRef);
78 classLocalRef = nullptr;
79 return static_cast<jclass>(classGlobalRef);
80 }
82 jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass,
83 const char* methodName, const char* methodType)
84 {
85 jmethodID methodID = env->GetMethodID(jClass, methodName, methodType);
86 if (!methodID) {
87 ALOG(">>> FATAL JNI ERROR! GetMethodID(methodName=\"%s\", "
88 "methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
89 methodName, methodType);
90 env->ExceptionDescribe();
91 MOZ_CRASH();
92 }
93 return methodID;
94 }
96 jmethodID AndroidBridge::GetStaticMethodID(JNIEnv* env, jclass jClass,
97 const char* methodName, const char* methodType)
98 {
99 jmethodID methodID = env->GetStaticMethodID(jClass, methodName, methodType);
100 if (!methodID) {
101 ALOG(">>> FATAL JNI ERROR! GetStaticMethodID(methodName=\"%s\", "
102 "methodType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
103 methodName, methodType);
104 env->ExceptionDescribe();
105 MOZ_CRASH();
106 }
107 return methodID;
108 }
110 jfieldID AndroidBridge::GetFieldID(JNIEnv* env, jclass jClass,
111 const char* fieldName, const char* fieldType)
112 {
113 jfieldID fieldID = env->GetFieldID(jClass, fieldName, fieldType);
114 if (!fieldID) {
115 ALOG(">>> FATAL JNI ERROR! GetFieldID(fieldName=\"%s\", "
116 "fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
117 fieldName, fieldType);
118 env->ExceptionDescribe();
119 MOZ_CRASH();
120 }
121 return fieldID;
122 }
124 jfieldID AndroidBridge::GetStaticFieldID(JNIEnv* env, jclass jClass,
125 const char* fieldName, const char* fieldType)
126 {
127 jfieldID fieldID = env->GetStaticFieldID(jClass, fieldName, fieldType);
128 if (!fieldID) {
129 ALOG(">>> FATAL JNI ERROR! GetStaticFieldID(fieldName=\"%s\", "
130 "fieldType=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
131 fieldName, fieldType);
132 env->ExceptionDescribe();
133 MOZ_CRASH();
134 }
135 return fieldID;
136 }
138 void
139 AndroidBridge::ConstructBridge(JNIEnv *jEnv)
140 {
141 /* NSS hack -- bionic doesn't handle recursive unloads correctly,
142 * because library finalizer functions are called with the dynamic
143 * linker lock still held. This results in a deadlock when trying
144 * to call dlclose() while we're already inside dlclose().
145 * Conveniently, NSS has an env var that can prevent it from unloading.
146 */
147 putenv("NSS_DISABLE_UNLOAD=1");
149 PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
151 AndroidBridge *bridge = new AndroidBridge();
152 if (!bridge->Init(jEnv)) {
153 delete bridge;
154 }
155 sBridge = bridge;
156 }
158 bool
159 AndroidBridge::Init(JNIEnv *jEnv)
160 {
161 ALOG_BRIDGE("AndroidBridge::Init");
162 jEnv->GetJavaVM(&mJavaVM);
163 if (!mJavaVM) {
164 MOZ_CRASH(); // Nothing we can do here
165 }
167 AutoLocalJNIFrame jniFrame(jEnv);
169 mJNIEnv = nullptr;
170 mThread = -1;
171 mGLControllerObj = nullptr;
172 mOpenedGraphicsLibraries = false;
173 mHasNativeBitmapAccess = false;
174 mHasNativeWindowAccess = false;
175 mHasNativeWindowFallback = false;
177 initInit();
179 #ifdef MOZ_WEBSMS_BACKEND
180 mAndroidSmsMessageClass = getClassGlobalRef("android/telephony/SmsMessage");
181 jCalculateLength = getStaticMethod("calculateLength", "(Ljava/lang/CharSequence;Z)[I");
182 #endif
184 jStringClass = getClassGlobalRef("java/lang/String");
186 if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv)) {
187 ALOG_BRIDGE("Failed to find API version");
188 }
190 jSurfaceClass = getClassGlobalRef("android/view/Surface");
191 if (mAPIVersion <= 8 /* Froyo */) {
192 jSurfacePointerField = getField("mSurface", "I");
193 } else if (mAPIVersion > 8 && mAPIVersion < 19 /* KitKat */) {
194 jSurfacePointerField = getField("mNativeSurface", "I");
195 } else {
196 // We don't know how to get this, just set it to 0
197 jSurfacePointerField = 0;
198 }
200 jclass eglClass = getClassGlobalRef("com/google/android/gles_jni/EGLSurfaceImpl");
201 if (eglClass) {
202 jEGLSurfacePointerField = getField("mEGLSurface", "I");
203 } else {
204 jEGLSurfacePointerField = 0;
205 }
207 InitAndroidJavaWrappers(jEnv);
209 // jEnv should NOT be cached here by anything -- the jEnv here
210 // is not valid for the real gecko main thread, which is set
211 // at SetMainThread time.
213 return true;
214 }
216 bool
217 AndroidBridge::SetMainThread(pthread_t thr)
218 {
219 ALOG_BRIDGE("AndroidBridge::SetMainThread");
220 if (thr) {
221 mThread = thr;
222 mJavaVM->GetEnv((void**) &mJNIEnv, JNI_VERSION_1_2);
223 return (bool) mJNIEnv;
224 }
226 mJNIEnv = nullptr;
227 mThread = -1;
228 return true;
229 }
231 // Raw JNIEnv variants.
232 jstring AndroidBridge::NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len) {
233 jstring ret = env->NewString(reinterpret_cast<const jchar*>(string), len);
234 if (env->ExceptionCheck()) {
235 ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
236 env->ExceptionDescribe();
237 env->ExceptionClear();
238 return nullptr;
239 }
240 return ret;
241 }
243 jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsAString& string) {
244 return NewJavaString(env, string.BeginReading(), string.Length());
245 }
247 jstring AndroidBridge::NewJavaString(JNIEnv* env, const char* string) {
248 return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
249 }
251 jstring AndroidBridge::NewJavaString(JNIEnv* env, const nsACString& string) {
252 return NewJavaString(env, NS_ConvertUTF8toUTF16(string));
253 }
255 // AutoLocalJNIFrame variants..
256 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char16_t* string, uint32_t len) {
257 return NewJavaString(frame->GetEnv(), string, len);
258 }
260 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsAString& string) {
261 return NewJavaString(frame, string.BeginReading(), string.Length());
262 }
264 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const char* string) {
265 return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
266 }
268 jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string) {
269 return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
270 }
272 extern "C" {
273 __attribute__ ((visibility("default")))
274 JNIEnv * GetJNIForThread()
275 {
276 JNIEnv *jEnv = static_cast<JNIEnv*>(PR_GetThreadPrivate(sJavaEnvThreadIndex));
277 if (jEnv) {
278 return jEnv;
279 }
280 JavaVM *jVm = mozilla::AndroidBridge::GetVM();
281 if (!jVm->GetEnv(reinterpret_cast<void**>(&jEnv), JNI_VERSION_1_2)) {
282 MOZ_ASSERT(jEnv);
283 return jEnv;
284 }
285 if (!jVm->AttachCurrentThread(&jEnv, nullptr)) {
286 MOZ_ASSERT(jEnv);
287 PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
288 return jEnv;
289 }
290 MOZ_CRASH();
291 return nullptr; // unreachable
292 }
293 }
295 void AutoGlobalWrappedJavaObject::Dispose() {
296 if (isNull()) {
297 return;
298 }
300 GetJNIForThread()->DeleteGlobalRef(wrapped_obj);
301 wrapped_obj = nullptr;
302 }
304 AutoGlobalWrappedJavaObject::~AutoGlobalWrappedJavaObject() {
305 Dispose();
306 }
308 static void
309 getHandlersFromStringArray(JNIEnv *aJNIEnv, jobjectArray jArr, jsize aLen,
310 nsIMutableArray *aHandlersArray,
311 nsIHandlerApp **aDefaultApp,
312 const nsAString& aAction = EmptyString(),
313 const nsACString& aMimeType = EmptyCString())
314 {
315 nsString empty = EmptyString();
316 for (jsize i = 0; i < aLen; i+=4) {
318 AutoLocalJNIFrame jniFrame(aJNIEnv, 4);
319 nsJNIString name(
320 static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i)), aJNIEnv);
321 nsJNIString isDefault(
322 static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 1)), aJNIEnv);
323 nsJNIString packageName(
324 static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 2)), aJNIEnv);
325 nsJNIString className(
326 static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 3)), aJNIEnv);
327 nsIHandlerApp* app = nsOSHelperAppService::
328 CreateAndroidHandlerApp(name, className, packageName,
329 className, aMimeType, aAction);
331 aHandlersArray->AppendElement(app, false);
332 if (aDefaultApp && isDefault.Length() > 0)
333 *aDefaultApp = app;
334 }
335 }
337 bool
338 AndroidBridge::GetHandlersForMimeType(const nsAString& aMimeType,
339 nsIMutableArray *aHandlersArray,
340 nsIHandlerApp **aDefaultApp,
341 const nsAString& aAction)
342 {
343 ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
345 JNIEnv *env = GetJNIEnv();
347 AutoLocalJNIFrame jniFrame(env, 1);
348 jobjectArray arr =
349 mozilla::widget::android::GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
350 if (!arr)
351 return false;
353 jsize len = env->GetArrayLength(arr);
355 if (!aHandlersArray)
356 return len > 0;
358 getHandlersFromStringArray(env, arr, len, aHandlersArray,
359 aDefaultApp, aAction,
360 NS_ConvertUTF16toUTF8(aMimeType));
361 return true;
362 }
364 bool
365 AndroidBridge::GetHandlersForURL(const nsAString& aURL,
366 nsIMutableArray* aHandlersArray,
367 nsIHandlerApp **aDefaultApp,
368 const nsAString& aAction)
369 {
370 ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
372 JNIEnv *env = GetJNIEnv();
374 AutoLocalJNIFrame jniFrame(env, 1);
375 jobjectArray arr = mozilla::widget::android::GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
376 if (!arr)
377 return false;
379 jsize len = env->GetArrayLength(arr);
381 if (!aHandlersArray)
382 return len > 0;
384 getHandlersFromStringArray(env, arr, len, aHandlersArray,
385 aDefaultApp, aAction);
386 return true;
387 }
389 void
390 AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
391 {
392 ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
394 JNIEnv *env = GetJNIEnv();
396 AutoLocalJNIFrame jniFrame(env, 1);
397 jstring jstrType = mozilla::widget::android::GeckoAppShell::GetMimeTypeFromExtensionsWrapper
398 (NS_ConvertUTF8toUTF16(aFileExt));
399 if (!jstrType) {
400 return;
401 }
402 nsJNIString jniStr(jstrType, env);
403 CopyUTF16toUTF8(jniStr.get(), aMimeType);
404 }
406 void
407 AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
408 {
409 ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
411 JNIEnv *env = GetJNIEnv();
413 AutoLocalJNIFrame jniFrame(env, 1);
414 jstring jstrExt = mozilla::widget::android::GeckoAppShell::GetExtensionFromMimeTypeWrapper
415 (NS_ConvertUTF8toUTF16(aMimeType));
416 if (!jstrExt) {
417 return;
418 }
419 nsJNIString jniStr(jstrExt, env);
420 CopyUTF16toUTF8(jniStr.get(), aFileExt);
421 }
423 bool
424 AndroidBridge::GetClipboardText(nsAString& aText)
425 {
426 ALOG_BRIDGE("AndroidBridge::GetClipboardText");
428 JNIEnv *env = GetJNIEnv();
430 AutoLocalJNIFrame jniFrame(env, 1);
431 jstring result = Clipboard::GetClipboardTextWrapper();
432 if (!result)
433 return false;
435 nsJNIString jniStr(result, env);
436 aText.Assign(jniStr);
437 return true;
438 }
440 void
441 AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
442 const nsAString& aAlertTitle,
443 const nsAString& aAlertText,
444 const nsAString& aAlertCookie,
445 nsIObserver *aAlertListener,
446 const nsAString& aAlertName)
447 {
448 if (nsAppShell::gAppShell && aAlertListener) {
449 // This will remove any observers already registered for this id
450 nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeAddObserver(aAlertName, aAlertListener));
451 }
453 mozilla::widget::android::GeckoAppShell::ShowAlertNotificationWrapper
454 (aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
455 }
457 int
458 AndroidBridge::GetDPI()
459 {
460 static int sDPI = 0;
461 if (sDPI)
462 return sDPI;
464 const int DEFAULT_DPI = 160;
466 sDPI = mozilla::widget::android::GeckoAppShell::GetDpiWrapper();
467 if (!sDPI) {
468 return DEFAULT_DPI;
469 }
471 return sDPI;
472 }
474 int
475 AndroidBridge::GetScreenDepth()
476 {
477 ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
479 static int sDepth = 0;
480 if (sDepth)
481 return sDepth;
483 const int DEFAULT_DEPTH = 16;
485 if (HasEnv()) {
486 sDepth = mozilla::widget::android::GeckoAppShell::GetScreenDepthWrapper();
487 }
488 if (!sDepth)
489 return DEFAULT_DEPTH;
491 return sDepth;
492 }
493 void
494 AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
495 {
496 ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
498 uint32_t len = aPattern.Length();
499 if (!len) {
500 ALOG_BRIDGE(" invalid 0-length array");
501 return;
502 }
504 JNIEnv *env = GetJNIEnv();
506 AutoLocalJNIFrame jniFrame(env, 1);
508 // It's clear if this worth special-casing, but it creates less
509 // java junk, so dodges the GC.
510 if (len == 1) {
511 jlong d = aPattern[0];
512 if (d < 0) {
513 ALOG_BRIDGE(" invalid vibration duration < 0");
514 return;
515 }
516 mozilla::widget::android::GeckoAppShell::Vibrate1(d);
517 return;
518 }
520 // First element of the array vibrate() expects is how long to wait
521 // *before* vibrating. For us, this is always 0.
523 jlongArray array = env->NewLongArray(len + 1);
524 if (!array) {
525 ALOG_BRIDGE(" failed to allocate array");
526 return;
527 }
529 jlong* elts = env->GetLongArrayElements(array, nullptr);
530 elts[0] = 0;
531 for (uint32_t i = 0; i < aPattern.Length(); ++i) {
532 jlong d = aPattern[i];
533 if (d < 0) {
534 ALOG_BRIDGE(" invalid vibration duration < 0");
535 env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
536 return;
537 }
538 elts[i + 1] = d;
539 }
540 env->ReleaseLongArrayElements(array, elts, 0);
542 mozilla::widget::android::GeckoAppShell::VibrateA(array, -1/*don't repeat*/);
543 }
545 void
546 AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
547 {
549 NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
550 if (!aColors)
551 return;
553 JNIEnv *env = GetJNIEnv();
555 AutoLocalJNIFrame jniFrame(env, 1);
557 jintArray arr = mozilla::widget::android::GeckoAppShell::GetSystemColoursWrapper();
558 if (!arr)
559 return;
561 uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
562 jint *elements = env->GetIntArrayElements(arr, 0);
564 uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
565 if (len < colorsCount)
566 colorsCount = len;
568 // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
569 nscolor *colors = (nscolor*)aColors;
571 for (uint32_t i = 0; i < colorsCount; i++) {
572 uint32_t androidColor = static_cast<uint32_t>(elements[i]);
573 uint8_t r = (androidColor & 0x00ff0000) >> 16;
574 uint8_t b = (androidColor & 0x000000ff);
575 colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
576 }
578 env->ReleaseIntArrayElements(arr, elements, 0);
579 }
581 void
582 AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
583 {
584 ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
585 NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
586 if (!aBuf)
587 return;
589 JNIEnv *env = GetJNIEnv();
591 AutoLocalJNIFrame jniFrame(env, 1);
593 jbyteArray arr = mozilla::widget::android::GeckoAppShell::GetIconForExtensionWrapper
594 (NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
596 NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
597 if (!arr)
598 return;
600 uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
601 jbyte *elements = env->GetByteArrayElements(arr, 0);
603 uint32_t bufSize = aIconSize * aIconSize * 4;
604 NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
605 if (len == bufSize)
606 memcpy(aBuf, elements, bufSize);
608 env->ReleaseByteArrayElements(arr, elements, 0);
609 }
611 void
612 AndroidBridge::SetLayerClient(JNIEnv* env, jobject jobj)
613 {
614 // if resetting is true, that means Android destroyed our GeckoApp activity
615 // and we had to recreate it, but all the Gecko-side things were not destroyed.
616 // We therefore need to link up the new java objects to Gecko, and that's what
617 // we do here.
618 bool resetting = (mLayerClient != nullptr);
620 if (resetting) {
621 // clear out the old layer client
622 delete mLayerClient;
623 mLayerClient = nullptr;
624 }
626 mLayerClient = mozilla::widget::android::GeckoLayerClient::Wrap(jobj);
628 if (resetting) {
629 // since we are re-linking the new java objects to Gecko, we need to get
630 // the viewport from the compositor (since the Java copy was thrown away)
631 // and we do that by setting the first-paint flag.
632 nsWindow::ForceIsFirstPaint();
633 }
634 }
636 void
637 AndroidBridge::RegisterCompositor(JNIEnv *env)
638 {
639 if (mGLControllerObj != nullptr && !mGLControllerObj->isNull()) {
640 // we already have this set up, no need to do it again
641 return;
642 }
644 jobject glController = LayerView::RegisterCompositorWrapper();
645 if (!glController) {
646 return;
647 }
649 mGLControllerObj = GLController::Wrap(glController);
650 }
652 EGLSurface
653 AndroidBridge::CreateEGLSurfaceForCompositor()
654 {
655 if (!jEGLSurfacePointerField) {
656 return nullptr;
657 }
658 MOZ_ASSERT(mGLControllerObj, "AndroidBridge::CreateEGLSurfaceForCompositor called with a null GL controller ref");
660 JNIEnv* env = GetJNIForThread(); // called on the compositor thread
662 AutoLocalJNIFrame jniFrame(env, 1);
663 jobject eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
664 if (!eglSurface)
665 return nullptr;
667 EGLSurface ret = reinterpret_cast<EGLSurface>(env->GetIntField(eglSurface, jEGLSurfacePointerField));
668 return ret;
669 }
671 bool
672 AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
673 {
674 ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
676 if (!jEnv) {
677 if (!HasEnv()) {
678 return false;
679 }
680 jEnv = GetJNIEnv();
681 }
683 initInit();
684 getClassGlobalRef(className);
685 jfieldID field = getStaticField(fieldName, "I");
687 if (!field) {
688 jEnv->DeleteGlobalRef(jClass);
689 return false;
690 }
692 *aInt = static_cast<int32_t>(jEnv->GetStaticIntField(jClass, field));
694 jEnv->DeleteGlobalRef(jClass);
695 return true;
696 }
698 bool
699 AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result, JNIEnv* jEnv /* = nullptr */)
700 {
701 ALOG_BRIDGE("AndroidBridge::GetStaticStringField %s", fieldName);
703 if (!jEnv) {
704 if (!HasEnv()) {
705 return false;
706 }
707 jEnv = GetJNIEnv();
708 }
710 AutoLocalJNIFrame jniFrame(jEnv, 1);
711 initInit();
712 getClassGlobalRef(className);
713 jfieldID field = getStaticField(fieldName, "Ljava/lang/String;");
715 if (!field) {
716 jEnv->DeleteGlobalRef(jClass);
717 return false;
718 }
720 jstring jstr = (jstring) jEnv->GetStaticObjectField(jClass, field);
721 jEnv->DeleteGlobalRef(jClass);
722 if (!jstr)
723 return false;
725 result.Assign(nsJNIString(jstr, jEnv));
726 return true;
727 }
729 // Available for places elsewhere in the code to link to.
730 bool
731 mozilla_AndroidBridge_SetMainThread(pthread_t thr)
732 {
733 return AndroidBridge::Bridge()->SetMainThread(thr);
734 }
736 void*
737 AndroidBridge::GetNativeSurface(JNIEnv* env, jobject surface) {
738 if (!env || !mHasNativeWindowFallback || !jSurfacePointerField)
739 return nullptr;
741 return (void*)env->GetIntField(surface, jSurfacePointerField);
742 }
744 void
745 AndroidBridge::OpenGraphicsLibraries()
746 {
747 if (!mOpenedGraphicsLibraries) {
748 // Try to dlopen libjnigraphics.so for direct bitmap access on
749 // Android 2.2+ (API level 8)
750 mOpenedGraphicsLibraries = true;
751 mHasNativeWindowAccess = false;
752 mHasNativeWindowFallback = false;
753 mHasNativeBitmapAccess = false;
755 void *handle = dlopen("libjnigraphics.so", RTLD_LAZY | RTLD_LOCAL);
756 if (handle) {
757 AndroidBitmap_getInfo = (int (*)(JNIEnv *, jobject, void *))dlsym(handle, "AndroidBitmap_getInfo");
758 AndroidBitmap_lockPixels = (int (*)(JNIEnv *, jobject, void **))dlsym(handle, "AndroidBitmap_lockPixels");
759 AndroidBitmap_unlockPixels = (int (*)(JNIEnv *, jobject))dlsym(handle, "AndroidBitmap_unlockPixels");
761 mHasNativeBitmapAccess = AndroidBitmap_getInfo && AndroidBitmap_lockPixels && AndroidBitmap_unlockPixels;
763 ALOG_BRIDGE("Successfully opened libjnigraphics.so, have native bitmap access? %d", mHasNativeBitmapAccess);
764 }
766 // Try to dlopen libandroid.so for and native window access on
767 // Android 2.3+ (API level 9)
768 handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
769 if (handle) {
770 ANativeWindow_fromSurface = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurface");
771 ANativeWindow_release = (void (*)(void*))dlsym(handle, "ANativeWindow_release");
772 ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
773 ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
774 ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
776 // This is only available in Honeycomb and ICS. It was removed in Jelly Bean
777 ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture");
779 mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost;
781 ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess);
782 }
784 // We need one symbol from here on Jelly Bean
785 handle = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_LOCAL);
786 if (handle) {
787 android_SurfaceTexture_getNativeWindow = (android::sp<AndroidRefable> (*)(JNIEnv*, jobject))dlsym(handle, "_ZN7android38android_SurfaceTexture_getNativeWindowEP7_JNIEnvP8_jobject");
788 }
790 if (mHasNativeWindowAccess)
791 return;
793 // Look up Surface functions, used for native window (surface) fallback
794 handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
795 if (handle) {
796 Surface_lock = (int (*)(void*, void*, void*, bool))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
797 Surface_unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
799 handle = dlopen("libui.so", RTLD_LAZY);
800 if (handle) {
801 Region_constructor = (void (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
802 Region_set = (void (*)(void*, void*))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
804 mHasNativeWindowFallback = Surface_lock && Surface_unlockAndPost && Region_constructor && Region_set;
805 }
806 }
807 }
808 }
810 namespace mozilla {
811 class TracerRunnable : public nsRunnable{
812 public:
813 TracerRunnable() {
814 mTracerLock = new Mutex("TracerRunnable");
815 mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable");
816 mMainThread = do_GetMainThread();
818 }
819 ~TracerRunnable() {
820 delete mTracerCondVar;
821 delete mTracerLock;
822 mTracerLock = nullptr;
823 mTracerCondVar = nullptr;
824 }
826 virtual nsresult Run() {
827 MutexAutoLock lock(*mTracerLock);
828 if (!AndroidBridge::Bridge())
829 return NS_OK;
831 mHasRun = true;
832 mTracerCondVar->Notify();
833 return NS_OK;
834 }
836 bool Fire() {
837 if (!mTracerLock || !mTracerCondVar)
838 return false;
839 MutexAutoLock lock(*mTracerLock);
840 mHasRun = false;
841 mMainThread->Dispatch(this, NS_DISPATCH_NORMAL);
842 while (!mHasRun)
843 mTracerCondVar->Wait();
844 return true;
845 }
847 void Signal() {
848 MutexAutoLock lock(*mTracerLock);
849 mHasRun = true;
850 mTracerCondVar->Notify();
851 }
852 private:
853 Mutex* mTracerLock;
854 CondVar* mTracerCondVar;
855 bool mHasRun;
856 nsCOMPtr<nsIThread> mMainThread;
858 };
859 StaticRefPtr<TracerRunnable> sTracerRunnable;
861 bool InitWidgetTracing() {
862 if (!sTracerRunnable)
863 sTracerRunnable = new TracerRunnable();
864 return true;
865 }
867 void CleanUpWidgetTracing() {
868 sTracerRunnable = nullptr;
869 }
871 bool FireAndWaitForTracerEvent() {
872 if (sTracerRunnable)
873 return sTracerRunnable->Fire();
874 return false;
875 }
877 void SignalTracerThread()
878 {
879 if (sTracerRunnable)
880 return sTracerRunnable->Signal();
881 }
883 }
884 bool
885 AndroidBridge::HasNativeBitmapAccess()
886 {
887 OpenGraphicsLibraries();
889 return mHasNativeBitmapAccess;
890 }
892 bool
893 AndroidBridge::ValidateBitmap(jobject bitmap, int width, int height)
894 {
895 // This structure is defined in Android API level 8's <android/bitmap.h>
896 // Because we can't depend on this, we get the function pointers via dlsym
897 // and define this struct ourselves.
898 struct BitmapInfo {
899 uint32_t width;
900 uint32_t height;
901 uint32_t stride;
902 uint32_t format;
903 uint32_t flags;
904 };
906 int err;
907 struct BitmapInfo info = { 0, };
909 JNIEnv *env = GetJNIEnv();
911 if ((err = AndroidBitmap_getInfo(env, bitmap, &info)) != 0) {
912 ALOG_BRIDGE("AndroidBitmap_getInfo failed! (error %d)", err);
913 return false;
914 }
916 if ((int)info.width != width || (int)info.height != height)
917 return false;
919 return true;
920 }
922 bool
923 AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps)
924 {
925 JNIEnv *env = GetJNIEnv();
927 AutoLocalJNIFrame jniFrame(env, 1);
928 jintArray arr = mozilla::widget::android::GeckoAppShell::InitCameraWrapper
929 (NS_ConvertUTF8toUTF16(contentType), (int32_t) camera, (int32_t) width, (int32_t) height);
931 if (!arr)
932 return false;
934 jint *elements = env->GetIntArrayElements(arr, 0);
936 *width = elements[1];
937 *height = elements[2];
938 *fps = elements[3];
940 bool res = elements[0] == 1;
942 env->ReleaseIntArrayElements(arr, elements, 0);
944 return res;
945 }
947 void
948 AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
949 {
950 ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
952 JNIEnv *env = GetJNIEnv();
954 AutoLocalJNIFrame jniFrame(env, 1);
956 // To prevent calling too many methods through JNI, the Java method returns
957 // an array of double even if we actually want a double and a boolean.
958 jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentBatteryInformationWrapper();
959 if (!arr || env->GetArrayLength(arr) != 3) {
960 return;
961 }
963 jdouble* info = env->GetDoubleArrayElements(arr, 0);
965 aBatteryInfo->level() = info[0];
966 aBatteryInfo->charging() = info[1] == 1.0f;
967 aBatteryInfo->remainingTime() = info[2];
969 env->ReleaseDoubleArrayElements(arr, info, 0);
970 }
972 void
973 AndroidBridge::HandleGeckoMessage(JSContext* cx, JS::HandleObject object)
974 {
975 ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
977 JNIEnv* const env = GetJNIEnv();
978 AutoLocalJNIFrame jniFrame(env, 1);
979 const jobject message =
980 mozilla::widget::CreateNativeJSContainer(env, cx, object);
981 GeckoAppShell::HandleGeckoMessageWrapper(message);
982 }
984 nsresult
985 AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
986 nsIMobileMessageCallback* aRequest)
987 {
988 #ifndef MOZ_WEBSMS_BACKEND
989 return NS_ERROR_FAILURE;
990 #else
991 ALOG_BRIDGE("AndroidBridge::GetSegmentInfoForText");
993 dom::mobilemessage::SmsSegmentInfoData data;
995 data.segments() = 0;
996 data.charsPerSegment() = 0;
997 data.charsAvailableInLastSegment() = 0;
999 JNIEnv *env = GetJNIEnv();
1001 AutoLocalJNIFrame jniFrame(env, 2);
1002 jstring jText = NewJavaString(&jniFrame, aText);
1003 jobject obj = env->CallStaticObjectMethod(mAndroidSmsMessageClass,
1004 jCalculateLength, jText, JNI_FALSE);
1005 if (jniFrame.CheckForException())
1006 return NS_ERROR_FAILURE;
1008 jintArray arr = static_cast<jintArray>(obj);
1009 if (!arr || env->GetArrayLength(arr) != 4)
1010 return NS_ERROR_FAILURE;
1012 jint* info = env->GetIntArrayElements(arr, JNI_FALSE);
1014 data.segments() = info[0]; // msgCount
1015 data.charsPerSegment() = info[2]; // codeUnitsRemaining
1016 // segmentChars = (codeUnitCount + codeUnitsRemaining) / msgCount
1017 data.charsAvailableInLastSegment() = (info[1] + info[2]) / info[0];
1019 env->ReleaseIntArrayElements(arr, info, JNI_ABORT);
1021 // TODO Bug 908598 - Should properly use |QueueSmsRequest(...)| to queue up
1022 // the nsIMobileMessageCallback just like other functions.
1023 nsCOMPtr<nsIDOMMozSmsSegmentInfo> info = new SmsSegmentInfo(data);
1024 return aRequest->NotifySegmentInfoForTextGot(info);
1025 #endif
1026 }
1028 void
1029 AndroidBridge::SendMessage(const nsAString& aNumber,
1030 const nsAString& aMessage,
1031 nsIMobileMessageCallback* aRequest)
1032 {
1033 ALOG_BRIDGE("AndroidBridge::SendMessage");
1035 uint32_t requestId;
1036 if (!QueueSmsRequest(aRequest, &requestId))
1037 return;
1039 mozilla::widget::android::GeckoAppShell::SendMessageWrapper(aNumber, aMessage, requestId);
1040 }
1042 void
1043 AndroidBridge::GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
1044 {
1045 ALOG_BRIDGE("AndroidBridge::GetMessage");
1047 uint32_t requestId;
1048 if (!QueueSmsRequest(aRequest, &requestId))
1049 return;
1051 mozilla::widget::android::GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
1052 }
1054 void
1055 AndroidBridge::DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
1056 {
1057 ALOG_BRIDGE("AndroidBridge::DeleteMessage");
1059 uint32_t requestId;
1060 if (!QueueSmsRequest(aRequest, &requestId))
1061 return;
1063 mozilla::widget::android::GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
1064 }
1066 void
1067 AndroidBridge::CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, bool aReverse,
1068 nsIMobileMessageCallback* aRequest)
1069 {
1070 ALOG_BRIDGE("AndroidBridge::CreateMessageList");
1072 JNIEnv *env = GetJNIEnv();
1074 uint32_t requestId;
1075 if (!QueueSmsRequest(aRequest, &requestId))
1076 return;
1078 AutoLocalJNIFrame jniFrame(env, 2);
1080 jobjectArray numbers =
1081 (jobjectArray)env->NewObjectArray(aFilter.numbers().Length(),
1082 jStringClass,
1083 NewJavaString(&jniFrame, EmptyString()));
1085 for (uint32_t i = 0; i < aFilter.numbers().Length(); ++i) {
1086 jstring elem = NewJavaString(&jniFrame, aFilter.numbers()[i]);
1087 env->SetObjectArrayElement(numbers, i, elem);
1088 env->DeleteLocalRef(elem);
1089 }
1091 mozilla::widget::android::GeckoAppShell::CreateMessageListWrapper(aFilter.startDate(),
1092 aFilter.endDate(), numbers, aFilter.numbers().Length(),
1093 aFilter.delivery(), aReverse, requestId);
1094 }
1096 void
1097 AndroidBridge::GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest)
1098 {
1099 ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
1101 uint32_t requestId;
1102 if (!QueueSmsRequest(aRequest, &requestId))
1103 return;
1105 mozilla::widget::android::GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
1106 }
1108 bool
1109 AndroidBridge::QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut)
1110 {
1111 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
1112 MOZ_ASSERT(aRequest && aRequestIdOut);
1114 const uint32_t length = mSmsRequests.Length();
1115 for (uint32_t i = 0; i < length; i++) {
1116 if (!(mSmsRequests)[i]) {
1117 (mSmsRequests)[i] = aRequest;
1118 *aRequestIdOut = i;
1119 return true;
1120 }
1121 }
1123 mSmsRequests.AppendElement(aRequest);
1125 // After AppendElement(), previous `length` points to the new tail element.
1126 *aRequestIdOut = length;
1127 return true;
1128 }
1130 already_AddRefed<nsIMobileMessageCallback>
1131 AndroidBridge::DequeueSmsRequest(uint32_t aRequestId)
1132 {
1133 MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
1135 MOZ_ASSERT(aRequestId < mSmsRequests.Length());
1136 if (aRequestId >= mSmsRequests.Length()) {
1137 return nullptr;
1138 }
1140 return mSmsRequests[aRequestId].forget();
1141 }
1143 void
1144 AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
1145 {
1146 ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
1148 JNIEnv *env = GetJNIEnv();
1150 AutoLocalJNIFrame jniFrame(env, 1);
1152 // To prevent calling too many methods through JNI, the Java method returns
1153 // an array of double even if we actually want an integer, a boolean, and an integer.
1155 jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentNetworkInformationWrapper();
1156 if (!arr || env->GetArrayLength(arr) != 3) {
1157 return;
1158 }
1160 jdouble* info = env->GetDoubleArrayElements(arr, 0);
1162 aNetworkInfo->type() = info[0];
1163 aNetworkInfo->isWifi() = info[1] == 1.0f;
1164 aNetworkInfo->dhcpGateway() = info[2];
1166 env->ReleaseDoubleArrayElements(arr, info, 0);
1167 }
1169 void *
1170 AndroidBridge::LockBitmap(jobject bitmap)
1171 {
1172 JNIEnv *env = GetJNIEnv();
1174 AutoLocalJNIFrame jniFrame(env, 0);
1176 int err;
1177 void *buf;
1179 if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) {
1180 ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
1181 buf = nullptr;
1182 }
1184 return buf;
1185 }
1187 void
1188 AndroidBridge::UnlockBitmap(jobject bitmap)
1189 {
1190 JNIEnv *env = GetJNIEnv();
1192 AutoLocalJNIFrame jniFrame(env, 0);
1194 int err;
1196 if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0)
1197 ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
1198 }
1201 bool
1202 AndroidBridge::HasNativeWindowAccess()
1203 {
1204 OpenGraphicsLibraries();
1206 // We have a fallback hack in place, so return true if that will work as well
1207 return mHasNativeWindowAccess || mHasNativeWindowFallback;
1208 }
1210 void*
1211 AndroidBridge::AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface)
1212 {
1213 OpenGraphicsLibraries();
1215 if (mHasNativeWindowAccess)
1216 return ANativeWindow_fromSurface(aEnv, aSurface);
1218 if (mHasNativeWindowFallback)
1219 return GetNativeSurface(aEnv, aSurface);
1221 return nullptr;
1222 }
1224 void
1225 AndroidBridge::ReleaseNativeWindow(void *window)
1226 {
1227 if (!window)
1228 return;
1230 if (mHasNativeWindowAccess)
1231 ANativeWindow_release(window);
1233 // XXX: we don't ref the pointer we get from the fallback (GetNativeSurface), so we
1234 // have nothing to do here. We should probably ref it.
1235 }
1237 void*
1238 AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
1239 {
1240 OpenGraphicsLibraries();
1242 if (mHasNativeWindowAccess && ANativeWindow_fromSurfaceTexture)
1243 return ANativeWindow_fromSurfaceTexture(aEnv, aSurfaceTexture);
1245 if (mHasNativeWindowAccess && android_SurfaceTexture_getNativeWindow) {
1246 android::sp<AndroidRefable> window = android_SurfaceTexture_getNativeWindow(aEnv, aSurfaceTexture);
1247 return window.get();
1248 }
1250 return nullptr;
1251 }
1253 void
1254 AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window)
1255 {
1256 if (!window)
1257 return;
1259 // FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it.
1260 }
1262 bool
1263 AndroidBridge::LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride)
1264 {
1265 /* Copied from native_window.h in Android NDK (platform-9) */
1266 typedef struct ANativeWindow_Buffer {
1267 // The number of pixels that are show horizontally.
1268 int32_t width;
1270 // The number of pixels that are shown vertically.
1271 int32_t height;
1273 // The number of *pixels* that a line in the buffer takes in
1274 // memory. This may be >= width.
1275 int32_t stride;
1277 // The format of the buffer. One of WINDOW_FORMAT_*
1278 int32_t format;
1280 // The actual bits.
1281 void* bits;
1283 // Do not touch.
1284 uint32_t reserved[6];
1285 } ANativeWindow_Buffer;
1287 // Very similar to the above, but the 'usage' field is included. We use this
1288 // in the fallback case when NDK support is not available
1289 struct SurfaceInfo {
1290 uint32_t w;
1291 uint32_t h;
1292 uint32_t s;
1293 uint32_t usage;
1294 uint32_t format;
1295 unsigned char* bits;
1296 uint32_t reserved[2];
1297 };
1299 int err;
1300 *bits = nullptr;
1301 *width = *height = *format = 0;
1303 if (mHasNativeWindowAccess) {
1304 ANativeWindow_Buffer buffer;
1306 if ((err = ANativeWindow_lock(window, (void*)&buffer, nullptr)) != 0) {
1307 ALOG_BRIDGE("ANativeWindow_lock failed! (error %d)", err);
1308 return false;
1309 }
1311 *bits = (unsigned char*)buffer.bits;
1312 *width = buffer.width;
1313 *height = buffer.height;
1314 *format = buffer.format;
1315 *stride = buffer.stride;
1316 } else if (mHasNativeWindowFallback) {
1317 SurfaceInfo info;
1319 if ((err = Surface_lock(window, &info, nullptr, true)) != 0) {
1320 ALOG_BRIDGE("Surface_lock failed! (error %d)", err);
1321 return false;
1322 }
1324 *bits = info.bits;
1325 *width = info.w;
1326 *height = info.h;
1327 *format = info.format;
1328 *stride = info.s;
1329 } else return false;
1331 return true;
1332 }
1334 jobject
1335 AndroidBridge::GetGlobalContextRef() {
1336 if (sGlobalContext == nullptr) {
1337 JNIEnv *env = GetJNIForThread();
1339 AutoLocalJNIFrame jniFrame(env, 4);
1341 jobject context = mozilla::widget::android::GeckoAppShell::GetContext();
1342 if (!context) {
1343 ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
1344 return 0;
1345 }
1346 jclass contextClass = env->FindClass("android/content/Context");
1347 if (!contextClass) {
1348 ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
1349 return 0;
1350 }
1351 jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
1352 "()Landroid/content/Context;");
1353 if (!mid) {
1354 ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
1355 return 0;
1356 }
1357 jobject appContext = env->CallObjectMethod(context, mid);
1358 if (!appContext) {
1359 ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
1360 return 0;
1361 }
1363 sGlobalContext = env->NewGlobalRef(appContext);
1364 MOZ_ASSERT(sGlobalContext);
1365 }
1367 return sGlobalContext;
1368 }
1370 bool
1371 AndroidBridge::UnlockWindow(void* window)
1372 {
1373 int err;
1375 if (!HasNativeWindowAccess())
1376 return false;
1378 if (mHasNativeWindowAccess && (err = ANativeWindow_unlockAndPost(window)) != 0) {
1379 ALOG_BRIDGE("ANativeWindow_unlockAndPost failed! (error %d)", err);
1380 return false;
1381 } else if (mHasNativeWindowFallback && (err = Surface_unlockAndPost(window)) != 0) {
1382 ALOG_BRIDGE("Surface_unlockAndPost failed! (error %d)", err);
1383 return false;
1384 }
1386 return true;
1387 }
1389 void
1390 AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
1391 {
1392 mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
1393 if (!client)
1394 return;
1396 client->SetFirstPaintViewport((float)aOffset.x, (float)aOffset.y, aZoom.scale,
1397 aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
1398 }
1400 void
1401 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
1402 {
1403 mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
1404 if (!client)
1405 return;
1407 client->SetPageRect(aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
1408 }
1410 void
1411 AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
1412 bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale,
1413 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
1414 {
1415 mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
1416 if (!client) {
1417 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1418 return;
1419 }
1421 jobject viewTransformJObj = client->SyncViewportInfo(aDisplayPort.x, aDisplayPort.y,
1422 aDisplayPort.width, aDisplayPort.height,
1423 aDisplayResolution.scale, aLayersUpdated);
1424 NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
1426 if (!viewTransformJObj) {
1427 return;
1428 }
1430 ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
1431 aScrollOffset = ScreenPoint(viewTransform->getx(), viewTransform->gety());
1432 aScale.scale = viewTransform->getscale();
1433 aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
1434 aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
1435 aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
1436 aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
1437 aOffset.x = viewTransform->getoffsetX();
1438 aOffset.y = viewTransform->getoffsetY();
1439 delete viewTransform;
1440 }
1442 void AndroidBridge::SyncFrameMetrics(const ScreenPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
1443 bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
1444 bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
1445 {
1446 mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
1447 if (!client) {
1448 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1449 return;
1450 }
1452 // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels
1453 LayerRect dpUnrounded = aDisplayPort * aDisplayResolution;
1454 dpUnrounded += LayerPoint::FromUnknownPoint(aScrollOffset.ToUnknownPoint());
1455 LayerIntRect dp = gfx::RoundedToInt(dpUnrounded);
1457 jobject viewTransformJObj = client->SyncFrameMetrics(aScrollOffset.x, aScrollOffset.y, aZoom,
1458 aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
1459 aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale,
1460 aIsFirstPaint);
1462 NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
1463 if (!viewTransformJObj) {
1464 return;
1465 }
1466 ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
1468 aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
1469 aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
1470 aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
1471 aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
1473 aOffset.x = viewTransform->getoffsetX();
1474 aOffset.y = viewTransform->getoffsetY();
1476 delete viewTransform;
1477 }
1479 AndroidBridge::AndroidBridge()
1480 : mLayerClient(nullptr),
1481 mNativePanZoomController(nullptr)
1482 {
1483 }
1485 AndroidBridge::~AndroidBridge()
1486 {
1487 }
1489 /* Implementation file */
1490 NS_IMPL_ISUPPORTS(nsAndroidBridge, nsIAndroidBridge)
1492 nsAndroidBridge::nsAndroidBridge()
1493 {
1494 }
1496 nsAndroidBridge::~nsAndroidBridge()
1497 {
1498 }
1500 /* void handleGeckoEvent (in AString message); */
1501 NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val,
1502 JSContext *cx)
1503 {
1504 if (val.isObject()) {
1505 JS::RootedObject object(cx, &val.toObject());
1506 AndroidBridge::Bridge()->HandleGeckoMessage(cx, object);
1507 return NS_OK;
1508 }
1510 // Now handle legacy JSON messages.
1511 if (!val.isString()) {
1512 return NS_ERROR_INVALID_ARG;
1513 }
1514 JS::RootedString jsonStr(cx, val.toString());
1516 size_t strLen = 0;
1517 const jschar* strChar = JS_GetStringCharsAndLength(cx, jsonStr, &strLen);
1518 if (!strChar) {
1519 return NS_ERROR_UNEXPECTED;
1520 }
1522 JS::RootedValue jsonVal(cx);
1523 if (!JS_ParseJSON(cx, strChar, strLen, &jsonVal) || !jsonVal.isObject()) {
1524 return NS_ERROR_INVALID_ARG;
1525 }
1527 // Spit out a warning before sending the message.
1528 nsContentUtils::ReportToConsoleNonLocalized(
1529 NS_LITERAL_STRING("Use of JSON is deprecated. "
1530 "Please pass Javascript objects directly to handleGeckoMessage."),
1531 nsIScriptError::warningFlag,
1532 NS_LITERAL_CSTRING("nsIAndroidBridge"),
1533 nullptr);
1535 JS::RootedObject object(cx, &jsonVal.toObject());
1536 AndroidBridge::Bridge()->HandleGeckoMessage(cx, object);
1537 return NS_OK;
1538 }
1540 /* nsIAndroidDisplayport getDisplayPort(in boolean aPageSizeUpdate, in boolean isBrowserContentDisplayed, in int32_t tabId, in nsIAndroidViewport metrics); */
1541 NS_IMETHODIMP nsAndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
1542 {
1543 AndroidBridge::Bridge()->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, metrics, displayPort);
1544 return NS_OK;
1545 }
1547 /* void displayedDocumentChanged(); */
1548 NS_IMETHODIMP nsAndroidBridge::ContentDocumentChanged()
1549 {
1550 AndroidBridge::Bridge()->ContentDocumentChanged();
1551 return NS_OK;
1552 }
1554 /* boolean isContentDocumentDisplayed(); */
1555 NS_IMETHODIMP nsAndroidBridge::IsContentDocumentDisplayed(bool *aRet)
1556 {
1557 *aRet = AndroidBridge::Bridge()->IsContentDocumentDisplayed();
1558 return NS_OK;
1559 }
1561 // DO NOT USE THIS unless you need to access JNI from
1562 // non-main threads. This is probably not what you want.
1563 // Questions, ask blassey or dougt.
1565 static void
1566 JavaThreadDetachFunc(void *arg)
1567 {
1568 JNIEnv *env = (JNIEnv*) arg;
1569 MOZ_ASSERT(env, "No JNIEnv on Gecko thread");
1570 if (!env) {
1571 return;
1572 }
1573 JavaVM *vm = nullptr;
1574 env->GetJavaVM(&vm);
1575 MOZ_ASSERT(vm, "No JavaVM on Gecko thread");
1576 if (!vm) {
1577 return;
1578 }
1579 vm->DetachCurrentThread();
1580 }
1582 uint32_t
1583 AndroidBridge::GetScreenOrientation()
1584 {
1585 ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
1587 int16_t orientation = mozilla::widget::android::GeckoAppShell::GetScreenOrientationWrapper();
1589 if (!orientation)
1590 return dom::eScreenOrientation_None;
1592 return static_cast<dom::ScreenOrientation>(orientation);
1593 }
1595 void
1596 AndroidBridge::ScheduleComposite()
1597 {
1598 nsWindow::ScheduleComposite();
1599 }
1601 nsresult
1602 AndroidBridge::GetProxyForURI(const nsACString & aSpec,
1603 const nsACString & aScheme,
1604 const nsACString & aHost,
1605 const int32_t aPort,
1606 nsACString & aResult)
1607 {
1608 if (!HasEnv()) {
1609 return NS_ERROR_FAILURE;
1610 }
1611 JNIEnv* env = GetJNIEnv();
1613 AutoLocalJNIFrame jniFrame(env, 1);
1614 jstring jstrRet =
1615 mozilla::widget::android::GeckoAppShell::GetProxyForURIWrapper(NS_ConvertUTF8toUTF16(aSpec),
1616 NS_ConvertUTF8toUTF16(aScheme),
1617 NS_ConvertUTF8toUTF16(aHost),
1618 aPort);
1620 if (!jstrRet)
1621 return NS_ERROR_FAILURE;
1623 nsJNIString jniStr(jstrRet, env);
1624 CopyUTF16toUTF8(jniStr, aResult);
1625 return NS_OK;
1626 }
1629 /* attribute nsIAndroidBrowserApp browserApp; */
1630 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
1631 {
1632 if (nsAppShell::gAppShell)
1633 nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
1634 return NS_OK;
1635 }
1637 NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
1638 {
1639 if (nsAppShell::gAppShell)
1640 nsAppShell::gAppShell->SetBrowserApp(aBrowserApp);
1641 return NS_OK;
1642 }
1644 void
1645 AndroidBridge::AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen) {
1646 nsWindow* win = nsWindow::TopWindow();
1647 if (!win)
1648 return;
1650 CSSRect cssRect = rect / win->GetDefaultScale();
1651 mozilla::widget::android::GeckoAppShell::AddPluginViewWrapper(view, cssRect.x, cssRect.y,
1652 cssRect.width, cssRect.height, isFullScreen);
1653 }
1655 extern "C"
1656 __attribute__ ((visibility("default")))
1657 jobject JNICALL
1658 Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
1660 bool
1661 AndroidBridge::GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult)
1662 {
1663 JNIEnv* env = GetJNIForThread();
1665 AutoLocalJNIFrame jniFrame(env, 1);
1667 jstring jstrThreadName =
1668 mozilla::widget::android::GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
1670 if (!jstrThreadName)
1671 return false;
1673 nsJNIString jniStr(jstrThreadName, env);
1674 CopyUTF16toUTF8(jniStr.get(), aResult);
1675 return true;
1676 }
1678 bool
1679 AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
1680 uint32_t aFrameId, nsCString & aResult)
1681 {
1682 JNIEnv* env = GetJNIForThread();
1684 AutoLocalJNIFrame jniFrame(env, 1);
1686 jstring jstrSampleName = mozilla::widget::android::GeckoJavaSampler::GetFrameNameJavaProfilingWrapper
1687 (aThreadId, aSampleId, aFrameId);
1689 if (!jstrSampleName)
1690 return false;
1692 nsJNIString jniStr(jstrSampleName, env);
1693 CopyUTF16toUTF8(jniStr.get(), aResult);
1694 return true;
1695 }
1697 nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer)
1698 {
1699 nsresult rv;
1700 float scale = 1.0;
1702 if (!buffer)
1703 return NS_ERROR_FAILURE;
1705 // take a screenshot, as wide as possible, proportional to the destination size
1706 nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
1707 if (!utils)
1708 return NS_ERROR_FAILURE;
1710 nsCOMPtr<nsIDOMClientRect> rect;
1711 rv = utils->GetRootBounds(getter_AddRefs(rect));
1712 NS_ENSURE_SUCCESS(rv, rv);
1713 if (!rect)
1714 return NS_ERROR_FAILURE;
1716 float left, top, width, height;
1717 rect->GetLeft(&left);
1718 rect->GetTop(&top);
1719 rect->GetWidth(&width);
1720 rect->GetHeight(&height);
1722 if (width == 0 || height == 0)
1723 return NS_ERROR_FAILURE;
1725 int32_t srcX = left;
1726 int32_t srcY = top;
1727 int32_t srcW;
1728 int32_t srcH;
1730 float aspectRatio = ((float) bufW) / bufH;
1731 if (width / aspectRatio < height) {
1732 srcW = width;
1733 srcH = width / aspectRatio;
1734 } else {
1735 srcW = height * aspectRatio;
1736 srcH = height;
1737 }
1739 JNIEnv* env = GetJNIEnv();
1741 AutoLocalJNIFrame jniFrame(env, 0);
1743 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
1744 if (!win)
1745 return NS_ERROR_FAILURE;
1746 nsRefPtr<nsPresContext> presContext;
1747 nsIDocShell* docshell = win->GetDocShell();
1748 if (docshell) {
1749 docshell->GetPresContext(getter_AddRefs(presContext));
1750 }
1751 if (!presContext)
1752 return NS_ERROR_FAILURE;
1753 nscolor bgColor = NS_RGB(255, 255, 255);
1754 nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
1755 uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
1756 nsIPresShell::RENDER_DOCUMENT_RELATIVE);
1757 nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
1758 nsPresContext::CSSPixelsToAppUnits(srcY / scale),
1759 nsPresContext::CSSPixelsToAppUnits(srcW / scale),
1760 nsPresContext::CSSPixelsToAppUnits(srcH / scale));
1762 bool is24bit = (GetScreenDepth() == 24);
1763 uint32_t stride = bufW * (is24bit ? 4 : 2);
1765 void* data = env->GetDirectBufferAddress(buffer);
1766 if (!data)
1767 return NS_ERROR_FAILURE;
1769 nsRefPtr<gfxImageSurface> surf =
1770 new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(bufW, bufH), stride,
1771 is24bit ? gfxImageFormat::RGB24 :
1772 gfxImageFormat::RGB16_565);
1773 if (surf->CairoStatus() != 0) {
1774 ALOG_BRIDGE("Error creating gfxImageSurface");
1775 return NS_ERROR_FAILURE;
1776 }
1778 nsRefPtr<gfxContext> context;
1779 if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) {
1780 RefPtr<DrawTarget> dt =
1781 gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf, IntSize(bufW, bufH));
1783 if (!dt) {
1784 ALOG_BRIDGE("Error creating DrawTarget");
1785 return NS_ERROR_FAILURE;
1786 }
1787 context = new gfxContext(dt);
1788 } else {
1789 context = new gfxContext(surf);
1790 }
1791 gfxPoint pt(0, 0);
1792 context->Translate(pt);
1793 context->Scale(scale * bufW / srcW, scale * bufH / srcH);
1794 rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
1795 if (is24bit) {
1796 gfxUtils::ConvertBGRAtoRGBA(surf);
1797 }
1798 NS_ENSURE_SUCCESS(rv, rv);
1799 return NS_OK;
1800 }
1802 void
1803 AndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
1804 {
1806 ALOG_BRIDGE("Enter: %s", __PRETTY_FUNCTION__);
1807 JNIEnv* env = GetJNIEnv();
1808 if (!mLayerClient || mLayerClient->isNull()) {
1810 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1811 return;
1812 }
1813 AutoLocalJNIFrame jniFrame(env, 0);
1815 float x, y, width, height,
1816 pageLeft, pageTop, pageRight, pageBottom,
1817 cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
1818 zoom;
1819 metrics->GetX(&x);
1820 metrics->GetY(&y);
1821 metrics->GetWidth(&width);
1822 metrics->GetHeight(&height);
1823 metrics->GetPageLeft(&pageLeft);
1824 metrics->GetPageTop(&pageTop);
1825 metrics->GetPageRight(&pageRight);
1826 metrics->GetPageBottom(&pageBottom);
1827 metrics->GetCssPageLeft(&cssPageLeft);
1828 metrics->GetCssPageTop(&cssPageTop);
1829 metrics->GetCssPageRight(&cssPageRight);
1830 metrics->GetCssPageBottom(&cssPageBottom);
1831 metrics->GetZoom(&zoom);
1833 ImmutableViewportMetrics jmetrics = ImmutableViewportMetrics(pageLeft, pageTop, pageRight, pageBottom,
1834 cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
1835 x, y, x + width, y + height,
1836 zoom);
1838 jobject jobj = mLayerClient->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics.wrappedObject());
1839 if (!jobj) {
1840 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1841 return;
1842 }
1843 DisplayPortMetrics* displayPortMetrics = DisplayPortMetrics::Wrap(jobj);
1845 AndroidRectF rect(env, displayPortMetrics->getMPosition());
1846 if (jniFrame.CheckForException()) {
1847 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1848 return;
1849 }
1851 float resolution = displayPortMetrics->getResolution();
1852 if (jniFrame.CheckForException()) {
1853 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1854 return;
1855 }
1857 *displayPort = new nsAndroidDisplayport(rect, resolution);
1858 (*displayPort)->AddRef();
1860 delete displayPortMetrics;
1861 ALOG_BRIDGE("Exit: %s", __PRETTY_FUNCTION__);
1862 }
1864 void
1865 AndroidBridge::ContentDocumentChanged()
1866 {
1867 if (!mLayerClient) {
1868 return;
1869 }
1870 mLayerClient->ContentDocumentChanged();
1871 }
1873 bool
1874 AndroidBridge::IsContentDocumentDisplayed()
1875 {
1876 if (!mLayerClient)
1877 return false;
1879 return mLayerClient->IsContentDocumentDisplayed();
1880 }
1882 bool
1883 AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ParentLayerRect& aCompositionBounds, CSSToParentLayerScale& aZoom)
1884 {
1885 mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
1886 if (!client) {
1887 ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
1888 return false;
1889 }
1891 jobject progressiveUpdateDataJObj = client->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
1892 (float)aDisplayPort.x,
1893 (float)aDisplayPort.y,
1894 (float)aDisplayPort.width,
1895 (float)aDisplayPort.height,
1896 aDisplayResolution,
1897 !aDrawingCritical);
1899 NS_ABORT_IF_FALSE(progressiveUpdateDataJObj, "No progressive update data!");
1901 ProgressiveUpdateData* progressiveUpdateData = ProgressiveUpdateData::Wrap(progressiveUpdateDataJObj);
1903 aCompositionBounds.x = progressiveUpdateData->getx();
1904 aCompositionBounds.y = progressiveUpdateData->gety();
1905 aCompositionBounds.width = progressiveUpdateData->getwidth();
1906 aCompositionBounds.height = progressiveUpdateData->getheight();
1907 aZoom.scale = progressiveUpdateData->getscale();
1909 bool ret = progressiveUpdateData->getabort();
1910 delete progressiveUpdateData;
1912 return ret;
1913 }
1915 mozilla::widget::android::NativePanZoomController*
1916 AndroidBridge::SetNativePanZoomController(jobject obj)
1917 {
1918 mozilla::widget::android::NativePanZoomController* old = mNativePanZoomController;
1919 mNativePanZoomController = mozilla::widget::android::NativePanZoomController::Wrap(obj);
1920 return old;
1921 }
1923 void
1924 AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics)
1925 {
1926 ALOG_BRIDGE("AndroidBridge::RequestContentRepaint");
1928 // FIXME implement this
1929 }
1931 void
1932 AndroidBridge::AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
1933 const uint32_t& aScrollGeneration)
1934 {
1935 // FIXME implement this
1936 }
1938 void
1939 AndroidBridge::HandleDoubleTap(const CSSPoint& aPoint,
1940 int32_t aModifiers,
1941 const mozilla::layers::ScrollableLayerGuid& aGuid)
1942 {
1943 nsCString data = nsPrintfCString("{ \"x\": %d, \"y\": %d }", aPoint.x, aPoint.y);
1944 nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeBroadcastEvent(
1945 NS_LITERAL_CSTRING("Gesture:DoubleTap"), data));
1946 }
1948 void
1949 AndroidBridge::HandleSingleTap(const CSSPoint& aPoint,
1950 int32_t aModifiers,
1951 const mozilla::layers::ScrollableLayerGuid& aGuid)
1952 {
1953 // TODO Send the modifier data to Gecko for use in mouse events.
1954 nsCString data = nsPrintfCString("{ \"x\": %d, \"y\": %d }", aPoint.x, aPoint.y);
1955 nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeBroadcastEvent(
1956 NS_LITERAL_CSTRING("Gesture:SingleTap"), data));
1957 }
1959 void
1960 AndroidBridge::HandleLongTap(const CSSPoint& aPoint,
1961 int32_t aModifiers,
1962 const mozilla::layers::ScrollableLayerGuid& aGuid)
1963 {
1964 nsCString data = nsPrintfCString("{ \"x\": %d, \"y\": %d }", aPoint.x, aPoint.y);
1965 nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeBroadcastEvent(
1966 NS_LITERAL_CSTRING("Gesture:LongPress"), data));
1967 }
1969 void
1970 AndroidBridge::HandleLongTapUp(const CSSPoint& aPoint,
1971 int32_t aModifiers,
1972 const mozilla::layers::ScrollableLayerGuid& aGuid)
1973 {
1974 }
1976 void
1977 AndroidBridge::SendAsyncScrollDOMEvent(bool aIsRoot,
1978 const CSSRect& aContentRect,
1979 const CSSSize& aScrollableSize)
1980 {
1981 // FIXME implement this
1982 }
1984 void
1985 AndroidBridge::PostDelayedTask(Task* aTask, int aDelayMs)
1986 {
1987 // add the new task into the mDelayedTaskQueue, sorted with
1988 // the earliest task first in the queue
1989 DelayedTask* newTask = new DelayedTask(aTask, aDelayMs);
1990 uint32_t i = 0;
1991 while (i < mDelayedTaskQueue.Length()) {
1992 if (newTask->IsEarlierThan(mDelayedTaskQueue[i])) {
1993 mDelayedTaskQueue.InsertElementAt(i, newTask);
1994 break;
1995 }
1996 i++;
1997 }
1998 if (i == mDelayedTaskQueue.Length()) {
1999 // this new task will run after all the existing tasks in the queue
2000 mDelayedTaskQueue.AppendElement(newTask);
2001 }
2002 if (i == 0) {
2003 // if we're inserting it at the head of the queue, notify Java because
2004 // we need to get a callback at an earlier time than the last scheduled
2005 // callback
2006 mNativePanZoomController->PostDelayedCallbackWrapper((int64_t)aDelayMs);
2007 }
2008 }
2010 int64_t
2011 AndroidBridge::RunDelayedTasks()
2012 {
2013 while (mDelayedTaskQueue.Length() > 0) {
2014 DelayedTask* nextTask = mDelayedTaskQueue[0];
2015 int64_t timeLeft = nextTask->MillisecondsToRunTime();
2016 if (timeLeft > 0) {
2017 // this task (and therefore all remaining tasks)
2018 // have not yet reached their runtime. return the
2019 // time left until we should be called again
2020 return timeLeft;
2021 }
2023 // we have a delayed task to run. extract it from
2024 // the wrapper and free the wrapper
2026 mDelayedTaskQueue.RemoveElementAt(0);
2027 Task* task = nextTask->GetTask();
2028 delete nextTask;
2030 task->Run();
2031 }
2032 return -1;
2033 }