Bug 564327 - Add Android widgets backend [2/2], patch by vlad, alexp, blassey, and me. r=dougt, sr=roc

This commit is contained in:
Michael Wu
2010-06-03 13:56:36 -07:00
parent f23dbb6689
commit 027564f075
25 changed files with 4896 additions and 1 deletions

View 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();
}