Backed out changeset 2bc4310263c4 (bug 783368) Backed out changeset a35c83a8d99d (bug 783368) Backed out changeset afb9b2a661ba (bug 783368) Backed out changeset 3926f510f9be (bug 783368) Backed out changeset 9d1fe200ff87 (bug 783368) Backed out changeset b6e4f88f5730 (bug 783368) Backed out changeset bc53f7dba7c6 (bug 783368) Backed out changeset 1948fa2fccc1 (bug 783368) Backed out changeset 9af163388fd1 (bug 783368) Backed out changeset 7a2256e1aa7c (bug 783368) Backed out changeset 4da1958a9885 (bug 783368)
2693 lines
86 KiB
C++
2693 lines
86 KiB
C++
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/Util.h"
|
|
#include "mozilla/layers/CompositorChild.h"
|
|
#include "mozilla/layers/CompositorParent.h"
|
|
|
|
#include <android/log.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include "mozilla/Hal.h"
|
|
#include "nsXULAppAPI.h"
|
|
#include <prthread.h>
|
|
#include "nsXPCOMStrings.h"
|
|
|
|
#include "AndroidBridge.h"
|
|
#include "nsAppShell.h"
|
|
#include "nsOSHelperAppService.h"
|
|
#include "nsWindow.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsIThreadManager.h"
|
|
#include "mozilla/dom/sms/PSms.h"
|
|
#include "gfxImageSurface.h"
|
|
#include "gfxContext.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "mozilla/dom/ScreenOrientation.h"
|
|
#include "nsIDOMWindowUtils.h"
|
|
#include "nsIDOMClientRect.h"
|
|
#include "StrongPointer.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
|
|
#ifdef DEBUG
|
|
#define ALOG_BRIDGE(args...) ALOG(args)
|
|
#else
|
|
#define ALOG_BRIDGE(args...)
|
|
#endif
|
|
|
|
#define IME_FULLSCREEN_PREF "widget.ime.android.landscape_fullscreen"
|
|
#define IME_FULLSCREEN_THRESHOLD_PREF "widget.ime.android.fullscreen_threshold"
|
|
|
|
using namespace mozilla;
|
|
|
|
NS_IMPL_THREADSAFE_ISUPPORTS0(nsFilePickerCallback)
|
|
|
|
AndroidBridge *AndroidBridge::sBridge = 0;
|
|
static unsigned sJavaEnvThreadIndex = 0;
|
|
static void JavaThreadDetachFunc(void *arg);
|
|
|
|
// This is a dummy class that can be used in the template for android::sp
|
|
class AndroidRefable {
|
|
void incStrong(void* thing) { }
|
|
void decStrong(void* thing) { }
|
|
};
|
|
|
|
// This isn't in AndroidBridge.h because including StrongPointer.h there is gross
|
|
static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr;
|
|
|
|
/* static */ StaticAutoPtr<nsTArray<nsCOMPtr<nsISmsRequest> > > AndroidBridge::sSmsRequests;
|
|
|
|
void
|
|
AndroidBridge::ConstructBridge(JNIEnv *jEnv,
|
|
jclass jGeckoAppShellClass)
|
|
{
|
|
/* NSS hack -- bionic doesn't handle recursive unloads correctly,
|
|
* because library finalizer functions are called with the dynamic
|
|
* linker lock still held. This results in a deadlock when trying
|
|
* to call dlclose() while we're already inside dlclose().
|
|
* Conveniently, NSS has an env var that can prevent it from unloading.
|
|
*/
|
|
putenv("NSS_DISABLE_UNLOAD=1");
|
|
|
|
PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
|
|
|
|
AndroidBridge *bridge = new AndroidBridge();
|
|
if (!bridge->Init(jEnv, jGeckoAppShellClass)) {
|
|
delete bridge;
|
|
}
|
|
sBridge = bridge;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::Init(JNIEnv *jEnv,
|
|
jclass jGeckoAppShellClass)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::Init");
|
|
jEnv->GetJavaVM(&mJavaVM);
|
|
|
|
AutoLocalJNIFrame jniFrame(jEnv);
|
|
|
|
mJNIEnv = nullptr;
|
|
mThread = nullptr;
|
|
mOpenedGraphicsLibraries = false;
|
|
mHasNativeBitmapAccess = false;
|
|
mHasNativeWindowAccess = false;
|
|
mHasNativeWindowFallback = false;
|
|
|
|
mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
|
|
|
|
jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
|
|
jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
|
jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
|
|
jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
|
|
|
|
jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
|
|
jEnableLocationHighAccuracy = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V");
|
|
jEnableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableSensor", "(I)V");
|
|
jDisableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableSensor", "(I)V");
|
|
jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
|
|
jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
|
|
jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
|
|
jGetHandlersForURL = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
|
|
jOpenUriExternal = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
|
|
jGetMimeTypeFromExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
jGetExtensionFromMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
jMoveTaskToBack = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "moveTaskToBack", "()V");
|
|
jGetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getClipboardText", "()Ljava/lang/String;");
|
|
jSetClipboardText = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setClipboardText", "(Ljava/lang/String;)V");
|
|
jShowAlertNotification = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
|
jShowFilePickerForExtensions = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
jShowFilePickerForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerForMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
jShowFilePickerAsync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showFilePickerAsync", "(Ljava/lang/String;J)V");
|
|
jUnlockProfile = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "unlockProfile", "()Z");
|
|
jKillAnyZombies = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "killAnyZombies", "()V");
|
|
jAlertsProgressListener_OnProgress = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
|
|
jAlertsProgressListener_OnCancel = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "alertsProgressListener_OnCancel", "(Ljava/lang/String;)V");
|
|
jGetDpi = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getDpi", "()I");
|
|
jSetFullScreen = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setFullScreen", "(Z)V");
|
|
jShowInputMethodPicker = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showInputMethodPicker", "()V");
|
|
jNotifyDefaultPrevented = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V");
|
|
jHideProgressDialog = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "hideProgressDialog", "()V");
|
|
jPerformHapticFeedback = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "performHapticFeedback", "(Z)V");
|
|
jVibrate1 = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "vibrate", "(J)V");
|
|
jVibrateA = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "vibrate", "([JI)V");
|
|
jCancelVibrate = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "cancelVibrate", "()V");
|
|
jSetKeepScreenOn = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setKeepScreenOn", "(Z)V");
|
|
jIsNetworkLinkUp = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkUp", "()Z");
|
|
jIsNetworkLinkKnown = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkKnown", "()Z");
|
|
jSetSelectedLocale = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setSelectedLocale", "(Ljava/lang/String;)V");
|
|
jScanMedia = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
jGetSystemColors = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getSystemColors", "()[I");
|
|
jGetIconForExtension = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B");
|
|
jCreateShortcut = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
|
jGetShowPasswordSetting = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getShowPasswordSetting", "()Z");
|
|
jInitCamera = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I");
|
|
jCloseCamera = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "closeCamera", "()V");
|
|
jIsTablet = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isTablet", "()Z");
|
|
jEnableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableBatteryNotifications", "()V");
|
|
jDisableBatteryNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableBatteryNotifications", "()V");
|
|
jGetCurrentBatteryInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
|
|
|
|
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
jCheckUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
|
|
jMarkUriVisited = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
|
|
|
|
jNumberOfMessages = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNumberOfMessagesForText", "(Ljava/lang/String;)I");
|
|
jSendMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V");
|
|
jSaveSentMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "saveSentMessage", "(Ljava/lang/String;Ljava/lang/String;J)I");
|
|
jGetMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getMessage", "(II)V");
|
|
jDeleteMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "deleteMessage", "(II)V");
|
|
jCreateMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;IIZI)V");
|
|
jGetNextMessageinList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getNextMessageInList", "(II)V");
|
|
jClearMessageList = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "clearMessageList", "(I)V");
|
|
|
|
jGetCurrentNetworkInformation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getCurrentNetworkInformation", "()[D");
|
|
jEnableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableNetworkNotifications", "()V");
|
|
jDisableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableNetworkNotifications", "()V");
|
|
|
|
jGetScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getScreenOrientation", "()S");
|
|
jEnableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableScreenOrientationNotifications", "()V");
|
|
jDisableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableScreenOrientationNotifications", "()V");
|
|
jLockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "lockScreenOrientation", "(I)V");
|
|
jUnlockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "unlockScreenOrientation", "()V");
|
|
|
|
jScreenshotHandlerClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/ScreenshotHandler"));
|
|
jNotifyScreenShot = jEnv->GetStaticMethodID(jScreenshotHandlerClass, "notifyScreenShot", "(Ljava/nio/ByteBuffer;IIIIIIII)V");
|
|
jNotifyPaintedRect = jEnv->GetStaticMethodID(jScreenshotHandlerClass, "notifyPaintedRect", "(FFFF)V");
|
|
|
|
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
|
|
jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
|
|
jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
|
|
jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
|
|
jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
|
|
jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
|
|
|
|
jStringClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("java/lang/String"));
|
|
|
|
jSurfaceClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("android/view/Surface"));
|
|
|
|
if (!GetStaticIntField("android/os/Build$VERSION", "SDK_INT", &mAPIVersion, jEnv))
|
|
ALOG_BRIDGE("Failed to find API version");
|
|
|
|
if (mAPIVersion <= 8 /* Froyo */)
|
|
jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mSurface", "I");
|
|
else /* not Froyo */
|
|
jSurfacePointerField = jEnv->GetFieldID(jSurfaceClass, "mNativeSurface", "I");
|
|
|
|
jNotifyWakeLockChanged = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
|
|
|
|
jGetGfxInfoData = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getGfxInfoData", "()Ljava/lang/String;");
|
|
jGetProxyForURI = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;");
|
|
jRegisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V");
|
|
jUnregisterSurfaceTextureFrameListener = jEnv->GetStaticMethodID(jGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
|
|
|
|
#ifdef MOZ_ANDROID_OMTC
|
|
jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()Z");
|
|
|
|
jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;IIIIZ)V");
|
|
jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V");
|
|
|
|
jLayerView = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("org/mozilla/gecko/gfx/LayerView"));
|
|
|
|
AndroidGLController::Init(jEnv);
|
|
AndroidEGLObject::Init(jEnv);
|
|
#else
|
|
jAddPluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "addPluginView", "(Landroid/view/View;DDDD)V");
|
|
jRemovePluginView = jEnv->GetStaticMethodID(jGeckoAppShellClass, "removePluginView", "(Landroid/view/View;)V");
|
|
#endif
|
|
|
|
InitAndroidJavaWrappers(jEnv);
|
|
|
|
// jEnv should NOT be cached here by anything -- the jEnv here
|
|
// is not valid for the real gecko main thread, which is set
|
|
// at SetMainThread time.
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::SetMainThread(void *thr)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SetMainThread");
|
|
if (thr) {
|
|
mThread = thr;
|
|
mJavaVM->GetEnv((void**) &mJNIEnv, JNI_VERSION_1_2);
|
|
return (bool) mJNIEnv;
|
|
}
|
|
|
|
mJNIEnv = nullptr;
|
|
mThread = nullptr;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyIME(int aType, int aState)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::NotifyIME");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
|
|
sBridge->jNotifyIME, aType, aState);
|
|
}
|
|
|
|
jstring NewJavaString(AutoLocalJNIFrame* frame, const PRUnichar* string, uint32_t len) {
|
|
jstring ret = frame->GetEnv()->NewString(string, len);
|
|
if (frame->CheckForException())
|
|
return NULL;
|
|
return ret;
|
|
}
|
|
|
|
jstring NewJavaStringUTF(AutoLocalJNIFrame* frame, const char* string) {
|
|
jstring ret = frame->GetEnv()->NewStringUTF(string);
|
|
if (frame->CheckForException())
|
|
return NULL;
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
|
|
const nsAString& aModeHint, const nsAString& aActionHint)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::NotifyIMEEnabled");
|
|
if (!sBridge)
|
|
return;
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
nsPromiseFlatString typeHint(aTypeHint);
|
|
nsPromiseFlatString modeHint(aModeHint);
|
|
nsPromiseFlatString actionHint(aActionHint);
|
|
|
|
jvalue args[5];
|
|
args[0].i = aState;
|
|
args[1].l = NewJavaString(&jniFrame, typeHint.get(), typeHint.Length());
|
|
args[2].l = env->NewString(modeHint.get(), modeHint.Length());
|
|
args[3].l = env->NewString(actionHint.get(), actionHint.Length());
|
|
args[4].z = false;
|
|
|
|
int32_t landscapeFS;
|
|
if (NS_SUCCEEDED(Preferences::GetInt(IME_FULLSCREEN_PREF, &landscapeFS))) {
|
|
if (landscapeFS == 1) {
|
|
args[4].z = true;
|
|
} else if (landscapeFS == -1){
|
|
if (NS_SUCCEEDED(
|
|
Preferences::GetInt(IME_FULLSCREEN_THRESHOLD_PREF,
|
|
&landscapeFS))) {
|
|
// the threshold is hundreths of inches, so convert the
|
|
// threshold to pixels and multiply the height by 100
|
|
if (nsWindow::GetAndroidScreenBounds().height * 100 <
|
|
landscapeFS * Bridge()->GetDPI()) {
|
|
args[4].z = true;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
|
|
sBridge->jNotifyIMEEnabled, args);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyIMEChange(const PRUnichar *aText, uint32_t aTextLen,
|
|
int aStart, int aEnd, int aNewEnd)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::NotifyIMEChange");
|
|
if (!sBridge)
|
|
return;
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jvalue args[4];
|
|
args[0].l = NewJavaString(&jniFrame, aText, aTextLen);
|
|
args[1].i = aStart;
|
|
args[2].i = aEnd;
|
|
args[3].i = aNewEnd;
|
|
env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
|
|
sBridge->jNotifyIMEChange, args);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::AcknowledgeEventSync()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::AcknowledgeEventSync");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableLocation(bool aEnable)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableLocation");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableLocationHighAccuracy(bool aEnable)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableLocationHighAccuracy");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocationHighAccuracy, aEnable);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableSensor(int aSensorType)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableSensor");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, aSensorType);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::DisableSensor(int aSensorType)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::DisableSensor");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor, aSensorType);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ScheduleRestart()
|
|
{
|
|
ALOG_BRIDGE("scheduling reboot");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyXreExit()
|
|
{
|
|
ALOG_BRIDGE("xre exiting");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
|
|
}
|
|
|
|
static void
|
|
getHandlersFromStringArray(JNIEnv *aJNIEnv, jobjectArray jArr, jsize aLen,
|
|
nsIMutableArray *aHandlersArray,
|
|
nsIHandlerApp **aDefaultApp,
|
|
const nsAString& aAction = EmptyString(),
|
|
const nsACString& aMimeType = EmptyCString())
|
|
{
|
|
nsString empty = EmptyString();
|
|
for (jsize i = 0; i < aLen; i+=4) {
|
|
nsJNIString name(
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i)), aJNIEnv);
|
|
nsJNIString isDefault(
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 1)), aJNIEnv);
|
|
nsJNIString packageName(
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 2)), aJNIEnv);
|
|
nsJNIString className(
|
|
static_cast<jstring>(aJNIEnv->GetObjectArrayElement(jArr, i + 3)), aJNIEnv);
|
|
nsIHandlerApp* app = nsOSHelperAppService::
|
|
CreateAndroidHandlerApp(name, className, packageName,
|
|
className, aMimeType, aAction);
|
|
|
|
aHandlersArray->AppendElement(app, false);
|
|
if (aDefaultApp && isDefault.Length() > 0)
|
|
*aDefaultApp = app;
|
|
}
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetHandlersForMimeType(const char *aMimeType,
|
|
nsIMutableArray *aHandlersArray,
|
|
nsIHandlerApp **aDefaultApp,
|
|
const nsAString& aAction)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
|
|
jstring jstrMimeType =
|
|
NewJavaString(&jniFrame, wMimeType.get(), wMimeType.Length());
|
|
|
|
jstring jstrAction = NewJavaString(&jniFrame, nsPromiseFlatString(aAction).get(),
|
|
aAction.Length());
|
|
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetHandlersForMimeType,
|
|
jstrMimeType, jstrAction);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
jobjectArray arr = static_cast<jobjectArray>(obj);
|
|
if (!arr)
|
|
return false;
|
|
|
|
jsize len = env->GetArrayLength(arr);
|
|
|
|
if (!aHandlersArray)
|
|
return len > 0;
|
|
|
|
getHandlersFromStringArray(env, arr, len, aHandlersArray,
|
|
aDefaultApp, aAction,
|
|
nsDependentCString(aMimeType));
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetHandlersForURL(const char *aURL,
|
|
nsIMutableArray* aHandlersArray,
|
|
nsIHandlerApp **aDefaultApp,
|
|
const nsAString& aAction)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
NS_ConvertUTF8toUTF16 wScheme(aURL);
|
|
jstring jstrScheme = NewJavaString(&jniFrame, wScheme.get(), wScheme.Length());
|
|
jstring jstrAction = NewJavaString(&jniFrame, nsPromiseFlatString(aAction).get(),
|
|
aAction.Length());
|
|
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetHandlersForURL,
|
|
jstrScheme, jstrAction);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
jobjectArray arr = static_cast<jobjectArray>(obj);
|
|
if (!arr)
|
|
return false;
|
|
|
|
jsize len = env->GetArrayLength(arr);
|
|
|
|
if (!aHandlersArray)
|
|
return len > 0;
|
|
|
|
getHandlersFromStringArray(env, arr, len, aHandlersArray,
|
|
aDefaultApp, aAction);
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::OpenUriExternal(const nsACString& aUriSpec, const nsACString& aMimeType,
|
|
const nsAString& aPackageName, const nsAString& aClassName,
|
|
const nsAString& aAction, const nsAString& aTitle)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::OpenUriExternal");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
NS_ConvertUTF8toUTF16 wUriSpec(aUriSpec);
|
|
NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
|
|
|
|
jstring jstrUri = NewJavaString(&jniFrame, wUriSpec.get(), wUriSpec.Length());
|
|
jstring jstrType = NewJavaString(&jniFrame, wMimeType.get(), wMimeType.Length());
|
|
|
|
jstring jstrPackage = NewJavaString(&jniFrame, nsPromiseFlatString(aPackageName).get(),
|
|
aPackageName.Length());
|
|
jstring jstrClass = NewJavaString(&jniFrame, nsPromiseFlatString(aClassName).get(),
|
|
aClassName.Length());
|
|
jstring jstrAction = NewJavaString(&jniFrame, nsPromiseFlatString(aAction).get(),
|
|
aAction.Length());
|
|
jstring jstrTitle = NewJavaString(&jniFrame, nsPromiseFlatString(aTitle).get(),
|
|
aTitle.Length());
|
|
|
|
bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass,
|
|
jOpenUriExternal,
|
|
jstrUri, jstrType, jstrPackage,
|
|
jstrClass, jstrAction, jstrTitle);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
NS_ConvertUTF8toUTF16 wFileExt(aFileExt);
|
|
jstring jstrExt = NewJavaString(&jniFrame, wFileExt.get(), wFileExt.Length());
|
|
jstring jstrType = static_cast<jstring>(
|
|
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetMimeTypeFromExtensions,
|
|
jstrExt));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
nsJNIString jniStr(jstrType, env);
|
|
aMimeType.Assign(NS_ConvertUTF16toUTF8(jniStr.get()));
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
|
|
jstring jstrType = NewJavaString(&jniFrame, wMimeType.get(), wMimeType.Length());
|
|
jstring jstrExt = static_cast<jstring>(
|
|
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetExtensionFromMimeType,
|
|
jstrType));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
nsJNIString jniStr(jstrExt, env);
|
|
aFileExt.Assign(NS_ConvertUTF16toUTF8(jniStr.get()));
|
|
}
|
|
|
|
void
|
|
AndroidBridge::MoveTaskToBack()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::MoveTaskToBack");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetClipboardText(nsAString& aText)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetClipboardText");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrType = static_cast<jstring>(
|
|
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetClipboardText));
|
|
if (jniFrame.CheckForException() || !jstrType)
|
|
return false;
|
|
|
|
nsJNIString jniStr(jstrType, env);
|
|
aText.Assign(jniStr);
|
|
return true;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetClipboardText(const nsAString& aText)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SetClipboardText");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstr = NewJavaString(&jniFrame, nsPromiseFlatString(aText).get(),
|
|
aText.Length());
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, jstr);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::ClipboardHasText()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::ClipboardHasText");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrType = static_cast<jstring>(
|
|
env->CallStaticObjectMethod(mGeckoAppShellClass,
|
|
jGetClipboardText));
|
|
if (jniFrame.CheckForException() || !jstrType)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EmptyClipboard()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EmptyClipboard");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, nullptr);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
|
|
const nsAString& aAlertTitle,
|
|
const nsAString& aAlertText,
|
|
const nsAString& aAlertCookie,
|
|
nsIObserver *aAlertListener,
|
|
const nsAString& aAlertName)
|
|
{
|
|
ALOG_BRIDGE("ShowAlertNotification");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
if (nsAppShell::gAppShell && aAlertListener)
|
|
nsAppShell::gAppShell->AddObserver(aAlertName, aAlertListener);
|
|
|
|
jvalue args[5];
|
|
args[0].l = NewJavaString(&jniFrame, nsPromiseFlatString(aImageUrl).get(), aImageUrl.Length());
|
|
args[1].l = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertTitle).get(), aAlertTitle.Length());
|
|
args[2].l = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
|
|
args[3].l = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertCookie).get(), aAlertCookie.Length());
|
|
args[4].l = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
|
|
env->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotification, args);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::AlertsProgressListener_OnProgress(const nsAString& aAlertName,
|
|
int64_t aProgress,
|
|
int64_t aProgressMax,
|
|
const nsAString& aAlertText)
|
|
{
|
|
ALOG_BRIDGE("AlertsProgressListener_OnProgress");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jstring jstrName = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
|
|
jstring jstrText = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnProgress,
|
|
jstrName, aProgress, aProgressMax, jstrText);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::AlertsProgressListener_OnCancel(const nsAString& aAlertName)
|
|
{
|
|
ALOG_BRIDGE("AlertsProgressListener_OnCancel");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jstring jstrName = NewJavaString(&jniFrame, nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnCancel, jstrName);
|
|
}
|
|
|
|
|
|
int
|
|
AndroidBridge::GetDPI()
|
|
{
|
|
static int sDPI = 0;
|
|
if (sDPI)
|
|
return sDPI;
|
|
|
|
ALOG_BRIDGE("AndroidBridge::GetDPI");
|
|
const int DEFAULT_DPI = 160;
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return DEFAULT_DPI;
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
sDPI = (int)env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpi);
|
|
if (jniFrame.CheckForException()) {
|
|
sDPI = 0;
|
|
return DEFAULT_DPI;
|
|
}
|
|
|
|
return sDPI;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString& aExtensions)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::ShowFilePickerForExtensions");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrFilers = NewJavaString(&jniFrame, nsPromiseFlatString(aExtensions).get(),
|
|
aExtensions.Length());
|
|
jstring jstr = static_cast<jstring>(env->CallStaticObjectMethod(
|
|
mGeckoAppShellClass,
|
|
jShowFilePickerForExtensions, jstrFilers));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
aFilePath.Assign(nsJNIString(jstr, env));
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& aMimeType)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::ShowFilePickerForMimeType");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrFilers = NewJavaString(&jniFrame, nsPromiseFlatString(aMimeType).get(),
|
|
aMimeType.Length());
|
|
jstring jstr = static_cast<jstring>(env->CallStaticObjectMethod(
|
|
mGeckoAppShellClass,
|
|
jShowFilePickerForMimeType, jstrFilers));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
aFilePath.Assign(nsJNIString(jstr, env));
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ShowFilePickerAsync(const nsAString& aMimeType, nsFilePickerCallback* callback)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jMimeType = NewJavaString(&jniFrame, nsPromiseFlatString(aMimeType).get(),
|
|
aMimeType.Length());
|
|
callback->AddRef();
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jShowFilePickerAsync, jMimeType, (jlong) callback);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetFullScreen(bool aFullScreen)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SetFullScreen");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, aFullScreen);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::HideProgressDialogOnce()
|
|
{
|
|
static bool once = false;
|
|
if (once)
|
|
return;
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
once = true;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::PerformHapticFeedback(bool aIsLongPress)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::PerformHapticFeedback");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass,
|
|
jPerformHapticFeedback, aIsLongPress);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::Vibrate");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
uint32_t len = aPattern.Length();
|
|
if (!len) {
|
|
ALOG_BRIDGE(" invalid 0-length array");
|
|
return;
|
|
}
|
|
|
|
// It's clear if this worth special-casing, but it creates less
|
|
// java junk, so dodges the GC.
|
|
if (len == 1) {
|
|
jlong d = aPattern[0];
|
|
if (d < 0) {
|
|
ALOG_BRIDGE(" invalid vibration duration < 0");
|
|
return;
|
|
}
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrate1, d);
|
|
return;
|
|
}
|
|
|
|
// First element of the array vibrate() expects is how long to wait
|
|
// *before* vibrating. For us, this is always 0.
|
|
|
|
jlongArray array = env->NewLongArray(len + 1);
|
|
if (!array) {
|
|
ALOG_BRIDGE(" failed to allocate array");
|
|
return;
|
|
}
|
|
|
|
jlong* elts = env->GetLongArrayElements(array, nullptr);
|
|
elts[0] = 0;
|
|
for (uint32_t i = 0; i < aPattern.Length(); ++i) {
|
|
jlong d = aPattern[i];
|
|
if (d < 0) {
|
|
ALOG_BRIDGE(" invalid vibration duration < 0");
|
|
env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
|
|
return;
|
|
}
|
|
elts[i + 1] = d;
|
|
}
|
|
env->ReleaseLongArrayElements(array, elts, 0);
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrateA,
|
|
array, -1/*don't repeat*/);
|
|
// GC owns |array| now?
|
|
}
|
|
|
|
void
|
|
AndroidBridge::CancelVibrate()
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::IsNetworkLinkUp()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::IsNetworkLinkUp");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
bool ret = !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::IsNetworkLinkKnown()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::IsNetworkLinkKnown");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
bool ret = !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetSelectedLocale(const nsAString& aLocale)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SetSelectedLocale");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jLocale = NewJavaString(&jniFrame, PromiseFlatString(aLocale).get(), aLocale.Length());
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jSetSelectedLocale, jLocale);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetSystemColors");
|
|
|
|
NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
|
|
if (!aColors)
|
|
return;
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColors);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
jintArray arr = static_cast<jintArray>(obj);
|
|
if (!arr)
|
|
return;
|
|
|
|
uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
|
|
jint *elements = env->GetIntArrayElements(arr, 0);
|
|
|
|
uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
|
|
if (len < colorsCount)
|
|
colorsCount = len;
|
|
|
|
// Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
|
|
nscolor *colors = (nscolor*)aColors;
|
|
|
|
for (uint32_t i = 0; i < colorsCount; i++) {
|
|
uint32_t androidColor = static_cast<uint32_t>(elements[i]);
|
|
uint8_t r = (androidColor & 0x00ff0000) >> 16;
|
|
uint8_t b = (androidColor & 0x000000ff);
|
|
colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
|
|
}
|
|
|
|
env->ReleaseIntArrayElements(arr, elements, 0);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
|
|
NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
|
|
if (!aBuf)
|
|
return;
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
nsString fileExt;
|
|
CopyUTF8toUTF16(aFileExt, fileExt);
|
|
jstring jstrFileExt = NewJavaString(&jniFrame, nsPromiseFlatString(fileExt).get(), fileExt.Length());
|
|
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtension, jstrFileExt, aIconSize);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
jbyteArray arr = static_cast<jbyteArray>(obj);
|
|
NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
|
|
if (!arr)
|
|
return;
|
|
|
|
uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
|
|
jbyte *elements = env->GetByteArrayElements(arr, 0);
|
|
|
|
uint32_t bufSize = aIconSize * aIconSize * 4;
|
|
NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
|
|
if (len == bufSize)
|
|
memcpy(aBuf, elements, bufSize);
|
|
|
|
env->ReleaseByteArrayElements(arr, elements, 0);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetShowPasswordSetting()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetShowPasswordSetting");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetSurfaceView(jobject obj)
|
|
{
|
|
mSurfaceView.Init(obj);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetLayerClient(JNIEnv* env, jobject jobj)
|
|
{
|
|
// if resetting is true, that means Android destroyed our GeckoApp activity
|
|
// and we had to recreate it, but all the Gecko-side things were not destroyed.
|
|
// We therefore need to link up the new java objects to Gecko, and that's what
|
|
// we do here.
|
|
bool resetting = (mLayerClient != NULL);
|
|
|
|
if (resetting) {
|
|
// clear out the old layer client
|
|
env->DeleteGlobalRef(mLayerClient->wrappedObject());
|
|
delete mLayerClient;
|
|
mLayerClient = NULL;
|
|
}
|
|
|
|
AndroidGeckoLayerClient *client = new AndroidGeckoLayerClient();
|
|
client->Init(env->NewGlobalRef(jobj));
|
|
mLayerClient = client;
|
|
|
|
if (resetting) {
|
|
RegisterCompositor(env, true);
|
|
}
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ShowInputMethodPicker()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::ShowInputMethodPicker");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker);
|
|
}
|
|
|
|
void *
|
|
AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView &sview)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::CallEglCreateWindowSurface");
|
|
|
|
JNIEnv *env = GetJNIForThread(); // called on the compositor thread
|
|
if (!env)
|
|
return NULL;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
/*
|
|
* This is basically:
|
|
*
|
|
* s = EGLContext.getEGL().eglCreateWindowSurface(new EGLDisplayImpl(dpy),
|
|
* new EGLConfigImpl(config),
|
|
* view.getHolder(), null);
|
|
* return s.mEGLSurface;
|
|
*
|
|
* We can't do it from java, because the EGLConfigImpl constructor is private.
|
|
*/
|
|
|
|
jobject surfaceHolder = sview.GetSurfaceHolder(&jniFrame);
|
|
if (!surfaceHolder)
|
|
return nullptr;
|
|
|
|
// grab some fields and methods we'll need
|
|
jmethodID constructConfig = env->GetMethodID(jEGLConfigImplClass, "<init>", "(I)V");
|
|
jmethodID constructDisplay = env->GetMethodID(jEGLDisplayImplClass, "<init>", "(I)V");
|
|
|
|
jmethodID getEgl = env->GetStaticMethodID(jEGLContextClass, "getEGL", "()Ljavax/microedition/khronos/egl/EGL;");
|
|
jmethodID createWindowSurface = env->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;");
|
|
|
|
jobject egl = env->CallStaticObjectMethod(jEGLContextClass, getEgl);
|
|
if (jniFrame.CheckForException())
|
|
return nullptr;
|
|
|
|
jobject jdpy = env->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy);
|
|
jobject jconf = env->NewObject(jEGLConfigImplClass, constructConfig, (int) config);
|
|
|
|
// make the call
|
|
jobject surf = env->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL);
|
|
if (jniFrame.CheckForException() || !surf)
|
|
return nullptr;
|
|
|
|
jfieldID sfield = env->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I");
|
|
|
|
jint realSurface = env->GetIntField(surf, sfield);
|
|
|
|
return (void*) realSurface;
|
|
}
|
|
|
|
static AndroidGLController sController;
|
|
|
|
void
|
|
AndroidBridge::RegisterCompositor(JNIEnv *env, bool resetting)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::RegisterCompositor");
|
|
if (!env)
|
|
env = GetJNIForThread(); // called on the compositor thread
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jmethodID registerCompositor = env->GetStaticMethodID(jLayerView, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;");
|
|
|
|
jobject glController = env->CallStaticObjectMethod(jLayerView, registerCompositor);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
if (resetting) {
|
|
sController.Reacquire(env, glController);
|
|
} else {
|
|
sController.Acquire(env, glController);
|
|
sController.SetGLVersion(2);
|
|
}
|
|
}
|
|
|
|
EGLSurface
|
|
AndroidBridge::ProvideEGLSurface()
|
|
{
|
|
sController.WaitForValidSurface();
|
|
return sController.ProvideEGLSurface();
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* env /* = nullptr */)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
|
|
|
|
if (!env) {
|
|
env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
}
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jclass cls = env->FindClass(className);
|
|
if (!cls)
|
|
return false;
|
|
|
|
jfieldID field = env->GetStaticFieldID(cls, fieldName, "I");
|
|
if (!field)
|
|
return false;
|
|
|
|
*aInt = static_cast<int32_t>(env->GetStaticIntField(cls, field));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result, JNIEnv* env /* = nullptr */)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetStaticStringField %s", fieldName);
|
|
|
|
if (!env) {
|
|
env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
}
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jclass cls = env->FindClass(className);
|
|
if (!cls)
|
|
return false;
|
|
|
|
jfieldID field = env->GetStaticFieldID(cls, fieldName, "Ljava/lang/String;");
|
|
if (!field)
|
|
return false;
|
|
|
|
jstring jstr = (jstring) env->GetStaticObjectField(cls, field);
|
|
if (!jstr)
|
|
return false;
|
|
|
|
result.Assign(nsJNIString(jstr, env));
|
|
return true;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetKeepScreenOn(bool on)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SetKeepScreenOn");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
|
|
sBridge->jSetKeepScreenOn, on);
|
|
}
|
|
|
|
// Available for places elsewhere in the code to link to.
|
|
bool
|
|
mozilla_AndroidBridge_SetMainThread(void *thr)
|
|
{
|
|
return AndroidBridge::Bridge()->SetMainThread(thr);
|
|
}
|
|
|
|
jclass GetGeckoAppShellClass()
|
|
{
|
|
return mozilla::AndroidBridge::GetGeckoAppShellClass();
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ScanMedia(const nsAString& aFile, const nsACString& aMimeType)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrFile = NewJavaString(&jniFrame, nsPromiseFlatString(aFile).get(), aFile.Length());
|
|
|
|
nsString mimeType2;
|
|
CopyUTF8toUTF16(aMimeType, mimeType2);
|
|
jstring jstrMimeTypes = NewJavaString(&jniFrame, nsPromiseFlatString(mimeType2).get(), mimeType2.Length());
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jScanMedia, jstrFile, jstrMimeTypes);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, const nsAString& aIconData, const nsAString& aIntent)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrTitle = NewJavaString(&jniFrame, nsPromiseFlatString(aTitle).get(), aTitle.Length());
|
|
jstring jstrURI = NewJavaString(&jniFrame, nsPromiseFlatString(aURI).get(), aURI.Length());
|
|
jstring jstrIconData = NewJavaString(&jniFrame, nsPromiseFlatString(aIconData).get(), aIconData.Length());
|
|
jstring jstrIntent = NewJavaString(&jniFrame, nsPromiseFlatString(aIntent).get(), aIntent.Length());
|
|
|
|
if (!jstrURI || !jstrTitle || !jstrIconData)
|
|
return;
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jCreateShortcut, jstrTitle, jstrURI, jstrIconData, jstrIntent);
|
|
}
|
|
|
|
void*
|
|
AndroidBridge::GetNativeSurface(JNIEnv* env, jobject surface) {
|
|
if (!env || !mHasNativeWindowFallback)
|
|
return nullptr;
|
|
|
|
return (void*)env->GetIntField(surface, jSurfacePointerField);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::OpenGraphicsLibraries()
|
|
{
|
|
if (!mOpenedGraphicsLibraries) {
|
|
// Try to dlopen libjnigraphics.so for direct bitmap access on
|
|
// Android 2.2+ (API level 8)
|
|
mOpenedGraphicsLibraries = true;
|
|
mHasNativeWindowAccess = false;
|
|
mHasNativeWindowFallback = false;
|
|
mHasNativeBitmapAccess = false;
|
|
|
|
void *handle = dlopen("libjnigraphics.so", RTLD_LAZY | RTLD_LOCAL);
|
|
if (handle) {
|
|
AndroidBitmap_getInfo = (int (*)(JNIEnv *, jobject, void *))dlsym(handle, "AndroidBitmap_getInfo");
|
|
AndroidBitmap_lockPixels = (int (*)(JNIEnv *, jobject, void **))dlsym(handle, "AndroidBitmap_lockPixels");
|
|
AndroidBitmap_unlockPixels = (int (*)(JNIEnv *, jobject))dlsym(handle, "AndroidBitmap_unlockPixels");
|
|
|
|
mHasNativeBitmapAccess = AndroidBitmap_getInfo && AndroidBitmap_lockPixels && AndroidBitmap_unlockPixels;
|
|
|
|
ALOG_BRIDGE("Successfully opened libjnigraphics.so, have native bitmap access? %d", mHasNativeBitmapAccess);
|
|
}
|
|
|
|
// Try to dlopen libandroid.so for and native window access on
|
|
// Android 2.3+ (API level 9)
|
|
handle = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL);
|
|
if (handle) {
|
|
ANativeWindow_fromSurface = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurface");
|
|
ANativeWindow_release = (void (*)(void*))dlsym(handle, "ANativeWindow_release");
|
|
ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
|
|
ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
|
|
ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
|
|
|
|
// This is only available in Honeycomb and ICS. It was removed in Jelly Bean
|
|
ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture");
|
|
|
|
mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost;
|
|
|
|
ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess);
|
|
}
|
|
|
|
// We need one symbol from here on Jelly Bean
|
|
handle = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_LOCAL);
|
|
if (handle) {
|
|
android_SurfaceTexture_getNativeWindow = (android::sp<AndroidRefable> (*)(JNIEnv*, jobject))dlsym(handle, "_ZN7android38android_SurfaceTexture_getNativeWindowEP7_JNIEnvP8_jobject");
|
|
}
|
|
|
|
if (mHasNativeWindowAccess)
|
|
return;
|
|
|
|
// Look up Surface functions, used for native window (surface) fallback
|
|
handle = dlopen("libsurfaceflinger_client.so", RTLD_LAZY);
|
|
if (handle) {
|
|
Surface_lock = (int (*)(void*, void*, void*, bool))dlsym(handle, "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEPNS_6RegionEb");
|
|
Surface_unlockAndPost = (int (*)(void*))dlsym(handle, "_ZN7android7Surface13unlockAndPostEv");
|
|
|
|
handle = dlopen("libui.so", RTLD_LAZY);
|
|
if (handle) {
|
|
Region_constructor = (void (*)(void*))dlsym(handle, "_ZN7android6RegionC1Ev");
|
|
Region_set = (void (*)(void*, void*))dlsym(handle, "_ZN7android6Region3setERKNS_4RectE");
|
|
|
|
mHasNativeWindowFallback = Surface_lock && Surface_unlockAndPost && Region_constructor && Region_set;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace mozilla {
|
|
class TracerRunnable : public nsRunnable{
|
|
public:
|
|
TracerRunnable() {
|
|
mTracerLock = new Mutex("TracerRunnable");
|
|
mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable");
|
|
mMainThread = do_GetMainThread();
|
|
|
|
}
|
|
~TracerRunnable() {
|
|
delete mTracerCondVar;
|
|
delete mTracerLock;
|
|
mTracerLock = nullptr;
|
|
mTracerCondVar = nullptr;
|
|
}
|
|
|
|
virtual nsresult Run() {
|
|
MutexAutoLock lock(*mTracerLock);
|
|
if (!AndroidBridge::Bridge())
|
|
return NS_OK;
|
|
|
|
mHasRun = true;
|
|
mTracerCondVar->Notify();
|
|
return NS_OK;
|
|
}
|
|
|
|
bool Fire() {
|
|
if (!mTracerLock || !mTracerCondVar)
|
|
return false;
|
|
MutexAutoLock lock(*mTracerLock);
|
|
mHasRun = false;
|
|
mMainThread->Dispatch(this, NS_DISPATCH_NORMAL);
|
|
while (!mHasRun)
|
|
mTracerCondVar->Wait();
|
|
return true;
|
|
}
|
|
|
|
void Signal() {
|
|
MutexAutoLock lock(*mTracerLock);
|
|
mHasRun = true;
|
|
mTracerCondVar->Notify();
|
|
}
|
|
private:
|
|
Mutex* mTracerLock;
|
|
CondVar* mTracerCondVar;
|
|
bool mHasRun;
|
|
nsCOMPtr<nsIThread> mMainThread;
|
|
|
|
};
|
|
nsCOMPtr<TracerRunnable> sTracerRunnable;
|
|
|
|
bool InitWidgetTracing() {
|
|
if (!sTracerRunnable)
|
|
sTracerRunnable = new TracerRunnable();
|
|
return true;
|
|
}
|
|
|
|
void CleanUpWidgetTracing() {
|
|
sTracerRunnable = nullptr;
|
|
}
|
|
|
|
bool FireAndWaitForTracerEvent() {
|
|
if (sTracerRunnable)
|
|
return sTracerRunnable->Fire();
|
|
return false;
|
|
}
|
|
|
|
void SignalTracerThread()
|
|
{
|
|
if (sTracerRunnable)
|
|
return sTracerRunnable->Signal();
|
|
}
|
|
|
|
}
|
|
bool
|
|
AndroidBridge::HasNativeBitmapAccess()
|
|
{
|
|
OpenGraphicsLibraries();
|
|
|
|
return mHasNativeBitmapAccess;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::ValidateBitmap(jobject bitmap, int width, int height)
|
|
{
|
|
// This structure is defined in Android API level 8's <android/bitmap.h>
|
|
// Because we can't depend on this, we get the function pointers via dlsym
|
|
// and define this struct ourselves.
|
|
struct BitmapInfo {
|
|
uint32_t width;
|
|
uint32_t height;
|
|
uint32_t stride;
|
|
uint32_t format;
|
|
uint32_t flags;
|
|
};
|
|
|
|
int err;
|
|
struct BitmapInfo info = { 0, };
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
if ((err = AndroidBitmap_getInfo(env, bitmap, &info)) != 0) {
|
|
ALOG_BRIDGE("AndroidBitmap_getInfo failed! (error %d)", err);
|
|
return false;
|
|
}
|
|
|
|
if ((int)info.width != width || (int)info.height != height)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
NS_ConvertASCIItoUTF16 s(contentType);
|
|
jstring jstrContentType = NewJavaString(&jniFrame, s.get(), NS_strlen(s.get()));
|
|
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jInitCamera, jstrContentType, camera, *width, *height);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
jintArray arr = static_cast<jintArray>(obj);
|
|
if (!arr)
|
|
return false;
|
|
|
|
jint *elements = env->GetIntArrayElements(arr, 0);
|
|
|
|
*width = elements[1];
|
|
*height = elements[2];
|
|
*fps = elements[3];
|
|
|
|
bool res = elements[0] == 1;
|
|
|
|
env->ReleaseIntArrayElements(arr, elements, 0);
|
|
|
|
return res;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::CloseCamera()
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableBatteryNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableBatteryObserver");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::DisableBatteryNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::DisableBatteryNotifications");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
// To prevent calling too many methods through JNI, the Java method returns
|
|
// an array of double even if we actually want a double and a boolean.
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformation);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
jdoubleArray arr = static_cast<jdoubleArray>(obj);
|
|
if (!arr || env->GetArrayLength(arr) != 3) {
|
|
return;
|
|
}
|
|
|
|
jdouble* info = env->GetDoubleArrayElements(arr, 0);
|
|
|
|
aBatteryInfo->level() = info[0];
|
|
aBatteryInfo->charging() = info[1] == 1.0f;
|
|
aBatteryInfo->remainingTime() = info[2];
|
|
|
|
env->ReleaseDoubleArrayElements(arr, info, 0);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::HandleGeckoMessage(const nsAString &aMessage, nsAString &aRet)
|
|
{
|
|
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jMessage = NewJavaString(&jniFrame, nsPromiseFlatString(aMessage).get(), aMessage.Length());
|
|
jstring returnMessage = static_cast<jstring>(env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
nsJNIString jniStr(returnMessage, env);
|
|
aRet.Assign(jniStr);
|
|
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::CheckURIVisited(const nsAString& aURI)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 1);
|
|
jstring jstrURI = NewJavaString(&jniFrame, nsPromiseFlatString(aURI).get(), aURI.Length());
|
|
// If creating the string fails, just bail
|
|
if (jstrURI)
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::MarkURIVisited(const nsAString& aURI)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrURI = NewJavaString(&jniFrame, nsPromiseFlatString(aURI).get(), aURI.Length());
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI);
|
|
}
|
|
|
|
uint16_t
|
|
AndroidBridge::GetNumberOfMessagesForText(const nsAString& aText)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetNumberOfMessagesForText");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return 0;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jText = NewJavaString(&jniFrame, PromiseFlatString(aText).get(), aText.Length());
|
|
uint16_t ret = env->CallStaticIntMethod(mGeckoAppShellClass, jNumberOfMessages, jText);
|
|
if (jniFrame.CheckForException())
|
|
return 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SendMessage(const nsAString& aNumber, const nsAString& aMessage, nsISmsRequest* aRequest)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SendMessage");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
int32_t requestId = QueueSmsRequest(aRequest);
|
|
NS_ENSURE_TRUE_VOID(requestId >= 0);
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jNumber = NewJavaString(&jniFrame, PromiseFlatString(aNumber).get(), aNumber.Length());
|
|
jstring jMessage = NewJavaString(&jniFrame, PromiseFlatString(aMessage).get(), aMessage.Length());
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jSendMessage, jNumber, jMessage, requestId);
|
|
}
|
|
|
|
int32_t
|
|
AndroidBridge::SaveSentMessage(const nsAString& aRecipient,
|
|
const nsAString& aBody, uint64_t aDate)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::SaveSentMessage");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return 0;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jRecipient = NewJavaString(&jniFrame, PromiseFlatString(aRecipient).get(), aRecipient.Length());
|
|
jstring jBody = NewJavaString(&jniFrame, PromiseFlatString(aBody).get(), aBody.Length());
|
|
int32_t ret = env->CallStaticIntMethod(mGeckoAppShellClass, jSaveSentMessage, jRecipient, jBody, aDate);
|
|
if (jniFrame.CheckForException())
|
|
return 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetMessage(int32_t aMessageId, nsISmsRequest* aRequest)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetMessage");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
int32_t requestId = QueueSmsRequest(aRequest);
|
|
NS_ENSURE_TRUE_VOID(requestId >= 0);
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessage, aMessageId, requestId);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::DeleteMessage(int32_t aMessageId, nsISmsRequest* aRequest)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::DeleteMessage");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
int32_t requestId = QueueSmsRequest(aRequest);
|
|
NS_ENSURE_TRUE_VOID(requestId >= 0);
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessage, aMessageId, requestId);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::CreateMessageList(const dom::sms::SmsFilterData& aFilter, bool aReverse,
|
|
nsISmsRequest* aRequest)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::CreateMessageList");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
int32_t requestId = QueueSmsRequest(aRequest);
|
|
NS_ENSURE_TRUE_VOID(requestId >= 0);
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jobjectArray numbers =
|
|
(jobjectArray)env->NewObjectArray(aFilter.numbers().Length(),
|
|
jStringClass,
|
|
NewJavaStringUTF(&jniFrame, ""));
|
|
|
|
for (uint32_t i = 0; i < aFilter.numbers().Length(); ++i) {
|
|
env->SetObjectArrayElement(numbers, i,
|
|
NewJavaStringUTF(&jniFrame, NS_ConvertUTF16toUTF8(aFilter.numbers()[i]).get()));
|
|
}
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jCreateMessageList,
|
|
aFilter.startDate(), aFilter.endDate(),
|
|
numbers, aFilter.numbers().Length(),
|
|
aFilter.delivery(), aReverse, requestId);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetNextMessageInList(int32_t aListId, nsISmsRequest* aRequest)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
int32_t requestId = QueueSmsRequest(aRequest);
|
|
NS_ENSURE_TRUE_VOID(requestId >= 0);
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageinList, aListId, requestId);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ClearMessageList(int32_t aListId)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::ClearMessageList");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, aListId);
|
|
}
|
|
|
|
int32_t
|
|
AndroidBridge::QueueSmsRequest(nsISmsRequest* aRequest)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
// XXX: This method will always fail on Android because we do not
|
|
// init sSmsRequests. See bug 775997 and Bug 809459.
|
|
|
|
if (!sSmsRequests) {
|
|
// Probably shutting down.
|
|
return -1;
|
|
}
|
|
|
|
uint32_t length = sSmsRequests->Length();
|
|
for (int32_t i = 0; i < length; i++) {
|
|
if (!(*sSmsRequests)[i]) {
|
|
(*sSmsRequests)[i] = aRequest;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
sSmsRequests->AppendElement(aRequest);
|
|
|
|
return length;
|
|
}
|
|
|
|
already_AddRefed<nsISmsRequest>
|
|
AndroidBridge::DequeueSmsRequest(int32_t aRequestId)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
if (!sSmsRequests || (aRequestId >= sSmsRequests->Length())) {
|
|
return nullptr;
|
|
}
|
|
|
|
return (*sSmsRequests)[aRequestId].forget();
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
|
|
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
// To prevent calling too many methods through JNI, the Java method returns
|
|
// an array of double even if we actually want a double and a boolean.
|
|
jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformation);
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
jdoubleArray arr = static_cast<jdoubleArray>(obj);
|
|
if (!arr || env->GetArrayLength(arr) != 2) {
|
|
return;
|
|
}
|
|
|
|
jdouble* info = env->GetDoubleArrayElements(arr, 0);
|
|
|
|
aNetworkInfo->bandwidth() = info[0];
|
|
aNetworkInfo->canBeMetered() = info[1] == 1.0f;
|
|
|
|
env->ReleaseDoubleArrayElements(arr, info, 0);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableNetworkNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableNetworkNotifications");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::DisableNetworkNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::DisableNetworkNotifications");
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications);
|
|
}
|
|
|
|
void *
|
|
AndroidBridge::LockBitmap(jobject bitmap)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return nullptr;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
int err;
|
|
void *buf;
|
|
|
|
if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) {
|
|
ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
|
|
buf = nullptr;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::UnlockBitmap(jobject bitmap)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
int err;
|
|
|
|
if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0)
|
|
ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
|
|
}
|
|
|
|
|
|
bool
|
|
AndroidBridge::HasNativeWindowAccess()
|
|
{
|
|
OpenGraphicsLibraries();
|
|
|
|
// We have a fallback hack in place, so return true if that will work as well
|
|
return mHasNativeWindowAccess || mHasNativeWindowFallback;
|
|
}
|
|
|
|
void*
|
|
AndroidBridge::AcquireNativeWindow(JNIEnv* aEnv, jobject aSurface)
|
|
{
|
|
OpenGraphicsLibraries();
|
|
|
|
if (mHasNativeWindowAccess)
|
|
return ANativeWindow_fromSurface(aEnv, aSurface);
|
|
|
|
if (mHasNativeWindowFallback)
|
|
return GetNativeSurface(aEnv, aSurface);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ReleaseNativeWindow(void *window)
|
|
{
|
|
if (!window)
|
|
return;
|
|
|
|
if (mHasNativeWindowAccess)
|
|
ANativeWindow_release(window);
|
|
|
|
// XXX: we don't ref the pointer we get from the fallback (GetNativeSurface), so we
|
|
// have nothing to do here. We should probably ref it.
|
|
}
|
|
|
|
void*
|
|
AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture)
|
|
{
|
|
OpenGraphicsLibraries();
|
|
|
|
if (mHasNativeWindowAccess && ANativeWindow_fromSurfaceTexture)
|
|
return ANativeWindow_fromSurfaceTexture(aEnv, aSurfaceTexture);
|
|
|
|
if (mHasNativeWindowAccess && android_SurfaceTexture_getNativeWindow) {
|
|
android::sp<AndroidRefable> window = android_SurfaceTexture_getNativeWindow(aEnv, aSurfaceTexture);
|
|
return window.get();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window)
|
|
{
|
|
if (!window)
|
|
return;
|
|
|
|
// FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it.
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::SetNativeWindowFormat(void *window, int width, int height, int format)
|
|
{
|
|
if (mHasNativeWindowAccess)
|
|
return ANativeWindow_setBuffersGeometry(window, width, height, format) == 0;
|
|
else
|
|
return false; //unimplemented in fallback
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride)
|
|
{
|
|
/* Copied from native_window.h in Android NDK (platform-9) */
|
|
typedef struct ANativeWindow_Buffer {
|
|
// The number of pixels that are show horizontally.
|
|
int32_t width;
|
|
|
|
// The number of pixels that are shown vertically.
|
|
int32_t height;
|
|
|
|
// The number of *pixels* that a line in the buffer takes in
|
|
// memory. This may be >= width.
|
|
int32_t stride;
|
|
|
|
// The format of the buffer. One of WINDOW_FORMAT_*
|
|
int32_t format;
|
|
|
|
// The actual bits.
|
|
void* bits;
|
|
|
|
// Do not touch.
|
|
uint32_t reserved[6];
|
|
} ANativeWindow_Buffer;
|
|
|
|
// Very similar to the above, but the 'usage' field is included. We use this
|
|
// in the fallback case when NDK support is not available
|
|
struct SurfaceInfo {
|
|
uint32_t w;
|
|
uint32_t h;
|
|
uint32_t s;
|
|
uint32_t usage;
|
|
uint32_t format;
|
|
unsigned char* bits;
|
|
uint32_t reserved[2];
|
|
};
|
|
|
|
int err;
|
|
*bits = NULL;
|
|
*width = *height = *format = 0;
|
|
|
|
if (mHasNativeWindowAccess) {
|
|
ANativeWindow_Buffer buffer;
|
|
|
|
if ((err = ANativeWindow_lock(window, (void*)&buffer, NULL)) != 0) {
|
|
ALOG_BRIDGE("ANativeWindow_lock failed! (error %d)", err);
|
|
return false;
|
|
}
|
|
|
|
*bits = (unsigned char*)buffer.bits;
|
|
*width = buffer.width;
|
|
*height = buffer.height;
|
|
*format = buffer.format;
|
|
*stride = buffer.stride;
|
|
} else if (mHasNativeWindowFallback) {
|
|
SurfaceInfo info;
|
|
|
|
if ((err = Surface_lock(window, &info, NULL, true)) != 0) {
|
|
ALOG_BRIDGE("Surface_lock failed! (error %d)", err);
|
|
return false;
|
|
}
|
|
|
|
*bits = info.bits;
|
|
*width = info.w;
|
|
*height = info.h;
|
|
*format = info.format;
|
|
*stride = info.s;
|
|
} else return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::UnlockWindow(void* window)
|
|
{
|
|
int err;
|
|
|
|
if (!HasNativeWindowAccess())
|
|
return false;
|
|
|
|
if (mHasNativeWindowAccess && (err = ANativeWindow_unlockAndPost(window)) != 0) {
|
|
ALOG_BRIDGE("ANativeWindow_unlockAndPost failed! (error %d)", err);
|
|
return false;
|
|
} else if (mHasNativeWindowFallback && (err = Surface_unlockAndPost(window)) != 0) {
|
|
ALOG_BRIDGE("Surface_unlockAndPost failed! (error %d)", err);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::IsTablet()
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
|
|
bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
|
|
{
|
|
AndroidGeckoLayerClient *client = mLayerClient;
|
|
if (!client)
|
|
return;
|
|
|
|
client->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SetPageRect(const gfx::Rect& aCssPageRect)
|
|
{
|
|
AndroidGeckoLayerClient *client = mLayerClient;
|
|
if (!client)
|
|
return;
|
|
|
|
client->SetPageRect(aCssPageRect);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
|
|
nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY)
|
|
{
|
|
AndroidGeckoLayerClient *client = mLayerClient;
|
|
if (!client)
|
|
return;
|
|
|
|
client->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated, aScrollOffset, aScaleX, aScaleY);
|
|
}
|
|
|
|
AndroidBridge::AndroidBridge()
|
|
: mLayerClient(NULL)
|
|
{
|
|
}
|
|
|
|
AndroidBridge::~AndroidBridge()
|
|
{
|
|
}
|
|
|
|
/* Implementation file */
|
|
NS_IMPL_ISUPPORTS1(nsAndroidBridge, nsIAndroidBridge)
|
|
|
|
nsAndroidBridge::nsAndroidBridge()
|
|
{
|
|
}
|
|
|
|
nsAndroidBridge::~nsAndroidBridge()
|
|
{
|
|
}
|
|
|
|
/* void handleGeckoEvent (in AString message); */
|
|
NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(const nsAString & message, nsAString &aRet)
|
|
{
|
|
AndroidBridge::Bridge()->HandleGeckoMessage(message, aRet);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyDefaultPrevented(bool aDefaultPrevented)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyDefaultPrevented, (jboolean)aDefaultPrevented);
|
|
}
|
|
|
|
|
|
// DO NOT USE THIS unless you need to access JNI from
|
|
// non-main threads. This is probably not what you want.
|
|
// Questions, ask blassey or dougt.
|
|
|
|
static void
|
|
JavaThreadDetachFunc(void *arg)
|
|
{
|
|
JNIEnv *env = (JNIEnv*) arg;
|
|
JavaVM *vm = NULL;
|
|
env->GetJavaVM(&vm);
|
|
vm->DetachCurrentThread();
|
|
}
|
|
|
|
extern "C" {
|
|
__attribute__ ((visibility("default")))
|
|
JNIEnv * GetJNIForThread()
|
|
{
|
|
JNIEnv *jEnv = NULL;
|
|
JavaVM *jVm = mozilla::AndroidBridge::GetVM();
|
|
if (!jVm) {
|
|
__android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "Returned a null VM");
|
|
return NULL;
|
|
}
|
|
jEnv = static_cast<JNIEnv*>(PR_GetThreadPrivate(sJavaEnvThreadIndex));
|
|
|
|
if (jEnv)
|
|
return jEnv;
|
|
|
|
int status = jVm->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
|
|
if (status) {
|
|
|
|
status = jVm->AttachCurrentThread(&jEnv, NULL);
|
|
if (status) {
|
|
__android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "Could not attach");
|
|
return NULL;
|
|
}
|
|
|
|
PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
|
|
}
|
|
if (!jEnv) {
|
|
__android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "returning NULL");
|
|
}
|
|
return jEnv;
|
|
}
|
|
}
|
|
|
|
uint32_t
|
|
AndroidBridge::GetScreenOrientation()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return dom::eScreenOrientation_None;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
|
|
jshort orientation = env->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientation);
|
|
if (jniFrame.CheckForException())
|
|
return dom::eScreenOrientation_None;
|
|
|
|
return static_cast<dom::ScreenOrientation>(orientation);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::EnableScreenOrientationNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::EnableScreenOrientationNotifications");
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::DisableScreenOrientationNotifications()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::DisableScreenOrientationNotifications");
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::LockScreenOrientation(uint32_t aOrientation)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::LockScreenOrientation");
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jLockScreenOrientation, aOrientation);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::UnlockScreenOrientation()
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::UnlockScreenOrientation");
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::PumpMessageLoop()
|
|
{
|
|
#if MOZ_ANDROID_OMTC
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
|
|
if ((void*)pthread_self() != mThread)
|
|
return false;
|
|
|
|
return env->CallStaticBooleanMethod(mGeckoAppShellClass, jPumpMessageLoop);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyWakeLockChanged(const nsAString& topic, const nsAString& state)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
jstring jstrTopic = NewJavaString(&jniFrame, nsPromiseFlatString(topic).get(),
|
|
topic.Length());
|
|
jstring jstrState = NewJavaString(&jniFrame, nsPromiseFlatString(state).get(),
|
|
state.Length());
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, jstrTopic, jstrState);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::ScheduleComposite()
|
|
{
|
|
#if MOZ_ANDROID_OMTC
|
|
nsWindow::ScheduleComposite();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
AndroidBridge::RegisterSurfaceTextureFrameListener(jobject surfaceTexture, int id)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, surfaceTexture, id);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::UnregisterSurfaceTextureFrameListener(jobject surfaceTexture)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jUnregisterSurfaceTextureFrameListener, surfaceTexture);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::GetGfxInfoData(nsACString& aRet)
|
|
{
|
|
ALOG_BRIDGE("AndroidBridge::GetGfxInfoData");
|
|
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
jstring jstrRet = static_cast<jstring>
|
|
(env->CallStaticObjectMethod(mGeckoAppShellClass, jGetGfxInfoData));
|
|
if (jniFrame.CheckForException())
|
|
return;
|
|
|
|
nsJNIString jniStr(jstrRet, env);
|
|
CopyUTF16toUTF8(jniStr, aRet);
|
|
}
|
|
|
|
#define CREATE_JAVA_STRING(name) jstring j##name = NewJavaStringUTF(&jniFrame, nsPromiseFlatCString(a##name).get())
|
|
|
|
nsresult
|
|
AndroidBridge::GetProxyForURI(const nsACString & aSpec,
|
|
const nsACString & aScheme,
|
|
const nsACString & aHost,
|
|
const int32_t aPort,
|
|
nsACString & aResult)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
CREATE_JAVA_STRING(Spec);
|
|
CREATE_JAVA_STRING(Scheme);
|
|
CREATE_JAVA_STRING(Host);
|
|
jstring jstrRet = static_cast<jstring>
|
|
(env->CallStaticObjectMethod(mGeckoAppShellClass, jGetProxyForURI, jSpec, jScheme, jHost, aPort));
|
|
|
|
if (jniFrame.CheckForException())
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsJNIString jniStr(jstrRet, env);
|
|
CopyUTF16toUTF8(jniStr, aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
/* attribute nsIAndroidBrowserApp browserApp; */
|
|
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
|
|
{
|
|
if (nsAppShell::gAppShell)
|
|
nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
|
|
{
|
|
if (nsAppShell::gAppShell)
|
|
nsAppShell::gAppShell->SetBrowserApp(aBrowserApp);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
AndroidBridge::AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen) {
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
#if MOZ_ANDROID_OMTC
|
|
env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
|
|
sBridge->jAddPluginView, view,
|
|
(int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height,
|
|
isFullScreen);
|
|
#else
|
|
env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
|
|
sBridge->jAddPluginView, view,
|
|
rect.x, rect.y, rect.width, rect.height);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
AndroidBridge::RemovePluginView(jobject view, bool isFullScreen)
|
|
{
|
|
JNIEnv *env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, view, isFullScreen);
|
|
}
|
|
|
|
extern "C"
|
|
__attribute__ ((visibility("default")))
|
|
jobject JNICALL
|
|
Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
|
|
|
|
|
|
nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, int32_t srcX, int32_t srcY, int32_t srcW, int32_t srcH, int32_t dstX, int32_t dstY, int32_t dstW, int32_t dstH, int32_t bufW, int32_t bufH, int32_t tabId, int32_t token, jobject buffer)
|
|
{
|
|
nsresult rv;
|
|
float scale = 1.0;
|
|
|
|
if (!buffer)
|
|
return NS_OK;
|
|
|
|
// take a screenshot, as wide as possible, proportional to the destination size
|
|
if (!srcW && !srcH) {
|
|
nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
|
|
if (!utils)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIDOMClientRect> rect;
|
|
rv = utils->GetRootBounds(getter_AddRefs(rect));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
if (!rect)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
float left, top, width, height;
|
|
rect->GetLeft(&left);
|
|
rect->GetTop(&top);
|
|
rect->GetWidth(&width);
|
|
rect->GetHeight(&height);
|
|
|
|
if (width == 0 || height == 0)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
float aspectRatio = ((float) dstW) / dstH;
|
|
if (width / aspectRatio < height) {
|
|
srcW = width;
|
|
srcH = width / aspectRatio;
|
|
} else {
|
|
srcW = height * aspectRatio;
|
|
srcH = height;
|
|
}
|
|
|
|
srcX = left;
|
|
srcY = top;
|
|
}
|
|
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return NS_OK;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
|
|
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(window);
|
|
if (!win)
|
|
return NS_ERROR_FAILURE;
|
|
nsRefPtr<nsPresContext> presContext;
|
|
nsIDocShell* docshell = win->GetDocShell();
|
|
if (docshell) {
|
|
docshell->GetPresContext(getter_AddRefs(presContext));
|
|
}
|
|
if (!presContext)
|
|
return NS_ERROR_FAILURE;
|
|
nscolor bgColor = NS_RGB(255, 255, 255);
|
|
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
|
uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING |
|
|
nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
|
nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
|
|
nsPresContext::CSSPixelsToAppUnits(srcY / scale),
|
|
nsPresContext::CSSPixelsToAppUnits(srcW / scale),
|
|
nsPresContext::CSSPixelsToAppUnits(srcH / scale));
|
|
|
|
uint32_t stride = bufW * 2 /* 16 bpp */;
|
|
|
|
void* data = env->GetDirectBufferAddress(buffer);
|
|
if (!data)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(static_cast<unsigned char*>(data), nsIntSize(bufW, bufH), stride, gfxASurface::ImageFormatRGB16_565);
|
|
if (surf->CairoStatus() != 0) {
|
|
ALOG_BRIDGE("Error creating gfxImageSurface");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
nsRefPtr<gfxContext> context = new gfxContext(surf);
|
|
gfxPoint pt(dstX, dstY);
|
|
context->Translate(pt);
|
|
context->Scale(scale * dstW / srcW, scale * dstH / srcH);
|
|
rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jScreenshotHandlerClass,
|
|
AndroidBridge::Bridge()->jNotifyScreenShot,
|
|
buffer, tabId,
|
|
dstX, dstY, dstX + dstW, dstY + dstH,
|
|
bufW, bufH, token);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsAndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
|
|
{
|
|
return AndroidBridge::Bridge()->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, metrics, displayPort);
|
|
}
|
|
|
|
nsresult
|
|
AndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env || !mLayerClient)
|
|
return NS_OK;
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
mLayerClient->GetDisplayPort(&jniFrame, aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, metrics, displayPort);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, float aDisplayResolution, gfx::Rect& aViewport, float& aScaleX, float& aScaleY)
|
|
{
|
|
AndroidGeckoLayerClient *client = mLayerClient;
|
|
if (!client)
|
|
return false;
|
|
|
|
return client->ProgressiveUpdateCallback(aHasPendingNewThebesContent, aDisplayPort, aDisplayResolution, aViewport, aScaleX, aScaleY);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::NotifyPaintedRect(float top, float left, float bottom, float right)
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
env->CallStaticVoidMethod(AndroidBridge::Bridge()->jScreenshotHandlerClass,
|
|
AndroidBridge::Bridge()->jNotifyPaintedRect,
|
|
top, left, bottom, right);
|
|
}
|
|
|
|
void
|
|
AndroidBridge::KillAnyZombies()
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return;
|
|
env->CallStaticVoidMethod(mGeckoAppShellClass, AndroidBridge::Bridge()->jKillAnyZombies);
|
|
}
|
|
|
|
bool
|
|
AndroidBridge::UnlockProfile()
|
|
{
|
|
JNIEnv* env = GetJNIEnv();
|
|
if (!env)
|
|
return false;
|
|
|
|
AutoLocalJNIFrame jniFrame(env, 0);
|
|
bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jUnlockProfile);
|
|
if (jniFrame.CheckForException())
|
|
return false;
|
|
|
|
return ret;
|
|
}
|
|
|
|
extern "C" {
|
|
__attribute__ ((visibility("default")))
|
|
jclass
|
|
jsjni_FindClass(const char *className) {
|
|
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
|
if (!env) return NULL;
|
|
return env->FindClass(className);
|
|
}
|
|
|
|
__attribute__ ((visibility("default")))
|
|
jmethodID
|
|
jsjni_GetStaticMethodID(jclass methodClass,
|
|
const char *methodName,
|
|
const char *signature) {
|
|
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
|
if (!env) return NULL;
|
|
return env->GetStaticMethodID(methodClass, methodName, signature);
|
|
}
|
|
|
|
__attribute__ ((visibility("default")))
|
|
bool
|
|
jsjni_ExceptionCheck() {
|
|
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
|
if (!env) return NULL;
|
|
return env->ExceptionCheck();
|
|
}
|
|
|
|
__attribute__ ((visibility("default")))
|
|
void
|
|
jsjni_CallStaticVoidMethodA(jclass cls,
|
|
jmethodID method,
|
|
jvalue *values) {
|
|
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
|
if (!env) return;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
env->CallStaticVoidMethodA(cls, method, values);
|
|
}
|
|
|
|
__attribute__ ((visibility("default")))
|
|
int
|
|
jsjni_CallStaticIntMethodA(jclass cls,
|
|
jmethodID method,
|
|
jvalue *values) {
|
|
JNIEnv *env = AndroidBridge::GetJNIEnv();
|
|
if (!env) return -1;
|
|
|
|
AutoLocalJNIFrame jniFrame(env);
|
|
return env->CallStaticIntMethodA(cls, method, values);
|
|
}
|
|
}
|