Bug 564327 - Add Android widgets backend [2/2], patch by vlad, alexp, blassey, and me. r=dougt, sr=roc
This commit is contained in:
237
widget/src/android/AndroidBridge.cpp
Normal file
237
widget/src/android/AndroidBridge.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Android code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Vladimir Vukicevic <vladimir@pobox.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <prthread.h>
|
||||
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
static PRUintn sJavaEnvThreadIndex = 0;
|
||||
|
||||
AndroidBridge *AndroidBridge::sBridge = 0;
|
||||
|
||||
static void
|
||||
JavaThreadDetachFunc(void *arg)
|
||||
{
|
||||
JNIEnv *env = (JNIEnv*) arg;
|
||||
JavaVM *vm = NULL;
|
||||
env->GetJavaVM(&vm);
|
||||
vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
AndroidBridge *
|
||||
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(strdup("NSS_DISABLE_UNLOAD=1"));
|
||||
|
||||
sBridge = new AndroidBridge();
|
||||
if (!sBridge->Init(jEnv, jGeckoAppShellClass)) {
|
||||
delete sBridge;
|
||||
sBridge = 0;
|
||||
}
|
||||
|
||||
PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
|
||||
|
||||
return sBridge;
|
||||
}
|
||||
|
||||
PRBool
|
||||
AndroidBridge::Init(JNIEnv *jEnv,
|
||||
jclass jGeckoAppShellClass)
|
||||
{
|
||||
jEnv->GetJavaVM(&mJavaVM);
|
||||
|
||||
mJNIEnv = nsnull;
|
||||
mThread = nsnull;
|
||||
|
||||
mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
|
||||
|
||||
jShowIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showIME", "(I)V");
|
||||
jEnableAccelerometer = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableAccelerometer", "(Z)V");
|
||||
jReturnIMEQueryResult = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "returnIMEQueryResult", "(Ljava/lang/String;II)V");
|
||||
jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
|
||||
jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
|
||||
|
||||
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 PR_TRUE;
|
||||
}
|
||||
|
||||
JNIEnv *
|
||||
AndroidBridge::AttachThread(PRBool asDaemon)
|
||||
{
|
||||
JNIEnv *jEnv = (JNIEnv*) PR_GetThreadPrivate(sJavaEnvThreadIndex);
|
||||
if (jEnv)
|
||||
return jEnv;
|
||||
|
||||
JavaVMAttachArgs args = {
|
||||
JNI_VERSION_1_2,
|
||||
"GeckoThread",
|
||||
NULL
|
||||
};
|
||||
|
||||
jint res = 0;
|
||||
|
||||
if (asDaemon) {
|
||||
res = mJavaVM->AttachCurrentThreadAsDaemon(&jEnv, &args);
|
||||
} else {
|
||||
res = mJavaVM->AttachCurrentThread(&jEnv, &args);
|
||||
}
|
||||
|
||||
if (res != 0) {
|
||||
ALOG("AttachCurrentThread failed!");
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
|
||||
|
||||
return jEnv;
|
||||
}
|
||||
|
||||
PRBool
|
||||
AndroidBridge::SetMainThread(void *thr)
|
||||
{
|
||||
if (thr) {
|
||||
mJNIEnv = AttachThread(PR_FALSE);
|
||||
if (!mJNIEnv)
|
||||
return PR_FALSE;
|
||||
|
||||
mThread = thr;
|
||||
} else {
|
||||
mJNIEnv = nsnull;
|
||||
mThread = nsnull;
|
||||
}
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::EnsureJNIThread()
|
||||
{
|
||||
JNIEnv *env;
|
||||
if (mJavaVM->AttachCurrentThread(&env, NULL) != 0) {
|
||||
ALOG("EnsureJNIThread: test Attach failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((void*)pthread_self() != mThread) {
|
||||
ALOG("###!!!!!!! Something's grabbing the JNIEnv from the wrong thread! (thr %p should be %p)",
|
||||
(void*)pthread_self(), (void*)mThread);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ShowIME(int aState)
|
||||
{
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jShowIME, aState);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::EnableAccelerometer(bool aEnable)
|
||||
{
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableAccelerometer, aEnable);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ReturnIMEQueryResult(const PRUnichar *result, PRUint32 len, int selectionStart, int selectionEnd)
|
||||
{
|
||||
jvalue args[3];
|
||||
args[0].l = mJNIEnv->NewString(result, len);
|
||||
args[1].i = selectionStart;
|
||||
args[2].i = selectionEnd;
|
||||
mJNIEnv->CallStaticVoidMethodA(mGeckoAppShellClass, jReturnIMEQueryResult, args);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ScheduleRestart()
|
||||
{
|
||||
ALOG("scheduling reboot");
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::NotifyXreExit()
|
||||
{
|
||||
ALOG("xre exiting");
|
||||
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::SetSurfaceView(jobject obj)
|
||||
{
|
||||
mSurfaceView.Init(obj);
|
||||
}
|
||||
|
||||
// Available for places elsewhere in the code to link to.
|
||||
PRBool
|
||||
mozilla_AndroidBridge_SetMainThread(void *thr)
|
||||
{
|
||||
return AndroidBridge::Bridge()->SetMainThread(thr);
|
||||
}
|
||||
|
||||
JavaVM *
|
||||
mozilla_AndroidBridge_GetJavaVM()
|
||||
{
|
||||
return AndroidBridge::Bridge()->VM();
|
||||
}
|
||||
|
||||
JNIEnv *
|
||||
mozilla_AndroidBridge_AttachThread(PRBool asDaemon)
|
||||
{
|
||||
return AndroidBridge::Bridge()->AttachThread(asDaemon);
|
||||
}
|
||||
|
||||
extern "C" JNIEnv * GetJNIForThread()
|
||||
{
|
||||
return mozilla::AndroidBridge::JNIForThread();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user