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

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

mercurial