зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1116868 - Add templated JNI classes; r=snorp
This commit is contained in:
Родитель
d60c1e78f2
Коммит
52b4f608fa
|
@ -28,6 +28,7 @@
|
|||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/jni/Utils.h"
|
||||
|
||||
// Some debug #defines
|
||||
// #define DEBUG_ANDROID_EVENTS
|
||||
|
@ -38,9 +39,6 @@ class nsIDOMMozSmsMessage;
|
|||
class nsIObserver;
|
||||
class Task;
|
||||
|
||||
/* See the comment in AndroidBridge about this function before using it */
|
||||
extern "C" MOZ_EXPORT JNIEnv * GetJNIForThread();
|
||||
|
||||
extern bool mozilla_AndroidBridge_SetMainThread(pthread_t);
|
||||
|
||||
namespace base {
|
||||
|
@ -166,29 +164,16 @@ public:
|
|||
|
||||
static bool ThrowException(JNIEnv *aEnv, const char *aClass,
|
||||
const char *aMessage) {
|
||||
MOZ_ASSERT(aEnv, "Invalid thread JNI env");
|
||||
jclass cls = aEnv->FindClass(aClass);
|
||||
MOZ_ASSERT(cls, "Cannot find exception class");
|
||||
bool ret = !aEnv->ThrowNew(cls, aMessage);
|
||||
aEnv->DeleteLocalRef(cls);
|
||||
return ret;
|
||||
|
||||
return jni::ThrowException(aEnv, aClass, aMessage);
|
||||
}
|
||||
|
||||
static bool ThrowException(JNIEnv *aEnv, const char *aMessage) {
|
||||
return ThrowException(aEnv, "java/lang/Exception", aMessage);
|
||||
return jni::ThrowException(aEnv, aMessage);
|
||||
}
|
||||
|
||||
static void HandleUncaughtException(JNIEnv *aEnv) {
|
||||
MOZ_ASSERT(aEnv);
|
||||
if (!aEnv->ExceptionCheck()) {
|
||||
return;
|
||||
}
|
||||
jthrowable e = aEnv->ExceptionOccurred();
|
||||
MOZ_ASSERT(e);
|
||||
aEnv->ExceptionClear();
|
||||
mozilla::widget::android::GeckoAppShell::HandleUncaughtException(nullptr, e);
|
||||
// Should be dead by now...
|
||||
MOZ_CRASH("Failed to handle uncaught exception");
|
||||
jni::HandleUncaughtException(aEnv);
|
||||
}
|
||||
|
||||
// The bridge needs to be constructed via ConstructBridge first,
|
||||
|
@ -557,7 +542,7 @@ public:
|
|||
|
||||
bool CheckForException() {
|
||||
if (mJNIEnv->ExceptionCheck()) {
|
||||
AndroidBridge::HandleUncaughtException(mJNIEnv);
|
||||
jni::HandleUncaughtException(mJNIEnv);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
#ifndef mozilla_jni_Accessors_h__
|
||||
#define mozilla_jni_Accessors_h__
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/jni/Refs.h"
|
||||
#include "mozilla/jni/Types.h"
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jni{
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class to convert an arbitrary type to a jvalue, e.g. Value(123).val.
|
||||
struct Value
|
||||
{
|
||||
Value(jboolean z) { val.z = z; }
|
||||
Value(jbyte b) { val.b = b; }
|
||||
Value(jchar c) { val.c = c; }
|
||||
Value(jshort s) { val.s = s; }
|
||||
Value(jint i) { val.i = i; }
|
||||
Value(jlong j) { val.j = j; }
|
||||
Value(jfloat f) { val.f = f; }
|
||||
Value(jdouble d) { val.d = d; }
|
||||
Value(jobject l) { val.l = l; }
|
||||
|
||||
jvalue val;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Base class for Method<>, Field<>, and Constructor<>.
|
||||
class Accessor {
|
||||
private:
|
||||
template<class Cls>
|
||||
static void EnsureClassRef(JNIEnv* env)
|
||||
{
|
||||
if (!Cls::sClassRef) {
|
||||
MOZ_ALWAYS_TRUE(Cls::sClassRef =
|
||||
AndroidBridge::GetClassGlobalRef(env, Cls::name));
|
||||
}
|
||||
}
|
||||
|
||||
static void GetNsresult(JNIEnv* env, nsresult* rv)
|
||||
{
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionClear();
|
||||
*rv = NS_ERROR_FAILURE;
|
||||
} else {
|
||||
*rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// Called before making a JNIEnv call.
|
||||
template<class Traits>
|
||||
static JNIEnv* BeginAccess()
|
||||
{
|
||||
JNIEnv* const env = Traits::isMultithreaded
|
||||
? GetJNIForThread() : AndroidBridge::GetJNIEnv();
|
||||
|
||||
EnsureClassRef<class Traits::Owner>(env);
|
||||
return env;
|
||||
}
|
||||
|
||||
// Called after making a JNIEnv call.
|
||||
template<class Traits>
|
||||
static void EndAccess(JNIEnv* env, nsresult* rv)
|
||||
{
|
||||
if (Traits::exceptionMode == ExceptionMode::ABORT) {
|
||||
return HandleUncaughtException(env);
|
||||
|
||||
} else if (Traits::exceptionMode == ExceptionMode::NSRESULT) {
|
||||
return GetNsresult(env, rv);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Member<> is used to call a JNI method given a traits class.
|
||||
template<class Traits, typename ReturnType = typename Traits::ReturnType>
|
||||
class Method : public Accessor
|
||||
{
|
||||
typedef Accessor Base;
|
||||
typedef class Traits::Owner Owner;
|
||||
|
||||
protected:
|
||||
static jmethodID sID;
|
||||
|
||||
static JNIEnv* BeginAccess()
|
||||
{
|
||||
JNIEnv* const env = Base::BeginAccess<Traits>();
|
||||
|
||||
if (sID) {
|
||||
return env;
|
||||
}
|
||||
|
||||
if (Traits::isStatic) {
|
||||
MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticMethodID(
|
||||
env, Traits::Owner::sClassRef, Traits::name, Traits::signature));
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetMethodID(
|
||||
env, Traits::Owner::sClassRef, Traits::name, Traits::signature));
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static void EndAccess(JNIEnv* env, nsresult* rv)
|
||||
{
|
||||
return Base::EndAccess<Traits>(env, rv);
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
static ReturnType Call(const Owner* cls, nsresult* rv, const Args&... args)
|
||||
{
|
||||
JNIEnv* const env = BeginAccess();
|
||||
|
||||
jvalue jargs[] = {
|
||||
Value(TypeAdapter<Args>::FromNative(env, args)).val ...
|
||||
};
|
||||
|
||||
auto result = TypeAdapter<ReturnType>::ToNative(env,
|
||||
Traits::isStatic ?
|
||||
(env->*TypeAdapter<ReturnType>::StaticCall)(
|
||||
Owner::sClassRef, sID, jargs) :
|
||||
(env->*TypeAdapter<ReturnType>::Call)(
|
||||
cls->mInstance, sID, jargs));
|
||||
|
||||
EndAccess(env, rv);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Define sID member.
|
||||
template<class T, typename R> jmethodID Method<T, R>::sID;
|
||||
|
||||
|
||||
// Specialize void because C++ forbids us from
|
||||
// using a "void" temporary result variable.
|
||||
template<class Traits>
|
||||
class Method<Traits, void> : public Method<Traits, bool>
|
||||
{
|
||||
typedef Method<Traits, bool> Base;
|
||||
typedef typename Traits::Owner Owner;
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
static void Call(const Owner* cls, nsresult* rv,
|
||||
const Args&... args) MOZ_OVERRIDE
|
||||
{
|
||||
JNIEnv* const env = Base::BeginAccess();
|
||||
|
||||
jvalue jargs[] = {
|
||||
Value(TypeAdapter<Args>::FromNative(env, args)).val ...
|
||||
};
|
||||
|
||||
if (Traits::isStatic) {
|
||||
env->CallStaticVoidMethodA(Owner::sClassRef, Base::sID, jargs);
|
||||
} else {
|
||||
env->CallVoidMethodA(cls->mInstance, Base::sID, jargs);
|
||||
}
|
||||
|
||||
Base::EndAccess(env, rv);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Constructor<> is used to construct a JNI instance given a traits class.
|
||||
template<class Traits>
|
||||
class Constructor : protected Method<Traits, typename Traits::ReturnType> {
|
||||
typedef class Traits::Owner Owner;
|
||||
typedef typename Traits::ReturnType ReturnType;
|
||||
typedef Method<Traits, ReturnType> Base;
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
static ReturnType Call(const Owner* cls, nsresult* rv,
|
||||
const Args&... args) MOZ_OVERRIDE
|
||||
{
|
||||
JNIEnv* const env = Base::BeginAccess();
|
||||
|
||||
jvalue jargs[] = {
|
||||
Value(TypeAdapter<Args>::FromNative(env, args)).val ...
|
||||
};
|
||||
|
||||
auto result = TypeAdapter<ReturnType>::ToNative(
|
||||
env, env->NewObjectA(Owner::sClassRef, Base::sID, jargs));
|
||||
|
||||
Base::EndAccess(env, rv);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Field<> is used to access a JNI field given a traits class.
|
||||
template<class Traits>
|
||||
class Field : public Accessor
|
||||
{
|
||||
typedef Accessor Base;
|
||||
typedef class Traits::Owner Owner;
|
||||
typedef typename Traits::ReturnType GetterType;
|
||||
typedef typename Traits::SetterType SetterType;
|
||||
|
||||
template<typename T> struct RemoveRef { typedef T Type; };
|
||||
template<typename T> struct RemoveRef<const T&> { typedef T Type; };
|
||||
|
||||
// Setter type without any const/& added
|
||||
typedef typename RemoveRef<SetterType>::Type SetterBaseType;
|
||||
|
||||
private:
|
||||
|
||||
static jfieldID sID;
|
||||
|
||||
static JNIEnv* BeginAccess()
|
||||
{
|
||||
JNIEnv* const env = Base::BeginAccess<Traits>();
|
||||
|
||||
if (sID) {
|
||||
return env;
|
||||
}
|
||||
|
||||
if (Traits::isStatic) {
|
||||
MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticFieldID(
|
||||
env, Traits::Owner::sClassRef, Traits::name, Traits::signature));
|
||||
} else {
|
||||
MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetFieldID(
|
||||
env, Traits::Owner::sClassRef, Traits::name, Traits::signature));
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static void EndAccess(JNIEnv* env, nsresult* rv)
|
||||
{
|
||||
return Base::EndAccess<Traits>(env, rv);
|
||||
}
|
||||
|
||||
public:
|
||||
static GetterType Get(const Owner* cls, nsresult* rv)
|
||||
{
|
||||
JNIEnv* const env = BeginAccess();
|
||||
|
||||
auto result = TypeAdapter<GetterType>::ToNative(
|
||||
env, Traits::isStatic ?
|
||||
|
||||
(env->*TypeAdapter<GetterType>::StaticGet)
|
||||
(Owner::sClassRef, sID) :
|
||||
|
||||
(env->*TypeAdapter<GetterType>::Get)
|
||||
(cls->mInstance, sID));
|
||||
|
||||
EndAccess(env, rv);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Set(const Owner* cls, nsresult* rv, SetterType val)
|
||||
{
|
||||
JNIEnv* const env = BeginAccess();
|
||||
|
||||
if (Traits::isStatic) {
|
||||
(env->*TypeAdapter<SetterBaseType>::StaticSet)(
|
||||
Owner::sClassRef, sID,
|
||||
TypeAdapter<SetterBaseType>::FromNative(env, val));
|
||||
} else {
|
||||
(env->*TypeAdapter<SetterBaseType>::Set)(
|
||||
cls->mInstance, sID,
|
||||
TypeAdapter<SetterBaseType>::FromNative(env, val));
|
||||
}
|
||||
|
||||
EndAccess(env, rv);
|
||||
}
|
||||
};
|
||||
|
||||
// Define sID member.
|
||||
template<class T> jfieldID Field<T>::sID;
|
||||
|
||||
|
||||
// Define the sClassRef member declared in Refs.h and
|
||||
// used by Method and Field above.
|
||||
template<class C> jclass Class<C>::sClassRef;
|
||||
|
||||
} // namespace jni
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jni_Accessors_h__
|
|
@ -0,0 +1,644 @@
|
|||
#ifndef mozilla_jni_Refs_h__
|
||||
#define mozilla_jni_Refs_h__
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/jni/Utils.h"
|
||||
|
||||
#include "nsError.h" // for nsresult
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jni {
|
||||
|
||||
class Accessor;
|
||||
template<class T> class Constructor;
|
||||
template<class T> class Field;
|
||||
template<class T, typename R> class Method;
|
||||
|
||||
// Wrapped object reference (e.g. jobject, jclass, etc...)
|
||||
template<class Cls> class Ref;
|
||||
// Wrapped local reference that inherits from Ref.
|
||||
template<class Cls> class LocalRef;
|
||||
// Wrapped global reference that inherits from Ref.
|
||||
template<class Cls> class GlobalRef;
|
||||
|
||||
// Type used for a reference parameter. Default is a wrapped object
|
||||
// reference, but Param can be specialized to define custom behavior,
|
||||
// e.g. a StringParam class that automatically converts nsAString& and
|
||||
// nsACString& to a jstring.
|
||||
template<class Cls> struct Param { typedef Ref<Cls> Type; };
|
||||
|
||||
|
||||
// How exception during a JNI call should be treated.
|
||||
enum class ExceptionMode
|
||||
{
|
||||
// Abort on unhandled excepion (default).
|
||||
ABORT,
|
||||
// Ignore the exception and return to caller.
|
||||
IGNORE,
|
||||
// Catch any exception and return a nsresult.
|
||||
NSRESULT,
|
||||
};
|
||||
|
||||
|
||||
// Base class for all JNI binding classes.
|
||||
// Templated so that we have one sClassRef for each class.
|
||||
template<class Cls>
|
||||
class Class
|
||||
{
|
||||
friend class Accessor;
|
||||
template<class T> friend class Constructor;
|
||||
template<class T> friend class Field;
|
||||
template<class T, typename R> friend class Method;
|
||||
|
||||
private:
|
||||
static jclass sClassRef; // global reference
|
||||
|
||||
protected:
|
||||
jobject mInstance; // local or global reference
|
||||
|
||||
Class(jobject instance) : mInstance(instance) {}
|
||||
};
|
||||
|
||||
|
||||
// Binding for a plain jobject.
|
||||
class Object : public Class<Object>
|
||||
{
|
||||
protected:
|
||||
Object(jobject instance) : Class(instance) {}
|
||||
|
||||
public:
|
||||
typedef jni::Ref<Object> Ref;
|
||||
typedef jni::LocalRef<Object> LocalRef;
|
||||
typedef jni::GlobalRef<Object> GlobalRef;
|
||||
typedef const typename jni::Param<Object>::Type& Param;
|
||||
};
|
||||
|
||||
|
||||
// Binding for a built-in object reference other than jobject.
|
||||
template<typename T>
|
||||
class TypedObject : public Object
|
||||
{
|
||||
typedef TypedObject<T> Self;
|
||||
|
||||
protected:
|
||||
TypedObject(jobject instance) : Object(instance) {}
|
||||
|
||||
public:
|
||||
typedef jni::Ref<Self> Ref;
|
||||
typedef jni::LocalRef<Self> LocalRef;
|
||||
typedef jni::GlobalRef<Self> GlobalRef;
|
||||
typedef const typename jni::Param<Self>::Type& Param;
|
||||
};
|
||||
|
||||
// Define bindings for built-in types.
|
||||
typedef TypedObject<jstring> String;
|
||||
typedef TypedObject<jclass> ClassObject;
|
||||
typedef TypedObject<jthrowable> Throwable;
|
||||
|
||||
typedef TypedObject<jbooleanArray> BooleanArray;
|
||||
typedef TypedObject<jbyteArray> ByteArray;
|
||||
typedef TypedObject<jcharArray> CharArray;
|
||||
typedef TypedObject<jshortArray> ShortArray;
|
||||
typedef TypedObject<jintArray> IntArray;
|
||||
typedef TypedObject<jlongArray> LongArray;
|
||||
typedef TypedObject<jfloatArray> FloatArray;
|
||||
typedef TypedObject<jdoubleArray> DoubleArray;
|
||||
typedef TypedObject<jobjectArray> ObjectArray;
|
||||
|
||||
template<> struct Param<String> { class Type; };
|
||||
|
||||
|
||||
// Base class for Ref and its specializations.
|
||||
template<class Cls, typename JNIType>
|
||||
class RefBase : protected Cls
|
||||
{
|
||||
typedef RefBase<Cls, JNIType> Self;
|
||||
typedef void (Self::*bool_type)() const;
|
||||
void non_null_reference() const {}
|
||||
|
||||
protected:
|
||||
RefBase(jobject instance) : Cls(instance) {}
|
||||
|
||||
public:
|
||||
// Construct a Ref form a raw JNI reference.
|
||||
static Ref<Cls> From(JNIType obj)
|
||||
{
|
||||
return Ref<Cls>(static_cast<jobject>(obj));
|
||||
}
|
||||
|
||||
// Get the raw JNI reference.
|
||||
JNIType Get() const
|
||||
{
|
||||
return static_cast<JNIType>(Cls::mInstance);
|
||||
}
|
||||
|
||||
bool operator==(const RefBase& other) const
|
||||
{
|
||||
// Treat two references of the same object as being the same.
|
||||
return Cls::mInstance == other.mInstance &&
|
||||
GetJNIForThread()->IsSameObject(
|
||||
Cls::mInstance, other.mInstance) != JNI_FALSE;
|
||||
}
|
||||
|
||||
bool operator!=(const RefBase& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool operator==(decltype(nullptr)) const
|
||||
{
|
||||
return !Cls::mInstance;
|
||||
}
|
||||
|
||||
bool operator!=(decltype(nullptr)) const
|
||||
{
|
||||
return !!Cls::mInstance;
|
||||
}
|
||||
|
||||
Cls* operator->()
|
||||
{
|
||||
MOZ_ASSERT(Cls::mInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
const Cls* operator->() const
|
||||
{
|
||||
MOZ_ASSERT(Cls::mInstance);
|
||||
return this;
|
||||
}
|
||||
|
||||
// Any ref can be cast to an object ref.
|
||||
operator Ref<Object>() const;
|
||||
|
||||
// Null checking (e.g. !!ref) using the safe-bool idiom.
|
||||
operator bool_type() const
|
||||
{
|
||||
return Cls::mInstance ? &Self::non_null_reference : nullptr;
|
||||
}
|
||||
|
||||
// We don't allow implicit conversion to jobject because that can lead
|
||||
// to easy mistakes such as assigning a temporary LocalRef to a jobject,
|
||||
// and using the jobject after the LocalRef has been freed.
|
||||
|
||||
// We don't allow explicit conversion, to make outside code use Ref::Get.
|
||||
// Using Ref::Get makes it very easy to see which code is using raw JNI
|
||||
// types to make future refactoring easier.
|
||||
|
||||
// operator JNIType() const = delete;
|
||||
};
|
||||
|
||||
|
||||
// Wrapped object reference (e.g. jobject, jclass, etc...)
|
||||
template<class Cls>
|
||||
class Ref : public RefBase<Cls, jobject>
|
||||
{
|
||||
template<class C, typename T> friend class RefBase;
|
||||
friend class jni::LocalRef<Cls>;
|
||||
friend class jni::GlobalRef<Cls>;
|
||||
|
||||
typedef RefBase<Cls, jobject> Base;
|
||||
|
||||
protected:
|
||||
// Protected jobject constructor because outside code should be using
|
||||
// Ref::From. Using Ref::From makes it very easy to see which code is using
|
||||
// raw JNI types for future refactoring.
|
||||
Ref(jobject instance) : Base(instance) {}
|
||||
|
||||
// Protected copy constructor so that there's no danger of assigning a
|
||||
// temporary LocalRef/GlobalRef to a Ref, and potentially use the Ref
|
||||
// after the source had been freed.
|
||||
Ref(const Ref& ref) : Base(ref.mInstance) {}
|
||||
|
||||
public:
|
||||
MOZ_IMPLICIT Ref(decltype(nullptr)) : Base(nullptr) {}
|
||||
};
|
||||
|
||||
|
||||
template<class Cls, typename JNIType>
|
||||
RefBase<Cls, JNIType>::operator Ref<Object>() const
|
||||
{
|
||||
return Ref<Object>(Cls::mInstance);
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Ref<TypedObject<T>>
|
||||
: public RefBase<TypedObject<T>, T>
|
||||
{
|
||||
friend class RefBase<TypedObject<T>, T>;
|
||||
friend class jni::LocalRef<TypedObject<T>>;
|
||||
friend class jni::GlobalRef<TypedObject<T>>;
|
||||
|
||||
typedef RefBase<TypedObject<T>, T> Base;
|
||||
|
||||
protected:
|
||||
Ref(jobject instance) : Base(instance) {}
|
||||
|
||||
Ref(const Ref& ref) : Base(ref.mInstance) {}
|
||||
|
||||
public:
|
||||
MOZ_IMPLICIT Ref(decltype(nullptr)) : Base(nullptr) {}
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
// See explanation in LocalRef.
|
||||
template<class Cls> struct GenericObject { typedef Object Type; };
|
||||
template<> struct GenericObject<Object> { typedef struct {} Type; };
|
||||
|
||||
} // namespace
|
||||
|
||||
template<class Cls>
|
||||
class LocalRef : public Ref<Cls>
|
||||
{
|
||||
template<class C> friend class LocalRef;
|
||||
|
||||
private:
|
||||
// In order to be able to convert LocalRef<Object> to LocalRef<Cls>, we
|
||||
// need constructors and copy assignment operators that take in a
|
||||
// LocalRef<Object> argument. However, if Cls *is* Object, we would have
|
||||
// duplicated constructors and operators with LocalRef<Object> arguments. To
|
||||
// avoid this conflict, we use GenericObject, which is defined as Object for
|
||||
// LocalRef<non-Object> and defined as a dummy class for LocalRef<Object>.
|
||||
typedef typename GenericObject<Cls>::Type GenericObject;
|
||||
|
||||
JNIEnv* const mEnv;
|
||||
|
||||
LocalRef(JNIEnv* env, jobject instance)
|
||||
: Ref<Cls>(instance)
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
LocalRef& swap(LocalRef& other)
|
||||
{
|
||||
auto instance = other.mInstance;
|
||||
other.mInstance = Ref<Cls>::mInstance;
|
||||
Ref<Cls>::mInstance = instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
// Construct a LocalRef from a raw JNI local reference. Unlike Ref::From,
|
||||
// LocalRef::Adopt returns a LocalRef that will delete the local reference
|
||||
// when going out of scope.
|
||||
static LocalRef Adopt(jobject instance)
|
||||
{
|
||||
return LocalRef(GetJNIForThread(), instance);
|
||||
}
|
||||
|
||||
static LocalRef Adopt(JNIEnv* env, jobject instance)
|
||||
{
|
||||
return LocalRef(env, instance);
|
||||
}
|
||||
|
||||
// Copy constructor.
|
||||
LocalRef(const LocalRef<Cls>& ref)
|
||||
: Ref<Cls>(ref.mEnv->NewLocalRef(ref.mInstance))
|
||||
, mEnv(ref.mEnv)
|
||||
{}
|
||||
|
||||
// Move constructor.
|
||||
LocalRef(LocalRef<Cls>&& ref)
|
||||
: Ref<Cls>(ref.mInstance)
|
||||
, mEnv(ref.mEnv)
|
||||
{
|
||||
ref.mInstance = nullptr;
|
||||
}
|
||||
|
||||
explicit LocalRef(JNIEnv* env = GetJNIForThread())
|
||||
: Ref<Cls>(nullptr)
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
// Construct a LocalRef from any Ref,
|
||||
// which means creating a new local reference.
|
||||
MOZ_IMPLICIT LocalRef(const Ref<Cls>& ref)
|
||||
: Ref<Cls>(nullptr)
|
||||
, mEnv(GetJNIForThread())
|
||||
{
|
||||
Ref<Cls>::mInstance = mEnv->NewLocalRef(ref.mInstance);
|
||||
}
|
||||
|
||||
// Move a LocalRef<Object> into a LocalRef<Cls> without
|
||||
// creating/deleting local references.
|
||||
MOZ_IMPLICIT LocalRef(LocalRef<GenericObject>&& ref)
|
||||
: Ref<Cls>(ref.mInstance)
|
||||
, mEnv(ref.mEnv)
|
||||
{
|
||||
ref.mInstance = nullptr;
|
||||
}
|
||||
|
||||
// Implicitly converts nullptr to LocalRef.
|
||||
MOZ_IMPLICIT LocalRef(decltype(nullptr))
|
||||
: Ref<Cls>(nullptr)
|
||||
, mEnv(GetJNIForThread())
|
||||
{}
|
||||
|
||||
~LocalRef()
|
||||
{
|
||||
if (Ref<Cls>::mInstance) {
|
||||
mEnv->DeleteLocalRef(Ref<Cls>::mInstance);
|
||||
Ref<Cls>::mInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the JNIEnv* associated with this local reference.
|
||||
JNIEnv* Env() const
|
||||
{
|
||||
return mEnv;
|
||||
}
|
||||
|
||||
// Get the raw JNI reference that can be used as a return value.
|
||||
// Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
|
||||
auto Forget() -> decltype(Ref<Cls>(nullptr).Get())
|
||||
{
|
||||
const auto obj = Ref<Cls>::Get();
|
||||
Ref<Cls>::mInstance = nullptr;
|
||||
return obj;
|
||||
}
|
||||
|
||||
LocalRef<Cls>& operator=(LocalRef<Cls> ref)
|
||||
{
|
||||
return swap(ref);
|
||||
}
|
||||
|
||||
LocalRef<Cls>& operator=(const Ref<Cls>& ref)
|
||||
{
|
||||
LocalRef<Cls> newRef(mEnv, ref.mInstance);
|
||||
return swap(newRef);
|
||||
}
|
||||
|
||||
LocalRef<Cls>& operator=(LocalRef<GenericObject>&& ref)
|
||||
{
|
||||
LocalRef<Cls> newRef(mozilla::Forward<LocalRef<GenericObject>>(ref));
|
||||
return swap(newRef);
|
||||
}
|
||||
|
||||
LocalRef<Cls>& operator=(decltype(nullptr))
|
||||
{
|
||||
LocalRef<Cls> newRef(mEnv, nullptr);
|
||||
return swap(newRef);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class Cls>
|
||||
class GlobalRef : public Ref<Cls>
|
||||
{
|
||||
private:
|
||||
static jobject NewGlobalRef(JNIEnv* env, jobject instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!env) {
|
||||
env = GetJNIForThread();
|
||||
}
|
||||
return env->NewGlobalRef(instance);
|
||||
}
|
||||
|
||||
GlobalRef& swap(GlobalRef& other)
|
||||
{
|
||||
auto instance = other.mInstance;
|
||||
other.mInstance = Ref<Cls>::mInstance;
|
||||
Ref<Cls>::mInstance = instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
GlobalRef()
|
||||
: Ref<Cls>(nullptr)
|
||||
{}
|
||||
|
||||
// Copy constructor
|
||||
GlobalRef(const GlobalRef& ref)
|
||||
: Ref<Cls>(ref.mInstance)
|
||||
{}
|
||||
|
||||
// Move constructor
|
||||
GlobalRef(GlobalRef&& ref)
|
||||
: Ref<Cls>(ref.mInstance)
|
||||
{
|
||||
ref.mInstance = nullptr;
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT GlobalRef(const Ref<Cls>& ref)
|
||||
: Ref<Cls>(NewGlobalRef(nullptr, ref.mInstance))
|
||||
{}
|
||||
|
||||
GlobalRef(JNIEnv* env, const Ref<Cls>& ref)
|
||||
: Ref<Cls>(NewGlobalRef(env, ref.mInstance))
|
||||
{}
|
||||
|
||||
// Implicitly converts nullptr to GlobalRef.
|
||||
MOZ_IMPLICIT GlobalRef(decltype(nullptr))
|
||||
: Ref<Cls>(nullptr)
|
||||
{}
|
||||
|
||||
~GlobalRef()
|
||||
{
|
||||
if (Ref<Cls>::mInstance) {
|
||||
JNIEnv* const env = GetJNIForThread();
|
||||
env->DeleteGlobalRef(Ref<Cls>::mInstance);
|
||||
Ref<Cls>::mInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the raw JNI reference that can be used as a return value.
|
||||
// Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref.
|
||||
auto Forget() -> decltype(Ref<Cls>(nullptr).Get())
|
||||
{
|
||||
const auto obj = Ref<Cls>::Get();
|
||||
Ref<Cls>::mInstance = nullptr;
|
||||
return obj;
|
||||
}
|
||||
|
||||
GlobalRef<Cls>& operator=(GlobalRef<Cls> ref)
|
||||
{
|
||||
return swap(ref);
|
||||
}
|
||||
|
||||
GlobalRef<Cls>& operator=(const Ref<Cls>& ref)
|
||||
{
|
||||
GlobalRef<Cls> newRef(ref);
|
||||
return swap(newRef);
|
||||
}
|
||||
|
||||
GlobalRef<Cls>& operator=(decltype(nullptr))
|
||||
{
|
||||
GlobalRef<Cls> newRef(nullptr);
|
||||
return swap(newRef);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Ref specialization for jstring.
|
||||
template<>
|
||||
class Ref<String> : public RefBase<String, jstring>
|
||||
{
|
||||
friend class RefBase<String, jstring>;
|
||||
friend class jni::LocalRef<String>;
|
||||
friend class jni::GlobalRef<String>;
|
||||
|
||||
typedef RefBase<TypedObject<jstring>, jstring> Base;
|
||||
|
||||
protected:
|
||||
Ref(jobject instance) : Base(instance) {}
|
||||
|
||||
Ref(const Ref& ref) : Base(ref.mInstance) {}
|
||||
|
||||
public:
|
||||
MOZ_IMPLICIT Ref(decltype(nullptr)) : Base(nullptr) {}
|
||||
|
||||
// Get the length of the jstring.
|
||||
size_t Length() const
|
||||
{
|
||||
JNIEnv* const env = GetJNIForThread();
|
||||
return env->GetStringLength(Get());
|
||||
}
|
||||
|
||||
// Convert jstring to a nsString.
|
||||
operator nsString() const
|
||||
{
|
||||
MOZ_ASSERT(Object::mInstance);
|
||||
|
||||
JNIEnv* const env = GetJNIForThread();
|
||||
const jchar* const str = env->GetStringChars(Get(), nullptr);
|
||||
const jsize len = env->GetStringLength(Get());
|
||||
|
||||
nsString result(reinterpret_cast<const char16_t*>(str), len);
|
||||
env->ReleaseStringChars(Get(), str);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert jstring to a nsCString.
|
||||
operator nsCString() const
|
||||
{
|
||||
return NS_ConvertUTF16toUTF8(operator nsString());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Define a custom parameter type for String,
|
||||
// which accepts both String::Ref and nsAString/nsACString
|
||||
class Param<String>::Type : public Ref<String>
|
||||
{
|
||||
private:
|
||||
// Not null if we should delete ref on destruction.
|
||||
JNIEnv* const mEnv;
|
||||
|
||||
static jstring GetString(JNIEnv* env, const nsAString& str)
|
||||
{
|
||||
const jstring result = env->NewString(
|
||||
reinterpret_cast<const jchar*>(str.BeginReading()),
|
||||
str.Length());
|
||||
HandleUncaughtException(env);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
MOZ_IMPLICIT Type(const String::Ref& ref)
|
||||
: Ref<String>(ref.Get())
|
||||
, mEnv(nullptr)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Type(const nsAString& str, JNIEnv* env = GetJNIForThread())
|
||||
: Ref<String>(GetString(env, str))
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Type(const char16_t* str, JNIEnv* env = GetJNIForThread())
|
||||
: Ref<String>(GetString(env, nsDependentString(str)))
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Type(const nsACString& str, JNIEnv* env = GetJNIForThread())
|
||||
: Ref<String>(GetString(env, NS_ConvertUTF8toUTF16(str)))
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
MOZ_IMPLICIT Type(const char* str, JNIEnv* env = GetJNIForThread())
|
||||
: Ref<String>(GetString(env, NS_ConvertUTF8toUTF16(str)))
|
||||
, mEnv(env)
|
||||
{}
|
||||
|
||||
~Type()
|
||||
{
|
||||
if (mEnv) {
|
||||
mEnv->DeleteLocalRef(Get());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Support conversion from LocalRef<T>* to LocalRef<Object>*:
|
||||
// LocalRef<Foo> foo;
|
||||
// Foo::GetFoo(&foo); // error because parameter type is LocalRef<Object>*.
|
||||
// Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument.
|
||||
template<class Cls>
|
||||
class ReturnToLocal
|
||||
{
|
||||
private:
|
||||
LocalRef<Cls>* const localRef;
|
||||
LocalRef<Object> objRef;
|
||||
|
||||
public:
|
||||
explicit ReturnToLocal(LocalRef<Cls>* ref) : localRef(ref) {}
|
||||
operator LocalRef<Object>*() { return &objRef; }
|
||||
|
||||
~ReturnToLocal()
|
||||
{
|
||||
if (objRef) {
|
||||
*localRef = mozilla::Move(objRef);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Cls>
|
||||
ReturnToLocal<Cls> ReturnTo(LocalRef<Cls>* ref)
|
||||
{
|
||||
return ReturnToLocal<Cls>(ref);
|
||||
}
|
||||
|
||||
|
||||
// Support conversion from GlobalRef<T>* to LocalRef<Object/T>*:
|
||||
// GlobalRef<Foo> foo;
|
||||
// Foo::GetFoo(&foo); // error because parameter type is LocalRef<Foo>*.
|
||||
// Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument.
|
||||
template<class Cls>
|
||||
class ReturnToGlobal
|
||||
{
|
||||
private:
|
||||
GlobalRef<Cls>* const globalRef;
|
||||
LocalRef<Object> objRef;
|
||||
LocalRef<Cls> clsRef;
|
||||
|
||||
public:
|
||||
explicit ReturnToGlobal(GlobalRef<Cls>* ref) : globalRef(ref) {}
|
||||
operator LocalRef<Object>*() { return &objRef; }
|
||||
operator LocalRef<Cls>*() { return &clsRef; }
|
||||
|
||||
~ReturnToGlobal()
|
||||
{
|
||||
if (objRef) {
|
||||
*globalRef = (clsRef = mozilla::Move(objRef));
|
||||
} else if (clsRef) {
|
||||
*globalRef = clsRef;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Cls>
|
||||
ReturnToGlobal<Cls> ReturnTo(GlobalRef<Cls>* ref)
|
||||
{
|
||||
return ReturnToGlobal<Cls>(ref);
|
||||
}
|
||||
|
||||
} // namespace jni
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jni_Refs_h__
|
|
@ -0,0 +1,120 @@
|
|||
#ifndef mozilla_jni_Types_h__
|
||||
#define mozilla_jni_Types_h__
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "mozilla/jni/Refs.h"
|
||||
#include "AndroidBridge.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jni {
|
||||
namespace {
|
||||
|
||||
// TypeAdapter specializations are the interfaces between naive (C++) types such
|
||||
// as int32_t and JNI types such as jint. The template parameter T is the native
|
||||
// type, and each TypeAdapter specialization can have the following members:
|
||||
//
|
||||
// * Call: JNIEnv member pointer for making a method call that returns T.
|
||||
// * StaticCall: JNIEnv member pointer for making a static call that returns T.
|
||||
// * Get: JNIEnv member pointer for getting a field of type T.
|
||||
// * StaticGet: JNIEnv member pointer for getting a static field of type T.
|
||||
// * Set: JNIEnv member pointer for setting a field of type T.
|
||||
// * StaticGet: JNIEnv member pointer for setting a static field of type T.
|
||||
// * ToNative: static function that converts the JNI type to the native type.
|
||||
// * FromNative: static function that converts the native type to the JNI type.
|
||||
|
||||
template<typename T> struct TypeAdapter;
|
||||
|
||||
|
||||
// TypeAdapter<LocalRef<Cls>> applies when jobject is a return value.
|
||||
template<class Cls> struct TypeAdapter<LocalRef<Cls>> {
|
||||
static constexpr auto Call = &JNIEnv::CallObjectMethodA;
|
||||
static constexpr auto StaticCall = &JNIEnv::CallStaticObjectMethodA;
|
||||
static constexpr auto Get = &JNIEnv::GetObjectField;
|
||||
static constexpr auto StaticGet = &JNIEnv::GetStaticObjectField;
|
||||
|
||||
static LocalRef<Cls> ToNative(JNIEnv* env, jobject instance) {
|
||||
return LocalRef<Cls>::Adopt(env, instance);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Cls> constexpr jobject
|
||||
(JNIEnv::*TypeAdapter<LocalRef<Cls>>::Call)(jobject, jmethodID, jvalue*);
|
||||
template<class Cls> constexpr jobject
|
||||
(JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticCall)(jclass, jmethodID, jvalue*);
|
||||
template<class Cls> constexpr jobject
|
||||
(JNIEnv::*TypeAdapter<LocalRef<Cls>>::Get)(jobject, jfieldID);
|
||||
template<class Cls> constexpr jobject
|
||||
(JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticGet)(jclass, jfieldID);
|
||||
|
||||
|
||||
// TypeAdapter<Ref<Cls>> applies when jobject is a parameter value.
|
||||
template<class Cls> struct TypeAdapter<Ref<Cls>> {
|
||||
static constexpr auto Set = &JNIEnv::SetObjectField;
|
||||
static constexpr auto StaticSet = &JNIEnv::SetStaticObjectField;
|
||||
|
||||
static jobject FromNative(JNIEnv*, const Ref<Cls>& instance) {
|
||||
return instance.Get();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Cls> constexpr void
|
||||
(JNIEnv::*TypeAdapter<Ref<Cls>>::Set)(jobject, jfieldID, jobject);
|
||||
template<class Cls> constexpr void
|
||||
(JNIEnv::*TypeAdapter<Ref<Cls>>::StaticSet)(jclass, jfieldID, jobject);
|
||||
|
||||
|
||||
// jstring has its own Param type.
|
||||
template<> struct TypeAdapter<class Param<String>::Type>
|
||||
: public TypeAdapter<String::Ref>
|
||||
{};
|
||||
|
||||
|
||||
#define DEFINE_PRIMITIVE_TYPE_ADAPTER(NativeType, JNIType, JNIName) \
|
||||
\
|
||||
template<> struct TypeAdapter<NativeType> { \
|
||||
static constexpr auto Call = &JNIEnv::Call ## JNIName ## MethodA; \
|
||||
static constexpr auto StaticCall = &JNIEnv::CallStatic ## JNIName ## MethodA; \
|
||||
static constexpr auto Get = &JNIEnv::Get ## JNIName ## Field; \
|
||||
static constexpr auto StaticGet = &JNIEnv::GetStatic ## JNIName ## Field; \
|
||||
static constexpr auto Set = &JNIEnv::Set ## JNIName ## Field; \
|
||||
static constexpr auto StaticSet = &JNIEnv::SetStatic ## JNIName ## Field; \
|
||||
\
|
||||
static JNIType FromNative(JNIEnv*, NativeType val) { \
|
||||
return static_cast<JNIType>(val); \
|
||||
} \
|
||||
static NativeType ToNative(JNIEnv*, JNIType val) { \
|
||||
return static_cast<NativeType>(val); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Call) \
|
||||
(jobject, jmethodID, jvalue*); \
|
||||
constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticCall) \
|
||||
(jclass, jmethodID, jvalue*); \
|
||||
constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Get) \
|
||||
(jobject, jfieldID); \
|
||||
constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticGet) \
|
||||
(jclass, jfieldID); \
|
||||
constexpr void (JNIEnv::*TypeAdapter<NativeType>::Set) \
|
||||
(jobject, jfieldID, JNIType); \
|
||||
constexpr void (JNIEnv::*TypeAdapter<NativeType>::StaticSet) \
|
||||
(jclass, jfieldID, JNIType)
|
||||
|
||||
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(bool, jboolean, Boolean);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(int8_t, jbyte, Byte);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(char16_t, jchar, Char);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(int16_t, jshort, Short);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(int32_t, jint, Int);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(int64_t, jlong, Long);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(float, jfloat, Float);
|
||||
DEFINE_PRIMITIVE_TYPE_ADAPTER(double, jdouble, Double);
|
||||
|
||||
#undef DEFINE_PRIMITIVE_TYPE_ADAPTER
|
||||
|
||||
} // namespace
|
||||
} // namespace jni
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_jni_Types_h__
|
|
@ -0,0 +1,43 @@
|
|||
#include "Utils.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
#include "Refs.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jni {
|
||||
|
||||
bool ThrowException(JNIEnv *aEnv, const char *aClass,
|
||||
const char *aMessage)
|
||||
{
|
||||
MOZ_ASSERT(aEnv, "Invalid thread JNI env");
|
||||
|
||||
ClassObject::LocalRef cls =
|
||||
ClassObject::LocalRef::Adopt(aEnv->FindClass(aClass));
|
||||
MOZ_ASSERT(cls, "Cannot find exception class");
|
||||
|
||||
return !aEnv->ThrowNew(cls.Get(), aMessage);
|
||||
}
|
||||
|
||||
void HandleUncaughtException(JNIEnv *aEnv)
|
||||
{
|
||||
MOZ_ASSERT(aEnv, "Invalid thread JNI env");
|
||||
|
||||
if (!aEnv->ExceptionCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Throwable::LocalRef e =
|
||||
Throwable::LocalRef::Adopt(aEnv->ExceptionOccurred());
|
||||
MOZ_ASSERT(e);
|
||||
|
||||
aEnv->ExceptionClear();
|
||||
widget::GeckoAppShell::HandleUncaughtException(nullptr, e);
|
||||
|
||||
// Should be dead by now...
|
||||
MOZ_CRASH("Failed to handle uncaught exception");
|
||||
}
|
||||
|
||||
} // jni
|
||||
} // mozilla
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef mozilla_jni_Utils_h__
|
||||
#define mozilla_jni_Utils_h__
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
/* See the comment in AndroidBridge about this function before using it */
|
||||
extern "C" MOZ_EXPORT JNIEnv * GetJNIForThread();
|
||||
|
||||
namespace mozilla {
|
||||
namespace jni {
|
||||
|
||||
bool ThrowException(JNIEnv *aEnv, const char *aClass,
|
||||
const char *aMessage);
|
||||
|
||||
inline bool ThrowException(JNIEnv *aEnv, const char *aMessage)
|
||||
{
|
||||
return ThrowException(aEnv, "java/lang/Exception", aMessage);
|
||||
}
|
||||
|
||||
void HandleUncaughtException(JNIEnv *aEnv);
|
||||
|
||||
} // jni
|
||||
} // mozilla
|
||||
|
||||
#endif // mozilla_jni_Utils_h__
|
|
@ -0,0 +1,24 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
EXPORTS.mozilla.jni += [
|
||||
'Accessors.h',
|
||||
'Refs.h',
|
||||
'Types.h',
|
||||
'Utils.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'Utils.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/widget/android',
|
||||
]
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
DIRS += [
|
||||
'bindings',
|
||||
'jni',
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
|
|
Загрузка…
Ссылка в новой задаче