widget/android/AndroidBridge.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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
  1028 void
  1029 AndroidBridge::SendMessage(const nsAString& aNumber,
  1030                            const nsAString& aMessage,
  1031                            nsIMobileMessageCallback* aRequest)
  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);
  1042 void
  1043 AndroidBridge::GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
  1045     ALOG_BRIDGE("AndroidBridge::GetMessage");
  1047     uint32_t requestId;
  1048     if (!QueueSmsRequest(aRequest, &requestId))
  1049         return;
  1051     mozilla::widget::android::GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
  1054 void
  1055 AndroidBridge::DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
  1057     ALOG_BRIDGE("AndroidBridge::DeleteMessage");
  1059     uint32_t requestId;
  1060     if (!QueueSmsRequest(aRequest, &requestId))
  1061         return;
  1063     mozilla::widget::android::GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
  1066 void
  1067 AndroidBridge::CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, bool aReverse,
  1068                                  nsIMobileMessageCallback* aRequest)
  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);
  1091     mozilla::widget::android::GeckoAppShell::CreateMessageListWrapper(aFilter.startDate(),
  1092                              aFilter.endDate(), numbers, aFilter.numbers().Length(),
  1093                              aFilter.delivery(), aReverse, requestId);
  1096 void
  1097 AndroidBridge::GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest)
  1099     ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
  1101     uint32_t requestId;
  1102     if (!QueueSmsRequest(aRequest, &requestId))
  1103         return;
  1105     mozilla::widget::android::GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
  1108 bool
  1109 AndroidBridge::QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut)
  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;
  1123     mSmsRequests.AppendElement(aRequest);
  1125     // After AppendElement(), previous `length` points to the new tail element.
  1126     *aRequestIdOut = length;
  1127     return true;
  1130 already_AddRefed<nsIMobileMessageCallback>
  1131 AndroidBridge::DequeueSmsRequest(uint32_t aRequestId)
  1133     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
  1135     MOZ_ASSERT(aRequestId < mSmsRequests.Length());
  1136     if (aRequestId >= mSmsRequests.Length()) {
  1137         return nullptr;
  1140     return mSmsRequests[aRequestId].forget();
  1143 void
  1144 AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
  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;
  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);
  1169 void *
  1170 AndroidBridge::LockBitmap(jobject bitmap)
  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;
  1184     return buf;
  1187 void
  1188 AndroidBridge::UnlockBitmap(jobject bitmap)
  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);
  1201 bool
  1202 AndroidBridge::HasNativeWindowAccess()
  1204     OpenGraphicsLibraries();
  1206     // We have a fallback hack in place, so return true if that will work as well
  1207     return mHasNativeWindowAccess || mHasNativeWindowFallback;
  1210 void*
  1211 AndroidBridge::AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface)
  1213     OpenGraphicsLibraries();
  1215     if (mHasNativeWindowAccess)
  1216         return ANativeWindow_fromSurface(aEnv, aSurface);
  1218     if (mHasNativeWindowFallback)
  1219         return GetNativeSurface(aEnv, aSurface);
  1221     return nullptr;
  1224 void
  1225 AndroidBridge::ReleaseNativeWindow(void *window)
  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.
  1237 void*
  1238 AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
  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();
  1250     return nullptr;
  1253 void
  1254 AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window)
  1256     if (!window)
  1257         return;
  1259     // FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it.
  1262 bool
  1263 AndroidBridge::LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride)
  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;
  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;
  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;
  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;
  1346         jclass contextClass = env->FindClass("android/content/Context");
  1347         if (!contextClass) {
  1348             ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
  1349             return 0;
  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;
  1357         jobject appContext = env->CallObjectMethod(context, mid);
  1358         if (!appContext) {
  1359             ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
  1360             return 0;
  1363         sGlobalContext = env->NewGlobalRef(appContext);
  1364         MOZ_ASSERT(sGlobalContext);
  1367     return sGlobalContext;
  1370 bool
  1371 AndroidBridge::UnlockWindow(void* window)
  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;
  1386     return true;
  1389 void
  1390 AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
  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());
  1400 void
  1401 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
  1403     mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
  1404     if (!client)
  1405         return;
  1407     client->SetPageRect(aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
  1410 void
  1411 AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
  1412                                 bool aLayersUpdated, ScreenPoint& aScrollOffset, CSSToScreenScale& aScale,
  1413                                 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
  1415     mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
  1416     if (!client) {
  1417         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
  1418         return;
  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;
  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;
  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)
  1446     mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
  1447     if (!client) {
  1448         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
  1449         return;
  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;
  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;
  1479 AndroidBridge::AndroidBridge()
  1480   : mLayerClient(nullptr),
  1481     mNativePanZoomController(nullptr)
  1485 AndroidBridge::~AndroidBridge()
  1489 /* Implementation file */
  1490 NS_IMPL_ISUPPORTS(nsAndroidBridge, nsIAndroidBridge)
  1492 nsAndroidBridge::nsAndroidBridge()
  1496 nsAndroidBridge::~nsAndroidBridge()
  1500 /* void handleGeckoEvent (in AString message); */
  1501 NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(JS::HandleValue val,
  1502                                                   JSContext *cx)
  1504     if (val.isObject()) {
  1505         JS::RootedObject object(cx, &val.toObject());
  1506         AndroidBridge::Bridge()->HandleGeckoMessage(cx, object);
  1507         return NS_OK;
  1510     // Now handle legacy JSON messages.
  1511     if (!val.isString()) {
  1512         return NS_ERROR_INVALID_ARG;
  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;
  1522     JS::RootedValue jsonVal(cx);
  1523     if (!JS_ParseJSON(cx, strChar, strLen, &jsonVal) || !jsonVal.isObject()) {
  1524         return NS_ERROR_INVALID_ARG;
  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;
  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)
  1543     AndroidBridge::Bridge()->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, metrics, displayPort);
  1544     return NS_OK;
  1547 /* void displayedDocumentChanged(); */
  1548 NS_IMETHODIMP nsAndroidBridge::ContentDocumentChanged()
  1550     AndroidBridge::Bridge()->ContentDocumentChanged();
  1551     return NS_OK;
  1554 /* boolean isContentDocumentDisplayed(); */
  1555 NS_IMETHODIMP nsAndroidBridge::IsContentDocumentDisplayed(bool *aRet)
  1557     *aRet = AndroidBridge::Bridge()->IsContentDocumentDisplayed();
  1558     return NS_OK;
  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)
  1568     JNIEnv *env = (JNIEnv*) arg;
  1569     MOZ_ASSERT(env, "No JNIEnv on Gecko thread");
  1570     if (!env) {
  1571         return;
  1573     JavaVM *vm = nullptr;
  1574     env->GetJavaVM(&vm);
  1575     MOZ_ASSERT(vm, "No JavaVM on Gecko thread");
  1576     if (!vm) {
  1577         return;
  1579     vm->DetachCurrentThread();
  1582 uint32_t
  1583 AndroidBridge::GetScreenOrientation()
  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);
  1595 void
  1596 AndroidBridge::ScheduleComposite()
  1598     nsWindow::ScheduleComposite();
  1601 nsresult
  1602 AndroidBridge::GetProxyForURI(const nsACString & aSpec,
  1603                               const nsACString & aScheme,
  1604                               const nsACString & aHost,
  1605                               const int32_t      aPort,
  1606                               nsACString & aResult)
  1608     if (!HasEnv()) {
  1609         return NS_ERROR_FAILURE;
  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;
  1629 /* attribute nsIAndroidBrowserApp browserApp; */
  1630 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
  1632     if (nsAppShell::gAppShell)
  1633         nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
  1634     return NS_OK;
  1637 NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
  1639     if (nsAppShell::gAppShell)
  1640         nsAppShell::gAppShell->SetBrowserApp(aBrowserApp);
  1641     return NS_OK;
  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);
  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)
  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;
  1678 bool
  1679 AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
  1680                                           uint32_t aFrameId, nsCString & aResult)
  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;
  1697 nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer)
  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;
  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));
  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;
  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;
  1787         context = new gfxContext(dt);
  1788     } else {
  1789         context = new gfxContext(surf);
  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);
  1798     NS_ENSURE_SUCCESS(rv, rv);
  1799     return NS_OK;
  1802 void
  1803 AndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
  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;
  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;
  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;
  1851     float resolution = displayPortMetrics->getResolution();
  1852     if (jniFrame.CheckForException()) {
  1853         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
  1854         return;
  1857     *displayPort = new nsAndroidDisplayport(rect, resolution);
  1858     (*displayPort)->AddRef();
  1860     delete displayPortMetrics;
  1861     ALOG_BRIDGE("Exit: %s", __PRETTY_FUNCTION__);
  1864 void
  1865 AndroidBridge::ContentDocumentChanged()
  1867     if (!mLayerClient) {
  1868         return;
  1870     mLayerClient->ContentDocumentChanged();
  1873 bool
  1874 AndroidBridge::IsContentDocumentDisplayed()
  1876     if (!mLayerClient)
  1877         return false;
  1879     return mLayerClient->IsContentDocumentDisplayed();
  1882 bool
  1883 AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, ParentLayerRect& aCompositionBounds, CSSToParentLayerScale& aZoom)
  1885     mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
  1886     if (!client) {
  1887         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
  1888         return false;
  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;
  1915 mozilla::widget::android::NativePanZoomController*
  1916 AndroidBridge::SetNativePanZoomController(jobject obj)
  1918     mozilla::widget::android::NativePanZoomController* old = mNativePanZoomController;
  1919     mNativePanZoomController = mozilla::widget::android::NativePanZoomController::Wrap(obj);
  1920     return old;
  1923 void
  1924 AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics)
  1926     ALOG_BRIDGE("AndroidBridge::RequestContentRepaint");
  1928     // FIXME implement this
  1931 void
  1932 AndroidBridge::AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
  1933                                        const uint32_t& aScrollGeneration)
  1935     // FIXME implement this
  1938 void
  1939 AndroidBridge::HandleDoubleTap(const CSSPoint& aPoint,
  1940                                int32_t aModifiers,
  1941                                const mozilla::layers::ScrollableLayerGuid& aGuid)
  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));
  1948 void
  1949 AndroidBridge::HandleSingleTap(const CSSPoint& aPoint,
  1950                                int32_t aModifiers,
  1951                                const mozilla::layers::ScrollableLayerGuid& aGuid)
  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));
  1959 void
  1960 AndroidBridge::HandleLongTap(const CSSPoint& aPoint,
  1961                              int32_t aModifiers,
  1962                              const mozilla::layers::ScrollableLayerGuid& aGuid)
  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));
  1969 void
  1970 AndroidBridge::HandleLongTapUp(const CSSPoint& aPoint,
  1971                                int32_t aModifiers,
  1972                                const mozilla::layers::ScrollableLayerGuid& aGuid)
  1976 void
  1977 AndroidBridge::SendAsyncScrollDOMEvent(bool aIsRoot,
  1978                                        const CSSRect& aContentRect,
  1979                                        const CSSSize& aScrollableSize)
  1981     // FIXME implement this
  1984 void
  1985 AndroidBridge::PostDelayedTask(Task* aTask, int aDelayMs)
  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;
  1996         i++;
  1998     if (i == mDelayedTaskQueue.Length()) {
  1999         // this new task will run after all the existing tasks in the queue
  2000         mDelayedTaskQueue.AppendElement(newTask);
  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);
  2010 int64_t
  2011 AndroidBridge::RunDelayedTasks()
  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;
  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();
  2032     return -1;

mercurial