diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj index bca8d68e5c..151e200ddc 100644 --- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj +++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj @@ -1045,6 +1045,7 @@ 59C46E289F86C80D4341EAA3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Files.cpp"; path = "../../src/native/android/juce_android_Files.cpp"; sourceTree = "SOURCE_ROOT"; }; FA82460758BDCB2DCCE1EAAA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Fonts.cpp"; path = "../../src/native/android/juce_android_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; CE06EEED7426AA45C27B629C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_GraphicsContext.cpp"; path = "../../src/native/android/juce_android_GraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; }; + F439E6C4B2D2AF19645252C0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_android_JNIHelpers.h"; path = "../../src/native/android/juce_android_JNIHelpers.h"; sourceTree = "SOURCE_ROOT"; }; 1D74C9567283836ECC70E48B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../src/native/android/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; }; 40216CE846A54CE706131A23 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Midi.cpp"; path = "../../src/native/android/juce_android_Midi.cpp"; sourceTree = "SOURCE_ROOT"; }; E646726910F110DC34DD1662 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Misc.cpp"; path = "../../src/native/android/juce_android_Misc.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -1889,6 +1890,7 @@ 59C46E289F86C80D4341EAA3, FA82460758BDCB2DCCE1EAAA, CE06EEED7426AA45C27B629C, + F439E6C4B2D2AF19645252C0, 1D74C9567283836ECC70E48B, 40216CE846A54CE706131A23, E646726910F110DC34DD1662, diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj index a36c3cef00..315e85a692 100644 --- a/Builds/VisualStudio2005/Juce.vcproj +++ b/Builds/VisualStudio2005/Juce.vcproj @@ -951,6 +951,7 @@ + diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj index 1c2aae5792..4bf4265ce0 100644 --- a/Builds/VisualStudio2008/Juce.vcproj +++ b/Builds/VisualStudio2008/Juce.vcproj @@ -951,6 +951,7 @@ + diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj index 1c8a608a17..16212248ae 100644 --- a/Builds/VisualStudio2008_DLL/Juce.vcproj +++ b/Builds/VisualStudio2008_DLL/Juce.vcproj @@ -953,6 +953,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj index a119988e57..a2de3370d0 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj +++ b/Builds/VisualStudio2010/Juce.vcxproj @@ -794,6 +794,7 @@ + diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters index 5fc890c022..cc426e1c8f 100644 --- a/Builds/VisualStudio2010/Juce.vcxproj.filters +++ b/Builds/VisualStudio2010/Juce.vcxproj.filters @@ -2313,6 +2313,9 @@ Juce\Source\native\windows + + Juce\Source\native\android + Juce\Source\native\android diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj index 9124e3dd91..e692a5f28f 100644 --- a/Builds/iOS/Juce.xcodeproj/project.pbxproj +++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj @@ -1045,6 +1045,7 @@ 59C46E289F86C80D4341EAA3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Files.cpp"; path = "../../src/native/android/juce_android_Files.cpp"; sourceTree = "SOURCE_ROOT"; }; FA82460758BDCB2DCCE1EAAA = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Fonts.cpp"; path = "../../src/native/android/juce_android_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; }; CE06EEED7426AA45C27B629C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_GraphicsContext.cpp"; path = "../../src/native/android/juce_android_GraphicsContext.cpp"; sourceTree = "SOURCE_ROOT"; }; + F439E6C4B2D2AF19645252C0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_android_JNIHelpers.h"; path = "../../src/native/android/juce_android_JNIHelpers.h"; sourceTree = "SOURCE_ROOT"; }; 1D74C9567283836ECC70E48B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../src/native/android/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; }; 40216CE846A54CE706131A23 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Midi.cpp"; path = "../../src/native/android/juce_android_Midi.cpp"; sourceTree = "SOURCE_ROOT"; }; E646726910F110DC34DD1662 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Misc.cpp"; path = "../../src/native/android/juce_android_Misc.cpp"; sourceTree = "SOURCE_ROOT"; }; @@ -1889,6 +1890,7 @@ 59C46E289F86C80D4341EAA3, FA82460758BDCB2DCCE1EAAA, CE06EEED7426AA45C27B629C, + F439E6C4B2D2AF19645252C0, 1D74C9567283836ECC70E48B, 40216CE846A54CE706131A23, E646726910F110DC34DD1662, diff --git a/Juce.jucer b/Juce.jucer index a27b39a836..0c7db697d7 100644 --- a/Juce.jucer +++ b/Juce.jucer @@ -1478,6 +1478,8 @@ file="src/native/android/juce_android_Fonts.cpp"/> + ", "()V") \ - METHOD (stringBufferClass, stringBufferToString, "toString", "()Ljava/lang/String;") \ -\ - METHOD (httpStreamClass, httpStreamRelease, "release", "()V") \ - METHOD (httpStreamClass, httpStreamRead, "read", "([BI)I") \ - METHOD (httpStreamClass, getPosition, "getPosition", "()J") \ - METHOD (httpStreamClass, getTotalLength, "getTotalLength", "()J") \ - METHOD (httpStreamClass, isExhausted, "isExhausted", "()Z") \ - METHOD (httpStreamClass, setPosition, "setPosition", "(J)Z") \ -\ - METHOD (fileClass, fileExists, "exists", "()Z") \ - STATICMETHOD (systemClass, getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;") \ -\ - METHOD (componentPeerViewClass, setViewName, "setViewName", "(Ljava/lang/String;)V") \ - METHOD (componentPeerViewClass, layout, "layout", "(IIII)V") \ - METHOD (componentPeerViewClass, getLeft, "getLeft", "()I") \ - METHOD (componentPeerViewClass, getTop, "getTop", "()I") \ - METHOD (componentPeerViewClass, getWidth, "getWidth", "()I") \ - METHOD (componentPeerViewClass, getHeight, "getHeight", "()I") \ - METHOD (componentPeerViewClass, getLocationOnScreen, "getLocationOnScreen", "([I)V") \ - METHOD (componentPeerViewClass, bringToFront, "bringToFront", "()V") \ - METHOD (componentPeerViewClass, requestFocus, "requestFocus", "()Z") \ - METHOD (componentPeerViewClass, setVisible, "setVisible", "(Z)V") \ - METHOD (componentPeerViewClass, isVisible, "isVisible", "()Z") \ - METHOD (componentPeerViewClass, hasFocus, "hasFocus", "()Z") \ - METHOD (componentPeerViewClass, invalidate, "invalidate", "(IIII)V") \ - METHOD (componentPeerViewClass, containsPoint, "containsPoint", "(II)Z") \ -\ - METHOD (canvasClass, drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, getClipBounds2, "getClipBounds", "()Landroid/graphics/Rect;") \ -\ - METHOD (paintClass, paintClassConstructor, "", "(I)V") \ - METHOD (paintClass, setColor, "setColor", "(I)V") \ - METHOD (paintClass, setAlpha, "setAlpha", "(I)V") \ - METHOD (paintClass, setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \ - METHOD (paintClass, ascent, "ascent", "()F") \ - METHOD (paintClass, descent, "descent", "()F") \ - METHOD (paintClass, setTextSize, "setTextSize", "(F)V") \ - METHOD (paintClass, getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \ - METHOD (paintClass, setTextScaleX, "setTextScaleX", "(F)V") \ - METHOD (paintClass, getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \ -\ - METHOD (matrixClass, matrixClassConstructor, "", "()V") \ - METHOD (matrixClass, setValues, "setValues", "([F)V") \ -\ - STATICMETHOD (typefaceClass, create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \ - STATICMETHOD (typefaceClass, createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ -\ - METHOD (rectClass, rectConstructor, "", "(IIII)V") \ - FIELD (rectClass, rectLeft, "left", "I") \ - FIELD (rectClass, rectRight, "right", "I") \ - FIELD (rectClass, rectTop, "top", "I") \ - FIELD (rectClass, rectBottom, "bottom", "I") \ -\ - METHOD (audioTrackClass, audioTrackConstructor, "", "(IIIIII)V") \ - STATICMETHOD (audioTrackClass, getMinBufferSize, "getMinBufferSize", "(III)I") \ - STATICMETHOD (audioTrackClass, getNativeOutputSampleRate, "getNativeOutputSampleRate", "(I)I") \ - METHOD (audioTrackClass, audioTrackPlay, "play", "()V") \ - METHOD (audioTrackClass, audioTrackStop, "stop", "()V") \ - METHOD (audioTrackClass, audioTrackRelease, "release", "()V") \ - METHOD (audioTrackClass, audioTrackFlush, "flush", "()V") \ - METHOD (audioTrackClass, audioTrackWrite, "write", "([SII)I") \ -\ - METHOD (audioRecordClass, audioRecordConstructor, "", "(IIIII)V"); \ - STATICMETHOD (audioRecordClass, getMinRecordBufferSize, "getMinBufferSize", "(III)I") \ - METHOD (audioRecordClass, startRecording, "startRecording", "()V"); \ - METHOD (audioRecordClass, stopRecording, "stop", "()V"); \ - METHOD (audioRecordClass, audioRecordRead, "read", "([SII)I"); \ - METHOD (audioRecordClass, audioRecordRelease, "release", "()V"); \ - -// List of extra methods needed when USE_ANDROID_CANVAS is enabled -#if ! USE_ANDROID_CANVAS -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) JUCE_JNI_METHODS_ESSENTIAL(METHOD, STATICMETHOD, FIELD, STATICFIELD) -#else -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) JUCE_JNI_METHODS_ESSENTIAL(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ - METHOD (pathClass, pathClassConstructor, "", "()V") \ - METHOD (pathClass, moveTo, "moveTo", "(FF)V") \ - METHOD (pathClass, lineTo, "lineTo", "(FF)V") \ - METHOD (pathClass, quadTo, "quadTo", "(FFFF)V") \ - METHOD (pathClass, cubicTo, "cubicTo", "(FFFFFF)V") \ - METHOD (pathClass, closePath, "close", "()V") \ - METHOD (pathClass, computeBounds, "computeBounds", "(Landroid/graphics/RectF;Z)V") \ -\ - STATICMETHOD (bitmapClass, createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ - STATICFIELD (bitmapConfigClass, ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ - STATICFIELD (bitmapConfigClass, ALPHA_8, "ALPHA_8", "Landroid/graphics/Bitmap$Config;") \ - METHOD (bitmapClass, bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ - METHOD (bitmapClass, getPixels, "getPixels", "([IIIIIII)V") \ - METHOD (bitmapClass, setPixels, "setPixels", "([IIIIIII)V") \ - METHOD (bitmapClass, recycle, "recycle", "()V") \ -\ - METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ - STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ -\ - METHOD (bitmapShaderClass, bitmapShaderConstructor, "", "(Landroid/graphics/Bitmap;Landroid/graphics/Shader$TileMode;Landroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ -\ - METHOD (canvasClass, canvasBitmapConstructor, "", "(Landroid/graphics/Bitmap;)V") \ - METHOD (canvasClass, drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, translate, "translate", "(FF)V") \ - METHOD (canvasClass, clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ - METHOD (canvasClass, clipRect, "clipRect", "(FFFF)Z") \ - METHOD (canvasClass, clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ - METHOD (canvasClass, concat, "concat", "(Landroid/graphics/Matrix;)V") \ - METHOD (canvasClass, drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawBitmapAt, "drawBitmap", "(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, getClipBounds, "getClipBounds", "(Landroid/graphics/Rect;)Z") \ - METHOD (canvasClass, getMatrix, "getMatrix", "()Landroid/graphics/Matrix;") \ - METHOD (canvasClass, save, "save", "()I") \ - METHOD (canvasClass, restore, "restore", "()V") \ - METHOD (canvasClass, saveLayerAlpha, "saveLayerAlpha", "(FFFFII)I") \ -\ - METHOD (linearGradientClass, linearGradientConstructor, "", "(FFFF[I[FLandroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (radialGradientClass, radialGradientConstructor, "", "(FFF[I[FLandroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (regionClass, regionConstructor, "", "()V"); \ - METHOD (regionClass, regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ +/*** Start of inlined file: juce_android_JNIHelpers.h ***/ +#ifndef __JUCE_ANDROID_JNIHELPERS_JUCEHEADER__ +#define __JUCE_ANDROID_JNIHELPERS_JUCEHEADER__ +#ifndef USE_ANDROID_CANVAS + #define USE_ANDROID_CANVAS 0 #endif -class ThreadLocalJNIEnvHolder -{ -public: - ThreadLocalJNIEnvHolder() - : jvm (0) - { - zeromem (threads, sizeof (threads)); - zeromem (envs, sizeof (envs)); - } - - void initialise (JNIEnv* env) - { - env->GetJavaVM (&jvm); - addEnv (env); - } - - void attach() - { - JNIEnv* env = nullptr; - jvm->AttachCurrentThread (&env, 0); - - if (env != 0) - addEnv (env); - } - - void detach() - { - jvm->DetachCurrentThread(); - - const pthread_t thisThread = pthread_self(); - - SpinLock::ScopedLockType sl (addRemoveLock); - for (int i = 0; i < maxThreads; ++i) - if (threads[i] == thisThread) - threads[i] = 0; - } - - JNIEnv* get() const noexcept - { - const pthread_t thisThread = pthread_self(); - - for (int i = 0; i < maxThreads; ++i) - if (threads[i] == thisThread) - return envs[i]; - - return nullptr; - } - - enum { maxThreads = 16 }; - -private: - JavaVM* jvm; - pthread_t threads [maxThreads]; - JNIEnv* envs [maxThreads]; - SpinLock addRemoveLock; - - void addEnv (JNIEnv* env) - { - SpinLock::ScopedLockType sl (addRemoveLock); - - if (get() == 0) - { - const pthread_t thisThread = pthread_self(); - - for (int i = 0; i < maxThreads; ++i) - { - if (threads[i] == 0) - { - envs[i] = env; - threads[i] = thisThread; - return; - } - } - } - - jassertfalse; // too many threads! - } -}; - -static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; - -struct AndroidThreadScope -{ - AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } - ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } -}; - -static inline JNIEnv* getEnv() noexcept -{ - return threadLocalJNIEnvHolder.get(); -} +extern JNIEnv* getEnv() noexcept; class GlobalRef { public: - inline GlobalRef() noexcept - : obj (0) - { - } - - inline explicit GlobalRef (jobject obj_) - : obj (retain (obj_)) - { - } - - inline GlobalRef (const GlobalRef& other) - : obj (retain (other.obj)) - { - } - - ~GlobalRef() - { - clear(); - } + inline GlobalRef() noexcept : obj (0) {} + inline explicit GlobalRef (jobject obj_) : obj (retain (obj_)) {} + inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {} + ~GlobalRef() { clear(); } inline void clear() { @@ -288490,8 +288225,9 @@ public: inline GlobalRef& operator= (const GlobalRef& other) { + jobject newObj = retain (other.obj); clear(); - obj = retain (other.obj); + obj = newObj; return *this; } @@ -288541,17 +288277,11 @@ template class LocalRef { public: - explicit inline LocalRef (JavaType obj_) noexcept - : obj (obj_) - { - } - - inline LocalRef (const LocalRef& other) noexcept - : obj (retain (other.obj)) - { - } + explicit inline LocalRef (JavaType obj_) noexcept : obj (obj_){} + inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {} + ~LocalRef() { clear(); } - ~LocalRef() + void clear() { if (obj != 0) getEnv()->DeleteLocalRef (obj); @@ -288559,14 +288289,9 @@ public: LocalRef& operator= (const LocalRef& other) { - if (obj != other.obj) - { - if (obj != 0) - getEnv()->DeleteLocalRef (obj); - - obj = retain (other.obj); - } - + jobject newObj = retain (other.obj); + clear(); + obj = newObj; return *this; } @@ -288582,208 +288307,396 @@ private: } }; -static const String juceString (jstring s) +namespace { - JNIEnv* env = getEnv(); + String juceString (JNIEnv* env, jstring s) + { + jboolean isCopy; + const char* const utf8 = env->GetStringUTFChars (s, &isCopy); + CharPointer_UTF8 utf8CP (utf8); + const String result (utf8CP); + env->ReleaseStringUTFChars (s, utf8); + return result; + } - jboolean isCopy; - const char* const utf8 = env->GetStringUTFChars (s, &isCopy); - CharPointer_UTF8 utf8CP (utf8); - const String result (utf8CP); - env->ReleaseStringUTFChars (s, utf8); - return result; + String juceString (jstring s) + { + return juceString (getEnv(), s); + } + + LocalRef javaString (const String& s) + { + return LocalRef (getEnv()->NewStringUTF (s.toUTF8())); + } + + LocalRef javaStringFromChar (const juce_wchar c) + { + char utf8[8] = { 0 }; + CharPointer_UTF8 (utf8).write (c); + return LocalRef (getEnv()->NewStringUTF (utf8)); + } +} + +class JNIClassBase +{ +public: + explicit JNIClassBase (const char* classPath_); + virtual ~JNIClassBase(); + + inline operator jclass() const noexcept { return classRef; } + + static void initialiseAllClasses (JNIEnv*); + static void releaseAllClasses (JNIEnv*); + +protected: + virtual void initialiseFields (JNIEnv*) = 0; + + jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params); + jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params); + jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature); + jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature); + +private: + const char* const classPath; + jclass classRef; + + static Array& getClasses(); + void initialise (JNIEnv*); + void release (JNIEnv*); + + JUCE_DECLARE_NON_COPYABLE (JNIClassBase); +}; + +#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params); +#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params); +#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature); +#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature) fieldID = resolveStaticField (env, stringName, signature); +#define DECLARE_JNI_METHOD(methodID, stringName, params) jmethodID methodID; +#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID; + +#define DECLARE_JNI_CLASS(CppClassName, javaPath) \ + class CppClassName ## _Class : public JNIClassBase \ + { \ + public: \ + CppClassName ## _Class() : JNIClassBase (javaPath) {} \ + \ + void initialiseFields (JNIEnv* env) \ + { \ + JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \ + } \ + \ + JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \ + }; \ + static CppClassName ## _Class CppClassName; + +#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \ + extern "C" __attribute__ ((visibility("default"))) returnType Java_com_juce_ ## className ## _ ## methodName params + +class AndroidSystem +{ +public: + AndroidSystem(); + + void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir); + void shutdown (JNIEnv*); + + GlobalRef activity; + String appFile, appDataDir; + int screenWidth, screenHeight; + + jobject createPaint (Graphics::ResamplingQuality quality); + const jobject createMatrix (JNIEnv*, const AffineTransform& t); +}; + +extern AndroidSystem android; + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ + METHOD (createNewView, "createNewView", "(Z)Lcom/juce/ComponentPeerView;") \ + METHOD (deleteView, "deleteView", "(Lcom/juce/ComponentPeerView;)V") \ + METHOD (postMessage, "postMessage", "(J)V") \ + METHOD (finish, "finish", "()V") \ + METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \ + METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ + METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ + METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \ + STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;ILjava/lang/StringBuffer;)Lcom/juce/JuceAppActivity$HTTPStream;") \ + METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ + METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ + METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ + +DECLARE_JNI_CLASS (JuceAppActivity, "com/juce/JuceAppActivity"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(I)V") \ + METHOD (setColor, "setColor", "(I)V") \ + METHOD (setAlpha, "setAlpha", "(I)V") \ + METHOD (setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \ + METHOD (ascent, "ascent", "()F") \ + METHOD (descent, "descent", "()F") \ + METHOD (setTextSize, "setTextSize", "(F)V") \ + METHOD (getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \ + METHOD (setTextScaleX, "setTextScaleX", "(F)V") \ + METHOD (getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \ + METHOD (setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ + +DECLARE_JNI_CLASS (Paint, "android/graphics/Paint"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V") \ + METHOD (setValues, "setValues", "([F)V") \ + +DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(IIII)V") \ + FIELD (left, "left", "I") \ + FIELD (right, "right", "I") \ + FIELD (top, "top", "I") \ + FIELD (bottom, "bottom", "I") \ + +DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect"); +#undef JNI_CLASS_MEMBERS + +#endif // __JUCE_ANDROID_JNIHELPERS_JUCEHEADER__ + +/*** End of inlined file: juce_android_JNIHelpers.h ***/ + +#define JUCE_INCLUDED_FILE 1 + +// Now include the actual code files.. + +/*** Start of inlined file: juce_android_SystemStats.cpp ***/ +// (This file gets included by juce_android_NativeCode.cpp, rather than being +// compiled on its own). +#if JUCE_INCLUDED_FILE + +JNIClassBase::JNIClassBase (const char* classPath_) + : classPath (classPath_), classRef (0) +{ + getClasses().add (this); +} + +JNIClassBase::~JNIClassBase() +{ + getClasses().removeValue (this); +} + +Array& JNIClassBase::getClasses() +{ + static Array classes; + return classes; +} + +void JNIClassBase::initialise (JNIEnv* env) +{ + classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath)); + jassert (classRef != 0); + + initialiseFields (env); +} + +void JNIClassBase::release (JNIEnv* env) +{ + env->DeleteGlobalRef (classRef); } -static const LocalRef javaString (const String& s) +void JNIClassBase::initialiseAllClasses (JNIEnv* env) { - return LocalRef (getEnv()->NewStringUTF (s.toUTF8())); + Array& classes = getClasses(); + for (int i = classes.size(); --i >= 0;) + classes.getUnchecked(i)->initialise (env); } -static const LocalRef javaStringFromChar (const juce_wchar c) +void JNIClassBase::releaseAllClasses (JNIEnv* env) { - char utf8[5] = { 0 }; - CharPointer_UTF8 (utf8).write (c); - return LocalRef (getEnv()->NewStringUTF (utf8)); + Array& classes = getClasses(); + for (int i = classes.size(); --i >= 0;) + classes.getUnchecked(i)->release (env); } -class AndroidJavaCallbacks +jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params) +{ + jmethodID m = env->GetMethodID (classRef, methodName, params); + jassert (m != 0); + return m; +} + +jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params) +{ + jmethodID m = env->GetStaticMethodID (classRef, methodName, params); + jassert (m != 0); + return m; +} + +jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature) +{ + jfieldID f = env->GetFieldID (classRef, fieldName, signature); + jassert (f != 0); + return f; +} + +jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature) +{ + jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature); + jassert (f != 0); + return f; +} + +class ThreadLocalJNIEnvHolder { public: - AndroidJavaCallbacks() : screenWidth (0), screenHeight (0) + ThreadLocalJNIEnvHolder() + : jvm (nullptr) { + zeromem (threads, sizeof (threads)); + zeromem (envs, sizeof (envs)); } - void initialise (JNIEnv* env, jobject activity_, - jstring appFile_, jstring appDataDir_) + void initialise (JNIEnv* env) { - threadLocalJNIEnvHolder.initialise (env); - activity = GlobalRef (activity_); - appFile = juceString (appFile_); - appDataDir = juceString (appDataDir_); - - #define CREATE_JNI_CLASS(className, path) \ - className = (jclass) env->NewGlobalRef (env->FindClass (path)); \ - jassert (className != 0); - JUCE_JNI_CLASSES (CREATE_JNI_CLASS); - #undef CREATE_JNI_CLASS - - #define CREATE_JNI_METHOD(ownerClass, methodID, stringName, params) \ - methodID = env->GetMethodID (ownerClass, stringName, params); \ - jassert (methodID != 0); - #define CREATE_JNI_STATICMETHOD(ownerClass, methodID, stringName, params) \ - methodID = env->GetStaticMethodID (ownerClass, stringName, params); \ - jassert (methodID != 0); - #define CREATE_JNI_FIELD(ownerClass, fieldID, stringName, signature) \ - fieldID = env->GetFieldID (ownerClass, stringName, signature); \ - jassert (fieldID != 0); - #define CREATE_JNI_STATICFIELD(ownerClass, fieldID, stringName, signature) \ - fieldID = env->GetStaticFieldID (ownerClass, stringName, signature); \ - jassert (fieldID != 0); - JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); - #undef CREATE_JNI_METHOD + env->GetJavaVM (&jvm); + addEnv (env); } - void shutdown() + void attach() { - JNIEnv* env = getEnv(); + JNIEnv* env = nullptr; + jvm->AttachCurrentThread (&env, 0); if (env != 0) - { - #define RELEASE_JNI_CLASS(className, path) env->DeleteGlobalRef (className); - JUCE_JNI_CLASSES (RELEASE_JNI_CLASS); - #undef RELEASE_JNI_CLASS - - activity.clear(); - } + addEnv (env); } - GlobalRef activity; - String appFile, appDataDir; - int screenWidth, screenHeight; - - jobject createPaint (Graphics::ResamplingQuality quality) + void detach() { - jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/ - | 4 /*DITHER_FLAG*/ - | 128 /*SUBPIXEL_TEXT_FLAG*/; + jvm->DetachCurrentThread(); - if (quality > Graphics::lowResamplingQuality) - constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/ + const pthread_t thisThread = pthread_self(); - return getEnv()->NewObject (paintClass, paintClassConstructor, constructorFlags); + SpinLock::ScopedLockType sl (addRemoveLock); + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + threads[i] = 0; } - const jobject createMatrix (JNIEnv* env, const AffineTransform& t) + JNIEnv* get() const noexcept { - jobject m = env->NewObject (matrixClass, matrixClassConstructor); - - jfloat values[9] = { t.mat00, t.mat01, t.mat02, - t.mat10, t.mat11, t.mat12, - 0.0f, 0.0f, 1.0f }; - - jfloatArray javaArray = env->NewFloatArray (9); - env->SetFloatArrayRegion (javaArray, 0, 9, values); + const pthread_t thisThread = pthread_self(); - env->CallVoidMethod (m, setValues, javaArray); - env->DeleteLocalRef (javaArray); + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + return envs[i]; - return m; + return nullptr; } - #define DECLARE_JNI_CLASS(className, path) jclass className; - JUCE_JNI_CLASSES (DECLARE_JNI_CLASS); - #undef DECLARE_JNI_CLASS - - #define DECLARE_JNI_METHOD(ownerClass, methodID, stringName, params) jmethodID methodID; - #define DECLARE_JNI_FIELD(ownerClass, fieldID, stringName, signature) jfieldID fieldID; - JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); - #undef DECLARE_JNI_METHOD -}; + enum { maxThreads = 16 }; -static AndroidJavaCallbacks android; +private: + JavaVM* jvm; + pthread_t threads [maxThreads]; + JNIEnv* envs [maxThreads]; + SpinLock addRemoveLock; -// This is an unsatisfactory workaround for a linker warning that appeared in NDK5c. -// If anyone actually understands what this symbol is for and why the linker gets confused by it, -// please let me know! -extern "C" { void* __dso_handle = 0; } + void addEnv (JNIEnv* env) + { + SpinLock::ScopedLockType sl (addRemoveLock); -#define JUCE_INCLUDED_FILE 1 + if (get() == nullptr) + { + const pthread_t thisThread = pthread_self(); -// Now include the actual code files.. + for (int i = 0; i < maxThreads; ++i) + { + if (threads[i] == 0) + { + envs[i] = env; + threads[i] = thisThread; + return; + } + } + } -/*** Start of inlined file: juce_android_Misc.cpp ***/ -// (This file gets included by juce_android_NativeCode.cpp, rather than being -// compiled on its own). -#if JUCE_INCLUDED_FILE + jassertfalse; // too many threads! + } +}; -END_JUCE_NAMESPACE -extern JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication(); // (from START_JUCE_APPLICATION) -BEGIN_JUCE_NAMESPACE +static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; -JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, - jstring appFile, jstring appDataDir)) +JNIEnv* getEnv() noexcept { - android.initialise (env, activity, appFile, appDataDir); - - DBG (SystemStats::getJUCEVersion()); - - JUCEApplication::createInstance = &juce_CreateApplication; - - initialiseJuce_GUI(); + return threadLocalJNIEnvHolder.get(); +} - if (! JUCEApplication::createInstance()->initialiseApp (String::empty)) - exit (0); +AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0) +{ } -JUCE_JNI_CALLBACK (JuceAppActivity, quitApp, void, (JNIEnv* env, jobject activity)) +void AndroidSystem::initialise (JNIEnv* env, jobject activity_, + jstring appFile_, jstring appDataDir_) { - JUCEApplication::appWillTerminateByForce(); + JNIClassBase::initialiseAllClasses (env); - android.shutdown(); + threadLocalJNIEnvHolder.initialise (env); + activity = GlobalRef (activity_); + appFile = juceString (env, appFile_); + appDataDir = juceString (env, appDataDir_); } -void LookAndFeel::playAlertSound() +void AndroidSystem::shutdown (JNIEnv* env) { + activity.clear(); + JNIClassBase::releaseAllClasses (env); } -void Logger::outputDebugString (const String& text) +jobject AndroidSystem::createPaint (Graphics::ResamplingQuality quality) { - JNIEnv* const env = getEnv(); + jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/ + | 4 /*DITHER_FLAG*/ + | 128 /*SUBPIXEL_TEXT_FLAG*/; - if (env != nullptr) - env->CallStaticVoidMethod (android.activityClass, android.printToConsole, - javaString (text).get()); -} + if (quality > Graphics::lowResamplingQuality) + constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/ -void SystemClipboard::copyTextToClipboard (const String& text) -{ - const LocalRef t (javaString (text)); - android.activity.callVoidMethod (android.setClipboardContent, t.get()); + return getEnv()->NewObject (Paint, Paint.constructor, constructorFlags); } -String SystemClipboard::getTextFromClipboard() +const jobject AndroidSystem::createMatrix (JNIEnv* env, const AffineTransform& t) { - const LocalRef text ((jstring) android.activity.callObjectMethod (android.getClipboardContent)); - return juceString (text); -} + jobject m = env->NewObject (Matrix, Matrix.constructor); -#endif + jfloat values[9] = { t.mat00, t.mat01, t.mat02, + t.mat10, t.mat11, t.mat12, + 0.0f, 0.0f, 1.0f }; -/*** End of inlined file: juce_android_Misc.cpp ***/ + jfloatArray javaArray = env->NewFloatArray (9); + env->SetFloatArrayRegion (javaArray, 0, 9, values); + env->CallVoidMethod (m, Matrix.setValues, javaArray); + env->DeleteLocalRef (javaArray); + return m; +} -/*** Start of inlined file: juce_android_SystemStats.cpp ***/ -// (This file gets included by juce_android_NativeCode.cpp, rather than being -// compiled on its own). -#if JUCE_INCLUDED_FILE +AndroidSystem android; namespace AndroidStatsHelpers { + + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;") + + DECLARE_JNI_CLASS (SystemClass, "java/lang/System"); + #undef JNI_CLASS_MEMBERS + String getSystemProperty (const String& name) { - return juceString (LocalRef ((jstring) getEnv()->CallStaticObjectMethod (android.systemClass, - android.getProperty, + return juceString (LocalRef ((jstring) getEnv()->CallStaticObjectMethod (SystemClass, + SystemClass.getProperty, javaString (name).get()))); } } @@ -288800,11 +288713,11 @@ String SystemStats::getOperatingSystemName() bool SystemStats::isOperatingSystem64Bit() { - #if JUCE_64BIT + #if JUCE_64BIT return true; - #else + #else return false; - #endif + #endif } String SystemStats::getCpuVendor() @@ -288819,13 +288732,11 @@ int SystemStats::getCpuSpeedInMegaherz() int SystemStats::getMemorySizeInMegabytes() { - // xxx they forgot to implement sysinfo in the library, dammit! Should put this stuff back when they fix it. -/* struct sysinfo sysi; + struct sysinfo sysi; if (sysinfo (&sysi) == 0) return (sysi.totalram * sysi.mem_unit / (1024 * 1024)); - */ - DBG ("warning! memory size is unavailable due to an Android bug!"); + return 0; } @@ -288905,11 +288816,78 @@ bool Time::setSystemTimeToThisTime() const return false; } +// This is an unsatisfactory workaround for a linker warning that appeared in NDK5c. +// If anyone actually understands what this symbol is for and why the linker gets confused by it, +// please let me know! +extern "C" { void* __dso_handle = 0; } + #endif /*** End of inlined file: juce_android_SystemStats.cpp ***/ + +/*** Start of inlined file: juce_android_Misc.cpp ***/ +// (This file gets included by juce_android_NativeCode.cpp, rather than being +// compiled on its own). +#if JUCE_INCLUDED_FILE + +END_JUCE_NAMESPACE +extern JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication(); // (from START_JUCE_APPLICATION) +BEGIN_JUCE_NAMESPACE + +JUCE_JNI_CALLBACK (JuceAppActivity, launchApp, void, (JNIEnv* env, jobject activity, + jstring appFile, jstring appDataDir)) +{ + android.initialise (env, activity, appFile, appDataDir); + + DBG (SystemStats::getJUCEVersion()); + + JUCEApplication::createInstance = &juce_CreateApplication; + + initialiseJuce_GUI(); + + if (! JUCEApplication::createInstance()->initialiseApp (String::empty)) + exit (0); +} + +JUCE_JNI_CALLBACK (JuceAppActivity, quitApp, void, (JNIEnv* env, jobject activity)) +{ + JUCEApplication::appWillTerminateByForce(); + + android.shutdown (env); +} + +void LookAndFeel::playAlertSound() +{ +} + +void Logger::outputDebugString (const String& text) +{ + JNIEnv* const env = getEnv(); + + if (env != nullptr) + env->CallStaticVoidMethod (JuceAppActivity, JuceAppActivity.printToConsole, + javaString (text).get()); +} + +void SystemClipboard::copyTextToClipboard (const String& text) +{ + const LocalRef t (javaString (text)); + android.activity.callVoidMethod (JuceAppActivity.setClipboardContent, t.get()); +} + +String SystemClipboard::getTextFromClipboard() +{ + const LocalRef text ((jstring) android.activity.callObjectMethod (JuceAppActivity.getClipboardContent)); + return juceString (text); +} + +#endif + +/*** End of inlined file: juce_android_Misc.cpp ***/ + + /*** Start of inlined file: juce_posix_SharedCode.h ***/ /* This file contains posix routines that are common to both the Linux and Mac builds. @@ -289645,6 +289623,12 @@ void* threadEntryProc (void* userData) JUCE_AUTORELEASEPOOL #if JUCE_ANDROID + struct AndroidThreadScope + { + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } + }; + const AndroidThreadScope androidEnv; #endif @@ -290259,6 +290243,24 @@ void Process::lowerPrivilege() {} // compiled on its own). #if JUCE_INCLUDED_FILE +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V") \ + METHOD (toString, "toString", "()Ljava/lang/String;") \ + +DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (release, "release", "()V") \ + METHOD (read, "read", "([BI)I") \ + METHOD (getPosition, "getPosition", "()J") \ + METHOD (getTotalLength, "getTotalLength", "()J") \ + METHOD (isExhausted, "isExhausted", "()Z") \ + METHOD (setPosition, "setPosition", "(J)Z") \ + +DECLARE_JNI_CLASS (HTTPStream, "com/juce/JuceAppActivity$HTTPStream"); +#undef JNI_CLASS_MEMBERS + void MACAddress::findAllAddresses (Array& result) { // TODO @@ -290294,10 +290296,10 @@ public: env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData()); } - LocalRef responseHeaderBuffer (env->NewObject (android.stringBufferClass, android.stringBufferConstructor)); + LocalRef responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor)); - stream = GlobalRef (env->CallStaticObjectMethod (android.activityClass, - android.createHTTPStream, + stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity, + JuceAppActivity.createHTTPStream, javaString (address).get(), (jboolean) isPost, postDataArray, @@ -290314,8 +290316,8 @@ public: { LocalRef headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(), - android.stringBufferToString)); - headerLines.addLines (juceString (headersString)); + StringBuffer.toString)); + headerLines.addLines (juceString (env, headersString)); } if (responseHeaders != 0) @@ -290336,13 +290338,13 @@ public: ~WebInputStream() { if (stream != 0) - stream.callVoidMethod (android.httpStreamRelease); + stream.callVoidMethod (HTTPStream.release); } - bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (android.isExhausted); } - int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (android.getTotalLength) : 0; } - int64 getPosition() { return stream != nullptr ? stream.callLongMethod (android.getPosition) : 0; } - bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (android.setPosition, (jlong) wantedPos); } + bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); } + int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; } + int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; } + bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); } int read (void* buffer, int bytesToRead) { @@ -290353,7 +290355,7 @@ public: jbyteArray javaArray = env->NewByteArray (bytesToRead); - int numBytes = stream.callIntMethod (android.httpStreamRead, javaArray, (jint) bytesToRead); + int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead); if (numBytes > 0) env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast (buffer)); @@ -290403,7 +290405,7 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend bool MessageManager::postMessageToSystemQueue (Message* message) { message->incReferenceCount(); - getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); + getEnv()->CallVoidMethod (android.activity, JuceAppActivity.postMessage, (jlong) (pointer_sized_uint) message); return true; } @@ -290467,7 +290469,7 @@ public: void messageCallback() { - android.activity.callVoidMethod (android.finish); + android.activity.callVoidMethod (JuceAppActivity.finish); } }; @@ -290487,6 +290489,13 @@ void MessageManager::stopDispatchLoop() // compiled on its own). #if JUCE_INCLUDED_FILE +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \ + STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ + +DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface"); +#undef JNI_CLASS_MEMBERS + StringArray Font::findAllTypefaceNames() { StringArray results; @@ -290525,21 +290534,21 @@ public: File fontFile (File ("/system/fonts").getChildFile (name).withFileExtension (".ttf")); if (fontFile.exists()) - typeface = GlobalRef (env->CallStaticObjectMethod (android.typefaceClass, android.createFromFile, + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, javaString (fontFile.getFullPathName()).get())); else - typeface = GlobalRef (env->CallStaticObjectMethod (android.typefaceClass, android.create, + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, javaString (getName()).get(), flags)); - rect = GlobalRef (env->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); paint = GlobalRef (android.createPaint (Graphics::highResamplingQuality)); - const LocalRef ignored (paint.callObjectMethod (android.setTypeface, typeface.get())); + const LocalRef ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get())); const float standardSize = 256.0f; - paint.callVoidMethod (android.setTextSize, standardSize); - ascent = std::abs (paint.callFloatMethod (android.ascent)) / standardSize; - descent = paint.callFloatMethod (android.descent) / standardSize; + paint.callVoidMethod (Paint.setTextSize, standardSize); + ascent = std::abs (paint.callFloatMethod (Paint.ascent)) / standardSize; + descent = paint.callFloatMethod (Paint.descent) / standardSize; const float height = ascent + descent; unitsToHeightScaleFactor = 1.0f / 256.0f;//(height * standardSize); @@ -290554,7 +290563,7 @@ public: const int numChars = text.length(); jfloatArray widths = env->NewFloatArray (numChars); - const int numDone = paint.callIntMethod (android.getTextWidths, javaString (text).get(), widths); + const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); HeapBlock localWidths (numDone); env->GetFloatArrayRegion (widths, 0, numDone, localWidths); @@ -290573,7 +290582,7 @@ public: const int numChars = text.length(); jfloatArray widths = env->NewFloatArray (numChars); - const int numDone = paint.callIntMethod (android.getTextWidths, javaString (text).get(), widths); + const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); HeapBlock localWidths (numDone); env->GetFloatArrayRegion (widths, 0, numDone, localWidths); @@ -290602,14 +290611,14 @@ public: JNIEnv* env = getEnv(); jobject matrix = android.createMatrix (env, AffineTransform::scale (unitsToHeightScaleFactor, unitsToHeightScaleFactor).followedBy (t)); - jintArray maskData = (jintArray) android.activity.callObjectMethod (android.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get()); + jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get()); env->DeleteLocalRef (matrix); - const int left = env->GetIntField (rect.get(), android.rectLeft); - const int top = env->GetIntField (rect.get(), android.rectTop); - const int right = env->GetIntField (rect.get(), android.rectRight); - const int bottom = env->GetIntField (rect.get(), android.rectBottom); + const int left = env->GetIntField (rect.get(), RectClass.left); + const int top = env->GetIntField (rect.get(), RectClass.top); + const int right = env->GetIntField (rect.get(), RectClass.right); + const int bottom = env->GetIntField (rect.get(), RectClass.bottom); const Rectangle bounds (left, top, right - left, bottom - top); @@ -290663,6 +290672,96 @@ Typeface::Ptr Typeface::createSystemTypefaceFor (const Font& font) #if USE_ANDROID_CANVAS +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(Landroid/graphics/Bitmap;)V") \ + METHOD (drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ + METHOD (translate, "translate", "(FF)V") \ + METHOD (clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ + METHOD (clipRect, "clipRect", "(FFFF)Z") \ + METHOD (clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ + METHOD (concat, "concat", "(Landroid/graphics/Matrix;)V") \ + METHOD (drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ + METHOD (drawBitmapAt, "drawBitmap", "(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V") \ + METHOD (drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ + METHOD (drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ + METHOD (drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ + METHOD (drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ + METHOD (getClipBounds, "getClipBounds", "(Landroid/graphics/Rect;)Z") \ + METHOD (getClipBounds2, "getClipBounds", "()Landroid/graphics/Rect;") \ + METHOD (getMatrix, "getMatrix", "()Landroid/graphics/Matrix;") \ + METHOD (save, "save", "()I") \ + METHOD (restore, "restore", "()V") \ + METHOD (saveLayerAlpha, "saveLayerAlpha", "(FFFFII)I") + +DECLARE_JNI_CLASS (Canvas, "android/graphics/Canvas"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V") \ + METHOD (moveTo, "moveTo", "(FF)V") \ + METHOD (lineTo, "lineTo", "(FF)V") \ + METHOD (quadTo, "quadTo", "(FFFF)V") \ + METHOD (cubicTo, "cubicTo", "(FFFFFF)V") \ + METHOD (closePath, "close", "()V") \ + METHOD (computeBounds, "computeBounds", "(Landroid/graphics/RectF;Z)V") \ + +DECLARE_JNI_CLASS (PathClass, "android/graphics/Path"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V"); \ + METHOD (regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ + +DECLARE_JNI_CLASS (RegionClass, "android/graphics/Region"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ + METHOD (bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ + METHOD (getPixels, "getPixels", "([IIIIIII)V") \ + METHOD (setPixels, "setPixels", "([IIIIIII)V") \ + METHOD (recycle, "recycle", "()V") \ + +DECLARE_JNI_CLASS (BitmapClass, "android/graphics/Bitmap"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICFIELD (ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ + STATICFIELD (ALPHA_8, "ALPHA_8", "Landroid/graphics/Bitmap$Config;") \ + +DECLARE_JNI_CLASS (BitmapConfig, "android/graphics/Bitmap$Config"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(Landroid/graphics/Bitmap;Landroid/graphics/Shader$TileMode;Landroid/graphics/Shader$TileMode;)V") + +DECLARE_JNI_CLASS (BitmapShader, "android/graphics/BitmapShader"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") + +DECLARE_JNI_CLASS (ShaderClass, "android/graphics/Shader"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICFIELD (CLAMP, "CLAMP", "Landroid/graphics/Shader$TileMode;") + +DECLARE_JNI_CLASS (ShaderTileMode, "android/graphics/Shader$TileMode"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(FFFF[I[FLandroid/graphics/Shader$TileMode;)V") \ + +DECLARE_JNI_CLASS (LinearGradientClass, "android/graphics/LinearGradient"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(FFF[I[FLandroid/graphics/Shader$TileMode;)V") \ + +DECLARE_JNI_CLASS (RadialGradientClass, "android/graphics/RadialGradient"); +#undef JNI_CLASS_MEMBERS + class AndroidImage : public Image::SharedImage { public: @@ -290682,7 +290781,7 @@ public: ~AndroidImage() { if (bitmap != 0) - bitmap.callVoidMethod (android.recycle); + bitmap.callVoidMethod (BitmapClass.recycle); } Image::ImageType getType() const { return Image::NativeImage; } @@ -290699,8 +290798,8 @@ public: SharedImage* clone() { JNIEnv* env = getEnv(); - jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); - GlobalRef newCopy (bitmap.callObjectMethod (android.bitmapCopy, mode, true)); + jobject mode = env->GetStaticObjectField (BitmapConfig, BitmapConfig.ARGB_8888); + GlobalRef newCopy (bitmap.callObjectMethod (BitmapClass.bitmapCopy, mode, true)); env->DeleteLocalRef (mode); return new AndroidImage (width, height, newCopy); @@ -290709,8 +290808,9 @@ public: static jobject createBitmap (int width, int height, bool asSingleChannel) { JNIEnv* env = getEnv(); - jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, asSingleChannel ? android.ALPHA_8 : android.ARGB_8888); - jobject result = env->CallStaticObjectMethod (android.bitmapClass, android.createBitmap, width, height, mode); + jobject mode = env->GetStaticObjectField (BitmapConfig, asSingleChannel ? BitmapConfig.ALPHA_8 + : BitmapConfig.ARGB_8888); + jobject result = env->CallStaticObjectMethod (BitmapClass, BitmapClass.createBitmap, width, height, mode); env->DeleteLocalRef (mode); return result; } @@ -290730,7 +290830,7 @@ private: intArray = env->NewIntArray (bitmapData.width * bitmapData.height); if (mode != Image::BitmapData::writeOnly) - owner_.bitmap.callVoidMethod (android.getPixels, intArray, 0, bitmapData.width, x_, y_, + owner_.bitmap.callVoidMethod (BitmapClass.getPixels, intArray, 0, bitmapData.width, x_, y_, bitmapData.width, bitmapData.height); bitmapData.data = (uint8*) env->GetIntArrayElements (intArray, 0); @@ -290765,7 +290865,7 @@ private: env->ReleaseIntArrayElements (intArray, (jint*) bitmapData.data, 0); if (mode != Image::BitmapData::readOnly) - owner.bitmap.callVoidMethod (android.setPixels, intArray, 0, bitmapData.width, x, y, + owner.bitmap.callVoidMethod (BitmapClass.setPixels, intArray, 0, bitmapData.width, x, y, bitmapData.width, bitmapData.height); env->DeleteLocalRef (intArray); @@ -290819,12 +290919,12 @@ public: void setOrigin (int x, int y) { - getCanvas().callVoidMethod (android.translate, (float) x, (float) y); + getCanvas().callVoidMethod (Canvas.translate, (float) x, (float) y); } void addTransform (const AffineTransform& transform) { - getCanvas().callVoidMethod (android.concat, createMatrixRef (getEnv(), transform).get()); + getCanvas().callVoidMethod (Canvas.concat, createMatrixRef (getEnv(), transform).get()); } float getScaleFactor() @@ -290834,7 +290934,7 @@ public: bool clipToRectangle (const Rectangle& r) { - return getCanvas().callBooleanMethod (android.clipRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); + return getCanvas().callBooleanMethod (Canvas.clipRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } bool clipToRectangleList (const RectangleList& clipRegion) @@ -290850,13 +290950,13 @@ public: void excludeClipRectangle (const Rectangle& r) { - android.activity.callVoidMethod (android.excludeClipRegion, getCanvas().get(), + android.activity.callVoidMethod (JuceAppActivity.excludeClipRegion, getCanvas().get(), (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } void clipToPath (const Path& path, const AffineTransform& transform) { - (void) getCanvas().callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get()); + (void) getCanvas().callBooleanMethod (Canvas.clipPath, createPath (getEnv(), path, transform).get()); } void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) @@ -290873,14 +290973,14 @@ public: Rectangle bounds (getClipBounds()); jobject temporaryLayerBitmap = AndroidImage::createBitmap (bounds.getWidth(), bounds.getHeight(), false); - jobject temporaryCanvas = env->NewObject (android.canvasClass, android.canvasBitmapConstructor, temporaryLayerBitmap); + jobject temporaryCanvas = env->NewObject (Canvas, Canvas.constructor, temporaryLayerBitmap); setFill (Colours::red); - env->CallVoidMethod (temporaryCanvas, android.drawRect, + env->CallVoidMethod (temporaryCanvas, Canvas.drawRect, (jfloat) 20, (jfloat) 20, (jfloat) 300, (jfloat) 200, getCurrentPaint()); - env->CallVoidMethod (temporaryCanvas, android.translate, + env->CallVoidMethod (temporaryCanvas, Canvas.translate, (jfloat) -bounds.getX(), (jfloat) -bounds.getY()); Image maskImage (Image::SingleChannel, bounds.getWidth(), bounds.getHeight(), true); @@ -290905,12 +291005,12 @@ public: const Rectangle getClipBounds() const { JNIEnv* env = getEnv(); - jobject rect = getCanvas().callObjectMethod (android.getClipBounds2); + jobject rect = getCanvas().callObjectMethod (Canvas.getClipBounds2); - const int left = env->GetIntField (rect, android.rectLeft); - const int top = env->GetIntField (rect, android.rectTop); - const int right = env->GetIntField (rect, android.rectRight); - const int bottom = env->GetIntField (rect, android.rectBottom); + const int left = env->GetIntField (rect, RectClass.left); + const int top = env->GetIntField (rect, RectClass.top); + const int right = env->GetIntField (rect, RectClass.right); + const int bottom = env->GetIntField (rect, RectClass.bottom); env->DeleteLocalRef (rect); return Rectangle (left, top, right - left, bottom - top); @@ -290918,8 +291018,8 @@ public: bool isClipEmpty() const { - LocalRef tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); - return ! getCanvas().callBooleanMethod (android.getClipBounds, tempRect.get()); + LocalRef tempRect (getEnv()->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); + return ! getCanvas().callBooleanMethod (Canvas.getClipBounds, tempRect.get()); } void setFill (const FillType& fillType) @@ -290939,14 +291039,14 @@ public: void fillRect (const Rectangle& r, bool replaceExistingContents) { - getCanvas().callVoidMethod (android.drawRect, + getCanvas().callVoidMethod (Canvas.drawRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(), getCurrentPaint()); } void fillPath (const Path& path, const AffineTransform& transform) { - getCanvas().callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(), + getCanvas().callVoidMethod (Canvas.drawPath, createPath (getEnv(), path, transform).get(), getCurrentPaint()); } @@ -290957,7 +291057,7 @@ public: if (androidImage != 0) { JNIEnv* env = getEnv(); - getCanvas().callVoidMethod (android.drawBitmap, androidImage->bitmap.get(), + getCanvas().callVoidMethod (Canvas.drawBitmap, androidImage->bitmap.get(), createMatrixRef (env, transform).get(), getImagePaint()); } else @@ -290992,7 +291092,7 @@ public: env->ReleaseIntArrayElements (imageData, dest, 0); - getCanvas().callVoidMethod (android.drawMemoryBitmap, imageData, 0, bm.width, + getCanvas().callVoidMethod (Canvas.drawMemoryBitmap, imageData, 0, bm.width, transform.getTranslationX(), transform.getTranslationY(), bm.width, bm.height, true, getImagePaint()); env->DeleteLocalRef (imageData); @@ -291010,18 +291110,18 @@ public: void drawLine (const Line & line) { - getCanvas().callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(), + getCanvas().callVoidMethod (Canvas.drawLine, line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), getCurrentPaint()); } void drawVerticalLine (int x, float top, float bottom) { - getCanvas().callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); + getCanvas().callVoidMethod (Canvas.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); } void drawHorizontalLine (int y, float left, float right) { - getCanvas().callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); + getCanvas().callVoidMethod (Canvas.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); } void setFont (const Font& newFont) @@ -291042,7 +291142,7 @@ public: { if (transform.isOnlyTranslation()) { - getCanvas().callVoidMethod (android.drawText, javaStringFromChar ((juce_wchar) glyphNumber).get(), + getCanvas().callVoidMethod (Canvas.drawText, javaStringFromChar ((juce_wchar) glyphNumber).get(), transform.getTranslationX(), transform.getTranslationY(), currentState->getPaintForTypeface()); } @@ -291057,7 +291157,7 @@ public: void saveState() { - (void) getCanvas().callIntMethod (android.save); + (void) getCanvas().callIntMethod (Canvas.save); stateStack.add (new SavedState (*currentState)); } @@ -291077,14 +291177,14 @@ public: jassertfalse; // trying to pop with an empty stack! } - getCanvas().callVoidMethod (android.restore); + getCanvas().callVoidMethod (Canvas.restore); } void beginTransparencyLayer (float opacity) { Rectangle clip (getClipBounds()); - (void) getCanvas().callIntMethod (android.saveLayerAlpha, + (void) getCanvas().callIntMethod (Canvas.saveLayerAlpha, (float) clip.getX(), (float) clip.getY(), (float) clip.getRight(), @@ -291148,8 +291248,8 @@ public: if (fillType.isColour()) { - env->DeleteLocalRef (paint.callObjectMethod (android.setShader, (jobject) 0)); - paint.callVoidMethod (android.setColor, colourToInt (fillType.colour)); + env->DeleteLocalRef (paint.callObjectMethod (Paint.setShader, (jobject) 0)); + paint.callVoidMethod (Paint.setColor, colourToInt (fillType.colour)); } else if (fillType.isGradient()) { @@ -291175,13 +291275,13 @@ public: env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData()); } - jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); + jobject tileMode = env->GetStaticObjectField (ShaderTileMode, ShaderTileMode.CLAMP); jobject shader; if (fillType.gradient->isRadial) { - shader = env->NewObject (android.radialGradientClass, - android.radialGradientConstructor, + shader = env->NewObject (RadialGradientClass, + RadialGradientClass.constructor, p1.getX(), p1.getY(), p1.getDistanceFrom (p2), coloursArray, positionsArray, @@ -291189,8 +291289,8 @@ public: } else { - shader = env->NewObject (android.linearGradientClass, - android.linearGradientConstructor, + shader = env->NewObject (LinearGradientClass, + LinearGradientClass.constructor, p1.getX(), p1.getY(), p2.getX(), p2.getY(), coloursArray, positionsArray, tileMode); @@ -291200,8 +291300,8 @@ public: env->DeleteLocalRef (coloursArray); env->DeleteLocalRef (positionsArray); - env->CallVoidMethod (shader, android.setLocalMatrix, createMatrixRef (env, fillType.transform).get()); - env->DeleteLocalRef (paint.callObjectMethod (android.setShader, shader)); + env->CallVoidMethod (shader, ShaderClass.setLocalMatrix, createMatrixRef (env, fillType.transform).get()); + env->DeleteLocalRef (paint.callObjectMethod (Paint.setShader, shader)); env->DeleteLocalRef (shader); } @@ -291226,17 +291326,17 @@ public: if (atf != 0) { - paint.callObjectMethod (android.setTypeface, atf->typeface.get()); - paint.callVoidMethod (android.setTextSize, font.getHeight()); + paint.callObjectMethod (Paint.setTypeface, atf->typeface.get()); + paint.callVoidMethod (Paint.setTextSize, font.getHeight()); const float hScale = font.getHorizontalScale(); if (hScale < 0.99f || hScale > 1.01f) - paint.callVoidMethod (android.setTextScaleX, hScale); + paint.callVoidMethod (Paint.setTextScaleX, hScale); } fillNeedsUpdate = true; - paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + paint.callVoidMethod (Paint.setAlpha, (jint) fillType.colour.getAlpha()); } return p; @@ -291245,7 +291345,7 @@ public: jobject getImagePaint() { jobject p = getPaint(); - paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + paint.callVoidMethod (Paint.setAlpha, (jint) fillType.colour.getAlpha()); fillNeedsUpdate = true; return p; } @@ -291258,27 +291358,27 @@ public: { JNIEnv* env = getEnv(); - jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); - jobject shader = env->NewObject (android.bitmapShaderClass, android.bitmapShaderConstructor, + jobject tileMode = env->GetStaticObjectField (ShaderTileMode, ShaderTileMode.CLAMP); + jobject shader = env->NewObject (BitmapShader, BitmapShader.constructor, temporaryLayerBitmap.get(), tileMode, tileMode); env->DeleteLocalRef (tileMode); jobject compositingPaint = android.createPaint (quality); - env->CallObjectMethod (compositingPaint, android.setShader, shader); + env->CallObjectMethod (compositingPaint, Paint.setShader, shader); env->DeleteLocalRef (shader); LocalRef maskBitmap (createAlphaBitmap (env, maskImage)); maskImage = Image::null; - env->CallVoidMethod (previousCanvas, android.drawBitmapAt, + env->CallVoidMethod (previousCanvas, Canvas.drawBitmapAt, maskBitmap.get(), (jfloat) maskLayerX, (jfloat) maskLayerY, compositingPaint); env->DeleteLocalRef (compositingPaint); canvas = GlobalRef (previousCanvas); - env->CallVoidMethod (temporaryLayerBitmap.get(), android.recycle); - env->CallVoidMethod (maskBitmap.get(), android.recycle); + env->CallVoidMethod (temporaryLayerBitmap.get(), BitmapClass.recycle); + env->CallVoidMethod (maskBitmap.get(), BitmapClass.recycle); temporaryLayerBitmap.clear(); } @@ -291321,7 +291421,7 @@ public: } env->ReleaseIntArrayElements (intArray, (jint*) dest, 0); - env->CallVoidMethod (bitmap, android.setPixels, intArray, 0, bm.width, 0, 0, bm.width, bm.height); + env->CallVoidMethod (bitmap, BitmapClass.setPixels, intArray, 0, bm.width, 0, 0, bm.width, bm.height); env->DeleteLocalRef (intArray); return bitmap; } @@ -291348,9 +291448,9 @@ private: jobject getCurrentPaint() const { return currentState->getPaint(); } jobject getImagePaint() const { return currentState->getImagePaint(); } - static const LocalRef createPath (JNIEnv* env, const Path& path) + static LocalRef createPath (JNIEnv* env, const Path& path) { - jobject p = env->NewObject (android.pathClass, android.pathClassConstructor); + jobject p = env->NewObject (PathClass, PathClass.constructor); Path::Iterator i (path); @@ -291358,11 +291458,11 @@ private: { switch (i.elementType) { - case Path::Iterator::startNewSubPath: env->CallVoidMethod (p, android.moveTo, i.x1, i.y1); break; - case Path::Iterator::lineTo: env->CallVoidMethod (p, android.lineTo, i.x1, i.y1); break; - case Path::Iterator::quadraticTo: env->CallVoidMethod (p, android.quadTo, i.x1, i.y1, i.x2, i.y2); break; - case Path::Iterator::cubicTo: env->CallVoidMethod (p, android.cubicTo, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; - case Path::Iterator::closePath: env->CallVoidMethod (p, android.closePath); break; + case Path::Iterator::startNewSubPath: env->CallVoidMethod (p, PathClass.moveTo, i.x1, i.y1); break; + case Path::Iterator::lineTo: env->CallVoidMethod (p, PathClass.lineTo, i.x1, i.y1); break; + case Path::Iterator::quadraticTo: env->CallVoidMethod (p, PathClass.quadTo, i.x1, i.y1, i.x2, i.y2); break; + case Path::Iterator::cubicTo: env->CallVoidMethod (p, PathClass.cubicTo, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; + case Path::Iterator::closePath: env->CallVoidMethod (p, PathClass.closePath); break; default: jassertfalse; break; } } @@ -291370,7 +291470,7 @@ private: return LocalRef (p); } - static const LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) + static LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) { if (transform.isIdentity()) return createPath (env, path); @@ -291380,25 +291480,25 @@ private: return createPath (env, tempPath); } - static const LocalRef createMatrixRef (JNIEnv* env, const AffineTransform& t) + static LocalRef createMatrixRef (JNIEnv* env, const AffineTransform& t) { - return LocalRef (android.createMatrix (*env, t)); + return LocalRef (android.createMatrix (env, t)); } - static const LocalRef createRect (JNIEnv* env, const Rectangle& r) + static LocalRef createRect (JNIEnv* env, const Rectangle& r) { - return LocalRef (env->NewObject (android.rectClass, android.rectConstructor, + return LocalRef (env->NewObject (RectClass, RectClass.constructor, r.getX(), r.getY(), r.getRight(), r.getBottom())); } - static const LocalRef createRegion (JNIEnv* env, const RectangleList& list) + static LocalRef createRegion (JNIEnv* env, const RectangleList& list) { - jobject region = env->NewObject (android.regionClass, android.regionConstructor); + jobject region = env->NewObject (RegionClass, RegionClass.constructor); const int numRects = list.getNumRectangles(); for (int i = 0; i < numRects; ++i) - env->CallBooleanMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get()); + env->CallBooleanMethod (region, RegionClass.regionUnion, createRect (env, list.getRectangle(i)).get()); return LocalRef (region); } @@ -291423,7 +291523,7 @@ private: LowLevelGraphicsContext* AndroidImage::createLowLevelContext() { - jobject canvas = getEnv()->NewObject (android.canvasClass, android.canvasBitmapConstructor, bitmap.get()); + jobject canvas = getEnv()->NewObject (Canvas, Canvas.constructor, bitmap.get()); return new AndroidLowLevelGraphicsContext (canvas); } #endif @@ -291438,13 +291538,39 @@ LowLevelGraphicsContext* AndroidImage::createLowLevelContext() // compiled on its own). #if JUCE_INCLUDED_FILE +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ + METHOD (getClipBounds, "getClipBounds", "()Landroid/graphics/Rect;") + +DECLARE_JNI_CLASS (CanvasMinimal, "android/graphics/Canvas"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (setViewName, "setViewName", "(Ljava/lang/String;)V") \ + METHOD (layout, "layout", "(IIII)V") \ + METHOD (getLeft, "getLeft", "()I") \ + METHOD (getTop, "getTop", "()I") \ + METHOD (getWidth, "getWidth", "()I") \ + METHOD (getHeight, "getHeight", "()I") \ + METHOD (getLocationOnScreen, "getLocationOnScreen", "([I)V") \ + METHOD (bringToFront, "bringToFront", "()V") \ + METHOD (requestFocus, "requestFocus", "()Z") \ + METHOD (setVisible, "setVisible", "(Z)V") \ + METHOD (isVisible, "isVisible", "()Z") \ + METHOD (hasFocus, "hasFocus", "()Z") \ + METHOD (invalidate, "invalidate", "(IIII)V") \ + METHOD (containsPoint, "containsPoint", "(II)Z") \ + +DECLARE_JNI_CLASS (ComponentPeerView, "com/juce/ComponentPeerView"); +#undef JNI_CLASS_MEMBERS + class AndroidComponentPeer : public ComponentPeer { public: AndroidComponentPeer (Component* const component, const int windowStyleFlags) : ComponentPeer (component, windowStyleFlags), - view (android.activity.callObjectMethod (android.createNewView, component->isOpaque())), + view (android.activity.callObjectMethod (JuceAppActivity.createNewView, component->isOpaque())), usingAndroidGraphics (false), fullScreen (false), sizeAllocated (0) @@ -291457,7 +291583,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - android.activity.callVoidMethod (android.deleteView, view.get()); + android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get()); } else { @@ -291472,7 +291598,7 @@ public: void messageCallback() { - android.activity.callVoidMethod (android.deleteView, view.get()); + android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get()); } private: @@ -291494,7 +291620,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - view.callVoidMethod (android.setVisible, shouldBeVisible); + view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); } else { @@ -291509,7 +291635,7 @@ public: void messageCallback() { - view.callVoidMethod (android.setVisible, shouldBeVisible); + view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); } private: @@ -291523,7 +291649,7 @@ public: void setTitle (const String& title) { - view.callVoidMethod (android.setViewName, javaString (title).get()); + view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get()); } void setPosition (int x, int y) @@ -291546,7 +291672,7 @@ public: w = jmax (0, w); h = jmax (0, h); - view.callVoidMethod (android.layout, x, y, x + w, y + h); + view.callVoidMethod (ComponentPeerView.layout, x, y, x + w, y + h); } else { @@ -291561,7 +291687,7 @@ public: void messageCallback() { - view.callVoidMethod (android.layout, x, y, x + w, y + h); + view.callVoidMethod (ComponentPeerView.layout, x, y, x + w, y + h); } private: @@ -291575,16 +291701,16 @@ public: const Rectangle getBounds() const { - return Rectangle (view.callIntMethod (android.getLeft), - view.callIntMethod (android.getTop), - view.callIntMethod (android.getWidth), - view.callIntMethod (android.getHeight)); + return Rectangle (view.callIntMethod (ComponentPeerView.getLeft), + view.callIntMethod (ComponentPeerView.getTop), + view.callIntMethod (ComponentPeerView.getWidth), + view.callIntMethod (ComponentPeerView.getHeight)); } const Point getScreenPosition() const { - return Point (view.callIntMethod (android.getLeft), - view.callIntMethod (android.getTop)); + return Point (view.callIntMethod (ComponentPeerView.getLeft), + view.callIntMethod (ComponentPeerView.getTop)); } const Point localToGlobal (const Point& relativePosition) @@ -291636,7 +291762,8 @@ public: { return isPositiveAndBelow (position.getX(), component->getWidth()) && isPositiveAndBelow (position.getY(), component->getHeight()) - && ((! trueIfInAChildWindow) || view.callBooleanMethod (android.containsPoint, position.getX(), position.getY())); + && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, + position.getX(), position.getY())); } const BorderSize getFrameSize() const @@ -291653,7 +291780,7 @@ public: void toFront (bool makeActive) { - view.callVoidMethod (android.bringToFront); + view.callVoidMethod (ComponentPeerView.bringToFront); if (makeActive) grabFocus(); @@ -291690,12 +291817,12 @@ public: bool isFocused() const { - return view.callBooleanMethod (android.hasFocus); + return view.callBooleanMethod (ComponentPeerView.hasFocus); } void grabFocus() { - view.callBooleanMethod (android.requestFocus); + view.callBooleanMethod (ComponentPeerView.requestFocus); } void handleFocusChangeCallback (bool hasFocus) @@ -291713,20 +291840,20 @@ public: void handlePaintCallback (JNIEnv* env, jobject canvas) { -#if USE_ANDROID_CANVAS + #if USE_ANDROID_CANVAS if (usingAndroidGraphics) { AndroidLowLevelGraphicsContext g (canvas); handlePaint (g); } else -#endif + #endif { - jobject rect = env->CallObjectMethod (canvas, android.getClipBounds2); - const int left = env->GetIntField (rect, android.rectLeft); - const int top = env->GetIntField (rect, android.rectTop); - const int right = env->GetIntField (rect, android.rectRight); - const int bottom = env->GetIntField (rect, android.rectBottom); + jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds); + const int left = env->GetIntField (rect, RectClass.left); + const int top = env->GetIntField (rect, RectClass.top); + const int right = env->GetIntField (rect, RectClass.right); + const int bottom = env->GetIntField (rect, RectClass.bottom); env->DeleteLocalRef (rect); const Rectangle clip (left, top, right - left, bottom - top); @@ -291756,7 +291883,7 @@ public: env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0); - env->CallVoidMethod (canvas, android.drawMemoryBitmap, (jintArray) buffer.get(), 0, clip.getWidth(), + env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(), (jfloat) clip.getX(), (jfloat) clip.getY(), clip.getWidth(), clip.getHeight(), true, (jobject) 0); } @@ -291767,7 +291894,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - view.callVoidMethod (android.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); + view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); } else { @@ -291782,7 +291909,7 @@ public: void messageCallback() { - view.callVoidMethod (android.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); + view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); } private: @@ -291914,25 +292041,16 @@ Point AndroidComponentPeer::lastMousePos; JUCE_JNI_CALLBACK (ComponentPeerView, javaMethodName, returnType, params) \ { \ AndroidComponentPeer* const peer = AndroidComponentPeer::findPeerForJavaView (view); \ - if (peer != 0) \ + if (peer != nullptr) \ peer->juceMethodInvocation; \ } -JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), - handlePaintCallback (env, canvas)) - -JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseDownCallback ((float) x, (float) y, (int64) time)) -JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseDragCallback ((float) x, (float) y, (int64) time)) -JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseUpCallback ((float) x, (float) y, (int64) time)) - -JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), - handleMovedOrResized()) - -JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), - handleFocusChangeCallback (hasFocus)) +JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), handlePaintCallback (env, canvas)) +JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseDownCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseDragCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseUpCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), handleMovedOrResized()) +JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), handleFocusChangeCallback (hasFocus)) ComponentPeer* Component::createNewPeer (int styleFlags, void*) { @@ -291993,7 +292111,7 @@ void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIcon const String& title, const String& message, Component* associatedComponent) { - android.activity.callVoidMethod (android.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0); + android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0); } bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType, @@ -292003,7 +292121,7 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType { jassert (callback != 0); // on android, all alerts must be non-modal!! - android.activity.callVoidMethod (android.showOkCancelBox, javaString (title).get(), javaString (message).get(), + android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(), javaString (message).get(), (jlong) (pointer_sized_int) callback); return false; } @@ -292015,7 +292133,7 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy { jassert (callback != 0); // on android, all alerts must be non-modal!! - android.activity.callVoidMethod (android.showYesNoCancelBox, javaString (title).get(), javaString (message).get(), + android.activity.callVoidMethod (JuceAppActivity.showYesNoCancelBox, javaString (title).get(), javaString (message).get(), (jlong) (pointer_sized_int) callback); return 0; } @@ -292373,6 +292491,30 @@ MidiInput* MidiInput::openDevice (int index, MidiInputCallback* callback) // compiled on its own). #if JUCE_INCLUDED_FILE +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \ + STATICMETHOD (getNativeOutputSampleRate, "getNativeOutputSampleRate", "(I)I") \ + METHOD (constructor, "", "(IIIIII)V") \ + METHOD (play, "play", "()V") \ + METHOD (stop, "stop", "()V") \ + METHOD (release, "release", "()V") \ + METHOD (flush, "flush", "()V") \ + METHOD (write, "write", "([SII)I") \ + +DECLARE_JNI_CLASS (AudioTrack, "android/media/AudioTrack"); +#undef JNI_CLASS_MEMBERS + +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \ + METHOD (constructor, "", "(IIIII)V"); \ + METHOD (startRecording, "startRecording", "()V"); \ + METHOD (stop, "stop", "()V"); \ + METHOD (read, "read", "([SII)I"); \ + METHOD (release, "release", "()V"); \ + +DECLARE_JNI_CLASS (AudioRecord, "android/media/AudioRecord"); +#undef JNI_CLASS_MEMBERS + #define CHANNEL_OUT_STEREO ((jint) 12) #define CHANNEL_IN_STEREO ((jint) 12) #define CHANNEL_IN_MONO ((jint) 16) @@ -292397,14 +292539,14 @@ public: inputChannelBuffer (1, 1) { JNIEnv* env = getEnv(); - sampleRate = env->CallStaticIntMethod (android.audioTrackClass, android.getNativeOutputSampleRate, MODE_STREAM); + sampleRate = env->CallStaticIntMethod (AudioTrack, AudioTrack.getNativeOutputSampleRate, MODE_STREAM); - const jint outMinBuffer = env->CallStaticIntMethod (android.audioTrackClass, android.getMinBufferSize, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT); + const jint outMinBuffer = env->CallStaticIntMethod (AudioTrack, AudioTrack.getMinBufferSize, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT); - jint inMinBuffer = env->CallStaticIntMethod (android.audioRecordClass, android.getMinRecordBufferSize, sampleRate, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT); + jint inMinBuffer = env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT); if (inMinBuffer <= 0) { - inMinBuffer = env->CallStaticIntMethod (android.audioRecordClass, android.getMinRecordBufferSize, sampleRate, CHANNEL_IN_MONO, ENCODING_PCM_16BIT); + inMinBuffer = env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_MONO, ENCODING_PCM_16BIT); if (inMinBuffer > 0) numDeviceInputChannelsAvailable = 1; @@ -292490,7 +292632,7 @@ public: if (numClientOutputChannels > 0) { numDeviceOutputChannels = 2; - outputDevice = GlobalRef (env->NewObject (android.audioTrackClass, android.audioTrackConstructor, + outputDevice = GlobalRef (env->NewObject (AudioTrack, AudioTrack.constructor, STREAM_MUSIC, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT, (jint) (actualBufferSize * numDeviceOutputChannels * sizeof (float)), MODE_STREAM)); isRunning = true; @@ -292499,7 +292641,7 @@ public: if (numClientInputChannels > 0 && numDeviceInputChannelsAvailable > 0) { numDeviceInputChannels = jmin (numClientInputChannels, numDeviceInputChannelsAvailable); - inputDevice = GlobalRef (env->NewObject (android.audioRecordClass, android.audioRecordConstructor, + inputDevice = GlobalRef (env->NewObject (AudioRecord, AudioRecord.constructor, 0 /* (default audio source) */, sampleRate, numDeviceInputChannelsAvailable > 1 ? CHANNEL_IN_STEREO : CHANNEL_IN_MONO, ENCODING_PCM_16BIT, @@ -292510,10 +292652,10 @@ public: if (isRunning) { if (outputDevice != nullptr) - env->CallVoidMethod (outputDevice, android.audioTrackPlay); + env->CallVoidMethod (outputDevice, AudioTrack.play); if (inputDevice != nullptr) - env->CallVoidMethod (inputDevice, android.startRecording); + env->CallVoidMethod (inputDevice, AudioRecord.startRecording); startThread (8); } @@ -292584,7 +292726,7 @@ public: { if (inputDevice != nullptr) { - jint numRead = env->CallIntMethod (inputDevice, android.audioRecordRead, audioBuffer, 0, actualBufferSize * numDeviceInputChannels); + jint numRead = env->CallIntMethod (inputDevice, AudioRecord.read, audioBuffer, 0, actualBufferSize * numDeviceInputChannels); if (numRead < actualBufferSize * numDeviceInputChannels) { @@ -292636,7 +292778,7 @@ public: } env->ReleaseShortArrayElements (audioBuffer, dest, 0); - jint numWritten = env->CallIntMethod (outputDevice, android.audioTrackWrite, audioBuffer, 0, actualBufferSize * numDeviceOutputChannels); + jint numWritten = env->CallIntMethod (outputDevice, AudioTrack.write, audioBuffer, 0, actualBufferSize * numDeviceOutputChannels); if (numWritten < actualBufferSize * numDeviceOutputChannels) { @@ -292664,15 +292806,15 @@ private: { if (outputDevice != nullptr) { - outputDevice.callVoidMethod (android.audioTrackStop); - outputDevice.callVoidMethod (android.audioTrackRelease); + outputDevice.callVoidMethod (AudioTrack.stop); + outputDevice.callVoidMethod (AudioTrack.release); outputDevice.clear(); } if (inputDevice != nullptr) { - inputDevice.callVoidMethod (android.stopRecording); - inputDevice.callVoidMethod (android.audioRecordRelease); + inputDevice.callVoidMethod (AudioRecord.stop); + inputDevice.callVoidMethod (AudioRecord.release); inputDevice.clear(); } } diff --git a/src/native/android/juce_android_Audio.cpp b/src/native/android/juce_android_Audio.cpp index d7af4bf98a..c85534ded5 100644 --- a/src/native/android/juce_android_Audio.cpp +++ b/src/native/android/juce_android_Audio.cpp @@ -27,6 +27,32 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \ + STATICMETHOD (getNativeOutputSampleRate, "getNativeOutputSampleRate", "(I)I") \ + METHOD (constructor, "", "(IIIIII)V") \ + METHOD (play, "play", "()V") \ + METHOD (stop, "stop", "()V") \ + METHOD (release, "release", "()V") \ + METHOD (flush, "flush", "()V") \ + METHOD (write, "write", "([SII)I") \ + +DECLARE_JNI_CLASS (AudioTrack, "android/media/AudioTrack"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getMinBufferSize, "getMinBufferSize", "(III)I") \ + METHOD (constructor, "", "(IIIII)V"); \ + METHOD (startRecording, "startRecording", "()V"); \ + METHOD (stop, "stop", "()V"); \ + METHOD (read, "read", "([SII)I"); \ + METHOD (release, "release", "()V"); \ + +DECLARE_JNI_CLASS (AudioRecord, "android/media/AudioRecord"); +#undef JNI_CLASS_MEMBERS + //============================================================================== #define CHANNEL_OUT_STEREO ((jint) 12) #define CHANNEL_IN_STEREO ((jint) 12) @@ -53,14 +79,14 @@ public: inputChannelBuffer (1, 1) { JNIEnv* env = getEnv(); - sampleRate = env->CallStaticIntMethod (android.audioTrackClass, android.getNativeOutputSampleRate, MODE_STREAM); + sampleRate = env->CallStaticIntMethod (AudioTrack, AudioTrack.getNativeOutputSampleRate, MODE_STREAM); - const jint outMinBuffer = env->CallStaticIntMethod (android.audioTrackClass, android.getMinBufferSize, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT); + const jint outMinBuffer = env->CallStaticIntMethod (AudioTrack, AudioTrack.getMinBufferSize, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT); - jint inMinBuffer = env->CallStaticIntMethod (android.audioRecordClass, android.getMinRecordBufferSize, sampleRate, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT); + jint inMinBuffer = env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_STEREO, ENCODING_PCM_16BIT); if (inMinBuffer <= 0) { - inMinBuffer = env->CallStaticIntMethod (android.audioRecordClass, android.getMinRecordBufferSize, sampleRate, CHANNEL_IN_MONO, ENCODING_PCM_16BIT); + inMinBuffer = env->CallStaticIntMethod (AudioRecord, AudioRecord.getMinBufferSize, sampleRate, CHANNEL_IN_MONO, ENCODING_PCM_16BIT); if (inMinBuffer > 0) numDeviceInputChannelsAvailable = 1; @@ -146,7 +172,7 @@ public: if (numClientOutputChannels > 0) { numDeviceOutputChannels = 2; - outputDevice = GlobalRef (env->NewObject (android.audioTrackClass, android.audioTrackConstructor, + outputDevice = GlobalRef (env->NewObject (AudioTrack, AudioTrack.constructor, STREAM_MUSIC, sampleRate, CHANNEL_OUT_STEREO, ENCODING_PCM_16BIT, (jint) (actualBufferSize * numDeviceOutputChannels * sizeof (float)), MODE_STREAM)); isRunning = true; @@ -155,7 +181,7 @@ public: if (numClientInputChannels > 0 && numDeviceInputChannelsAvailable > 0) { numDeviceInputChannels = jmin (numClientInputChannels, numDeviceInputChannelsAvailable); - inputDevice = GlobalRef (env->NewObject (android.audioRecordClass, android.audioRecordConstructor, + inputDevice = GlobalRef (env->NewObject (AudioRecord, AudioRecord.constructor, 0 /* (default audio source) */, sampleRate, numDeviceInputChannelsAvailable > 1 ? CHANNEL_IN_STEREO : CHANNEL_IN_MONO, ENCODING_PCM_16BIT, @@ -166,10 +192,10 @@ public: if (isRunning) { if (outputDevice != nullptr) - env->CallVoidMethod (outputDevice, android.audioTrackPlay); + env->CallVoidMethod (outputDevice, AudioTrack.play); if (inputDevice != nullptr) - env->CallVoidMethod (inputDevice, android.startRecording); + env->CallVoidMethod (inputDevice, AudioRecord.startRecording); startThread (8); } @@ -240,7 +266,7 @@ public: { if (inputDevice != nullptr) { - jint numRead = env->CallIntMethod (inputDevice, android.audioRecordRead, audioBuffer, 0, actualBufferSize * numDeviceInputChannels); + jint numRead = env->CallIntMethod (inputDevice, AudioRecord.read, audioBuffer, 0, actualBufferSize * numDeviceInputChannels); if (numRead < actualBufferSize * numDeviceInputChannels) { @@ -292,7 +318,7 @@ public: } env->ReleaseShortArrayElements (audioBuffer, dest, 0); - jint numWritten = env->CallIntMethod (outputDevice, android.audioTrackWrite, audioBuffer, 0, actualBufferSize * numDeviceOutputChannels); + jint numWritten = env->CallIntMethod (outputDevice, AudioTrack.write, audioBuffer, 0, actualBufferSize * numDeviceOutputChannels); if (numWritten < actualBufferSize * numDeviceOutputChannels) { @@ -320,15 +346,15 @@ private: { if (outputDevice != nullptr) { - outputDevice.callVoidMethod (android.audioTrackStop); - outputDevice.callVoidMethod (android.audioTrackRelease); + outputDevice.callVoidMethod (AudioTrack.stop); + outputDevice.callVoidMethod (AudioTrack.release); outputDevice.clear(); } if (inputDevice != nullptr) { - inputDevice.callVoidMethod (android.stopRecording); - inputDevice.callVoidMethod (android.audioRecordRelease); + inputDevice.callVoidMethod (AudioRecord.stop); + inputDevice.callVoidMethod (AudioRecord.release); inputDevice.clear(); } } diff --git a/src/native/android/juce_android_Fonts.cpp b/src/native/android/juce_android_Fonts.cpp index b1781a3c8b..459a7a3e9e 100644 --- a/src/native/android/juce_android_Fonts.cpp +++ b/src/native/android/juce_android_Fonts.cpp @@ -27,6 +27,14 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \ + STATICMETHOD (createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ + +DECLARE_JNI_CLASS (TypefaceClass, "android/graphics/Typeface"); +#undef JNI_CLASS_MEMBERS + //============================================================================== StringArray Font::findAllTypefaceNames() @@ -68,21 +76,21 @@ public: File fontFile (File ("/system/fonts").getChildFile (name).withFileExtension (".ttf")); if (fontFile.exists()) - typeface = GlobalRef (env->CallStaticObjectMethod (android.typefaceClass, android.createFromFile, + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.createFromFile, javaString (fontFile.getFullPathName()).get())); else - typeface = GlobalRef (env->CallStaticObjectMethod (android.typefaceClass, android.create, + typeface = GlobalRef (env->CallStaticObjectMethod (TypefaceClass, TypefaceClass.create, javaString (getName()).get(), flags)); - rect = GlobalRef (env->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); + rect = GlobalRef (env->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); paint = GlobalRef (android.createPaint (Graphics::highResamplingQuality)); - const LocalRef ignored (paint.callObjectMethod (android.setTypeface, typeface.get())); + const LocalRef ignored (paint.callObjectMethod (Paint.setTypeface, typeface.get())); const float standardSize = 256.0f; - paint.callVoidMethod (android.setTextSize, standardSize); - ascent = std::abs (paint.callFloatMethod (android.ascent)) / standardSize; - descent = paint.callFloatMethod (android.descent) / standardSize; + paint.callVoidMethod (Paint.setTextSize, standardSize); + ascent = std::abs (paint.callFloatMethod (Paint.ascent)) / standardSize; + descent = paint.callFloatMethod (Paint.descent) / standardSize; const float height = ascent + descent; unitsToHeightScaleFactor = 1.0f / 256.0f;//(height * standardSize); @@ -97,7 +105,7 @@ public: const int numChars = text.length(); jfloatArray widths = env->NewFloatArray (numChars); - const int numDone = paint.callIntMethod (android.getTextWidths, javaString (text).get(), widths); + const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); HeapBlock localWidths (numDone); env->GetFloatArrayRegion (widths, 0, numDone, localWidths); @@ -116,7 +124,7 @@ public: const int numChars = text.length(); jfloatArray widths = env->NewFloatArray (numChars); - const int numDone = paint.callIntMethod (android.getTextWidths, javaString (text).get(), widths); + const int numDone = paint.callIntMethod (Paint.getTextWidths, javaString (text).get(), widths); HeapBlock localWidths (numDone); env->GetFloatArrayRegion (widths, 0, numDone, localWidths); @@ -145,14 +153,14 @@ public: JNIEnv* env = getEnv(); jobject matrix = android.createMatrix (env, AffineTransform::scale (unitsToHeightScaleFactor, unitsToHeightScaleFactor).followedBy (t)); - jintArray maskData = (jintArray) android.activity.callObjectMethod (android.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get()); + jintArray maskData = (jintArray) android.activity.callObjectMethod (JuceAppActivity.renderGlyph, (jchar) glyphNumber, paint.get(), matrix, rect.get()); env->DeleteLocalRef (matrix); - const int left = env->GetIntField (rect.get(), android.rectLeft); - const int top = env->GetIntField (rect.get(), android.rectTop); - const int right = env->GetIntField (rect.get(), android.rectRight); - const int bottom = env->GetIntField (rect.get(), android.rectBottom); + const int left = env->GetIntField (rect.get(), RectClass.left); + const int top = env->GetIntField (rect.get(), RectClass.top); + const int right = env->GetIntField (rect.get(), RectClass.right); + const int bottom = env->GetIntField (rect.get(), RectClass.bottom); const Rectangle bounds (left, top, right - left, bottom - top); diff --git a/src/native/android/juce_android_GraphicsContext.cpp b/src/native/android/juce_android_GraphicsContext.cpp index 73088ecb94..279e142f01 100644 --- a/src/native/android/juce_android_GraphicsContext.cpp +++ b/src/native/android/juce_android_GraphicsContext.cpp @@ -28,6 +28,107 @@ #if JUCE_INCLUDED_FILE #if USE_ANDROID_CANVAS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(Landroid/graphics/Bitmap;)V") \ + METHOD (drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ + METHOD (translate, "translate", "(FF)V") \ + METHOD (clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ + METHOD (clipRect, "clipRect", "(FFFF)Z") \ + METHOD (clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ + METHOD (concat, "concat", "(Landroid/graphics/Matrix;)V") \ + METHOD (drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ + METHOD (drawBitmapAt, "drawBitmap", "(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V") \ + METHOD (drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ + METHOD (drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ + METHOD (drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ + METHOD (drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ + METHOD (getClipBounds, "getClipBounds", "(Landroid/graphics/Rect;)Z") \ + METHOD (getClipBounds2, "getClipBounds", "()Landroid/graphics/Rect;") \ + METHOD (getMatrix, "getMatrix", "()Landroid/graphics/Matrix;") \ + METHOD (save, "save", "()I") \ + METHOD (restore, "restore", "()V") \ + METHOD (saveLayerAlpha, "saveLayerAlpha", "(FFFFII)I") + +DECLARE_JNI_CLASS (Canvas, "android/graphics/Canvas"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V") \ + METHOD (moveTo, "moveTo", "(FF)V") \ + METHOD (lineTo, "lineTo", "(FF)V") \ + METHOD (quadTo, "quadTo", "(FFFF)V") \ + METHOD (cubicTo, "cubicTo", "(FFFFFF)V") \ + METHOD (closePath, "close", "()V") \ + METHOD (computeBounds, "computeBounds", "(Landroid/graphics/RectF;Z)V") \ + +DECLARE_JNI_CLASS (PathClass, "android/graphics/Path"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V"); \ + METHOD (regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ + +DECLARE_JNI_CLASS (RegionClass, "android/graphics/Region"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ + METHOD (bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ + METHOD (getPixels, "getPixels", "([IIIIIII)V") \ + METHOD (setPixels, "setPixels", "([IIIIIII)V") \ + METHOD (recycle, "recycle", "()V") \ + +DECLARE_JNI_CLASS (BitmapClass, "android/graphics/Bitmap"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICFIELD (ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ + STATICFIELD (ALPHA_8, "ALPHA_8", "Landroid/graphics/Bitmap$Config;") \ + +DECLARE_JNI_CLASS (BitmapConfig, "android/graphics/Bitmap$Config"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(Landroid/graphics/Bitmap;Landroid/graphics/Shader$TileMode;Landroid/graphics/Shader$TileMode;)V") + +DECLARE_JNI_CLASS (BitmapShader, "android/graphics/BitmapShader"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") + +DECLARE_JNI_CLASS (ShaderClass, "android/graphics/Shader"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICFIELD (CLAMP, "CLAMP", "Landroid/graphics/Shader$TileMode;") + +DECLARE_JNI_CLASS (ShaderTileMode, "android/graphics/Shader$TileMode"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(FFFF[I[FLandroid/graphics/Shader$TileMode;)V") \ + +DECLARE_JNI_CLASS (LinearGradientClass, "android/graphics/LinearGradient"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "(FFF[I[FLandroid/graphics/Shader$TileMode;)V") \ + +DECLARE_JNI_CLASS (RadialGradientClass, "android/graphics/RadialGradient"); +#undef JNI_CLASS_MEMBERS + //============================================================================== class AndroidImage : public Image::SharedImage { @@ -48,7 +149,7 @@ public: ~AndroidImage() { if (bitmap != 0) - bitmap.callVoidMethod (android.recycle); + bitmap.callVoidMethod (BitmapClass.recycle); } Image::ImageType getType() const { return Image::NativeImage; } @@ -65,8 +166,8 @@ public: SharedImage* clone() { JNIEnv* env = getEnv(); - jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, android.ARGB_8888); - GlobalRef newCopy (bitmap.callObjectMethod (android.bitmapCopy, mode, true)); + jobject mode = env->GetStaticObjectField (BitmapConfig, BitmapConfig.ARGB_8888); + GlobalRef newCopy (bitmap.callObjectMethod (BitmapClass.bitmapCopy, mode, true)); env->DeleteLocalRef (mode); return new AndroidImage (width, height, newCopy); @@ -75,8 +176,9 @@ public: static jobject createBitmap (int width, int height, bool asSingleChannel) { JNIEnv* env = getEnv(); - jobject mode = env->GetStaticObjectField (android.bitmapConfigClass, asSingleChannel ? android.ALPHA_8 : android.ARGB_8888); - jobject result = env->CallStaticObjectMethod (android.bitmapClass, android.createBitmap, width, height, mode); + jobject mode = env->GetStaticObjectField (BitmapConfig, asSingleChannel ? BitmapConfig.ALPHA_8 + : BitmapConfig.ARGB_8888); + jobject result = env->CallStaticObjectMethod (BitmapClass, BitmapClass.createBitmap, width, height, mode); env->DeleteLocalRef (mode); return result; } @@ -97,7 +199,7 @@ private: intArray = env->NewIntArray (bitmapData.width * bitmapData.height); if (mode != Image::BitmapData::writeOnly) - owner_.bitmap.callVoidMethod (android.getPixels, intArray, 0, bitmapData.width, x_, y_, + owner_.bitmap.callVoidMethod (BitmapClass.getPixels, intArray, 0, bitmapData.width, x_, y_, bitmapData.width, bitmapData.height); bitmapData.data = (uint8*) env->GetIntArrayElements (intArray, 0); @@ -132,7 +234,7 @@ private: env->ReleaseIntArrayElements (intArray, (jint*) bitmapData.data, 0); if (mode != Image::BitmapData::readOnly) - owner.bitmap.callVoidMethod (android.setPixels, intArray, 0, bitmapData.width, x, y, + owner.bitmap.callVoidMethod (BitmapClass.setPixels, intArray, 0, bitmapData.width, x, y, bitmapData.width, bitmapData.height); env->DeleteLocalRef (intArray); @@ -187,12 +289,12 @@ public: //============================================================================== void setOrigin (int x, int y) { - getCanvas().callVoidMethod (android.translate, (float) x, (float) y); + getCanvas().callVoidMethod (Canvas.translate, (float) x, (float) y); } void addTransform (const AffineTransform& transform) { - getCanvas().callVoidMethod (android.concat, createMatrixRef (getEnv(), transform).get()); + getCanvas().callVoidMethod (Canvas.concat, createMatrixRef (getEnv(), transform).get()); } float getScaleFactor() @@ -202,7 +304,7 @@ public: bool clipToRectangle (const Rectangle& r) { - return getCanvas().callBooleanMethod (android.clipRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); + return getCanvas().callBooleanMethod (Canvas.clipRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } bool clipToRectangleList (const RectangleList& clipRegion) @@ -218,13 +320,13 @@ public: void excludeClipRectangle (const Rectangle& r) { - android.activity.callVoidMethod (android.excludeClipRegion, getCanvas().get(), + android.activity.callVoidMethod (JuceAppActivity.excludeClipRegion, getCanvas().get(), (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom()); } void clipToPath (const Path& path, const AffineTransform& transform) { - (void) getCanvas().callBooleanMethod (android.clipPath, createPath (getEnv(), path, transform).get()); + (void) getCanvas().callBooleanMethod (Canvas.clipPath, createPath (getEnv(), path, transform).get()); } void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) @@ -241,14 +343,14 @@ public: Rectangle bounds (getClipBounds()); jobject temporaryLayerBitmap = AndroidImage::createBitmap (bounds.getWidth(), bounds.getHeight(), false); - jobject temporaryCanvas = env->NewObject (android.canvasClass, android.canvasBitmapConstructor, temporaryLayerBitmap); + jobject temporaryCanvas = env->NewObject (Canvas, Canvas.constructor, temporaryLayerBitmap); setFill (Colours::red); - env->CallVoidMethod (temporaryCanvas, android.drawRect, + env->CallVoidMethod (temporaryCanvas, Canvas.drawRect, (jfloat) 20, (jfloat) 20, (jfloat) 300, (jfloat) 200, getCurrentPaint()); - env->CallVoidMethod (temporaryCanvas, android.translate, + env->CallVoidMethod (temporaryCanvas, Canvas.translate, (jfloat) -bounds.getX(), (jfloat) -bounds.getY()); Image maskImage (Image::SingleChannel, bounds.getWidth(), bounds.getHeight(), true); @@ -273,12 +375,12 @@ public: const Rectangle getClipBounds() const { JNIEnv* env = getEnv(); - jobject rect = getCanvas().callObjectMethod (android.getClipBounds2); + jobject rect = getCanvas().callObjectMethod (Canvas.getClipBounds2); - const int left = env->GetIntField (rect, android.rectLeft); - const int top = env->GetIntField (rect, android.rectTop); - const int right = env->GetIntField (rect, android.rectRight); - const int bottom = env->GetIntField (rect, android.rectBottom); + const int left = env->GetIntField (rect, RectClass.left); + const int top = env->GetIntField (rect, RectClass.top); + const int right = env->GetIntField (rect, RectClass.right); + const int bottom = env->GetIntField (rect, RectClass.bottom); env->DeleteLocalRef (rect); return Rectangle (left, top, right - left, bottom - top); @@ -286,8 +388,8 @@ public: bool isClipEmpty() const { - LocalRef tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0)); - return ! getCanvas().callBooleanMethod (android.getClipBounds, tempRect.get()); + LocalRef tempRect (getEnv()->NewObject (RectClass, RectClass.constructor, 0, 0, 0, 0)); + return ! getCanvas().callBooleanMethod (Canvas.getClipBounds, tempRect.get()); } //============================================================================== @@ -309,14 +411,14 @@ public: //============================================================================== void fillRect (const Rectangle& r, bool replaceExistingContents) { - getCanvas().callVoidMethod (android.drawRect, + getCanvas().callVoidMethod (Canvas.drawRect, (float) r.getX(), (float) r.getY(), (float) r.getRight(), (float) r.getBottom(), getCurrentPaint()); } void fillPath (const Path& path, const AffineTransform& transform) { - getCanvas().callVoidMethod (android.drawPath, createPath (getEnv(), path, transform).get(), + getCanvas().callVoidMethod (Canvas.drawPath, createPath (getEnv(), path, transform).get(), getCurrentPaint()); } @@ -327,7 +429,7 @@ public: if (androidImage != 0) { JNIEnv* env = getEnv(); - getCanvas().callVoidMethod (android.drawBitmap, androidImage->bitmap.get(), + getCanvas().callVoidMethod (Canvas.drawBitmap, androidImage->bitmap.get(), createMatrixRef (env, transform).get(), getImagePaint()); } else @@ -362,7 +464,7 @@ public: env->ReleaseIntArrayElements (imageData, dest, 0); - getCanvas().callVoidMethod (android.drawMemoryBitmap, imageData, 0, bm.width, + getCanvas().callVoidMethod (Canvas.drawMemoryBitmap, imageData, 0, bm.width, transform.getTranslationX(), transform.getTranslationY(), bm.width, bm.height, true, getImagePaint()); env->DeleteLocalRef (imageData); @@ -380,18 +482,18 @@ public: void drawLine (const Line & line) { - getCanvas().callVoidMethod (android.drawLine, line.getStartX(), line.getStartY(), + getCanvas().callVoidMethod (Canvas.drawLine, line.getStartX(), line.getStartY(), line.getEndX(), line.getEndY(), getCurrentPaint()); } void drawVerticalLine (int x, float top, float bottom) { - getCanvas().callVoidMethod (android.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); + getCanvas().callVoidMethod (Canvas.drawRect, (float) x, top, x + 1.0f, bottom, getCurrentPaint()); } void drawHorizontalLine (int y, float left, float right) { - getCanvas().callVoidMethod (android.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); + getCanvas().callVoidMethod (Canvas.drawRect, left, (float) y, right, y + 1.0f, getCurrentPaint()); } void setFont (const Font& newFont) @@ -412,7 +514,7 @@ public: { if (transform.isOnlyTranslation()) { - getCanvas().callVoidMethod (android.drawText, javaStringFromChar ((juce_wchar) glyphNumber).get(), + getCanvas().callVoidMethod (Canvas.drawText, javaStringFromChar ((juce_wchar) glyphNumber).get(), transform.getTranslationX(), transform.getTranslationY(), currentState->getPaintForTypeface()); } @@ -428,7 +530,7 @@ public: //============================================================================== void saveState() { - (void) getCanvas().callIntMethod (android.save); + (void) getCanvas().callIntMethod (Canvas.save); stateStack.add (new SavedState (*currentState)); } @@ -448,14 +550,14 @@ public: jassertfalse; // trying to pop with an empty stack! } - getCanvas().callVoidMethod (android.restore); + getCanvas().callVoidMethod (Canvas.restore); } void beginTransparencyLayer (float opacity) { Rectangle clip (getClipBounds()); - (void) getCanvas().callIntMethod (android.saveLayerAlpha, + (void) getCanvas().callIntMethod (Canvas.saveLayerAlpha, (float) clip.getX(), (float) clip.getY(), (float) clip.getRight(), @@ -520,8 +622,8 @@ public: if (fillType.isColour()) { - env->DeleteLocalRef (paint.callObjectMethod (android.setShader, (jobject) 0)); - paint.callVoidMethod (android.setColor, colourToInt (fillType.colour)); + env->DeleteLocalRef (paint.callObjectMethod (Paint.setShader, (jobject) 0)); + paint.callVoidMethod (Paint.setColor, colourToInt (fillType.colour)); } else if (fillType.isGradient()) { @@ -547,13 +649,13 @@ public: env->SetFloatArrayRegion (positionsArray, 0, numColours, positions.getData()); } - jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); + jobject tileMode = env->GetStaticObjectField (ShaderTileMode, ShaderTileMode.CLAMP); jobject shader; if (fillType.gradient->isRadial) { - shader = env->NewObject (android.radialGradientClass, - android.radialGradientConstructor, + shader = env->NewObject (RadialGradientClass, + RadialGradientClass.constructor, p1.getX(), p1.getY(), p1.getDistanceFrom (p2), coloursArray, positionsArray, @@ -561,8 +663,8 @@ public: } else { - shader = env->NewObject (android.linearGradientClass, - android.linearGradientConstructor, + shader = env->NewObject (LinearGradientClass, + LinearGradientClass.constructor, p1.getX(), p1.getY(), p2.getX(), p2.getY(), coloursArray, positionsArray, tileMode); @@ -572,8 +674,8 @@ public: env->DeleteLocalRef (coloursArray); env->DeleteLocalRef (positionsArray); - env->CallVoidMethod (shader, android.setLocalMatrix, createMatrixRef (env, fillType.transform).get()); - env->DeleteLocalRef (paint.callObjectMethod (android.setShader, shader)); + env->CallVoidMethod (shader, ShaderClass.setLocalMatrix, createMatrixRef (env, fillType.transform).get()); + env->DeleteLocalRef (paint.callObjectMethod (Paint.setShader, shader)); env->DeleteLocalRef (shader); } @@ -598,17 +700,17 @@ public: if (atf != 0) { - paint.callObjectMethod (android.setTypeface, atf->typeface.get()); - paint.callVoidMethod (android.setTextSize, font.getHeight()); + paint.callObjectMethod (Paint.setTypeface, atf->typeface.get()); + paint.callVoidMethod (Paint.setTextSize, font.getHeight()); const float hScale = font.getHorizontalScale(); if (hScale < 0.99f || hScale > 1.01f) - paint.callVoidMethod (android.setTextScaleX, hScale); + paint.callVoidMethod (Paint.setTextScaleX, hScale); } fillNeedsUpdate = true; - paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + paint.callVoidMethod (Paint.setAlpha, (jint) fillType.colour.getAlpha()); } return p; @@ -617,7 +719,7 @@ public: jobject getImagePaint() { jobject p = getPaint(); - paint.callVoidMethod (android.setAlpha, (jint) fillType.colour.getAlpha()); + paint.callVoidMethod (Paint.setAlpha, (jint) fillType.colour.getAlpha()); fillNeedsUpdate = true; return p; } @@ -630,27 +732,27 @@ public: { JNIEnv* env = getEnv(); - jobject tileMode = env->GetStaticObjectField (android.shaderTileModeClass, android.clampMode); - jobject shader = env->NewObject (android.bitmapShaderClass, android.bitmapShaderConstructor, + jobject tileMode = env->GetStaticObjectField (ShaderTileMode, ShaderTileMode.CLAMP); + jobject shader = env->NewObject (BitmapShader, BitmapShader.constructor, temporaryLayerBitmap.get(), tileMode, tileMode); env->DeleteLocalRef (tileMode); jobject compositingPaint = android.createPaint (quality); - env->CallObjectMethod (compositingPaint, android.setShader, shader); + env->CallObjectMethod (compositingPaint, Paint.setShader, shader); env->DeleteLocalRef (shader); LocalRef maskBitmap (createAlphaBitmap (env, maskImage)); maskImage = Image::null; - env->CallVoidMethod (previousCanvas, android.drawBitmapAt, + env->CallVoidMethod (previousCanvas, Canvas.drawBitmapAt, maskBitmap.get(), (jfloat) maskLayerX, (jfloat) maskLayerY, compositingPaint); env->DeleteLocalRef (compositingPaint); canvas = GlobalRef (previousCanvas); - env->CallVoidMethod (temporaryLayerBitmap.get(), android.recycle); - env->CallVoidMethod (maskBitmap.get(), android.recycle); + env->CallVoidMethod (temporaryLayerBitmap.get(), BitmapClass.recycle); + env->CallVoidMethod (maskBitmap.get(), BitmapClass.recycle); temporaryLayerBitmap.clear(); } @@ -693,7 +795,7 @@ public: } env->ReleaseIntArrayElements (intArray, (jint*) dest, 0); - env->CallVoidMethod (bitmap, android.setPixels, intArray, 0, bm.width, 0, 0, bm.width, bm.height); + env->CallVoidMethod (bitmap, BitmapClass.setPixels, intArray, 0, bm.width, 0, 0, bm.width, bm.height); env->DeleteLocalRef (intArray); return bitmap; } @@ -720,9 +822,9 @@ private: jobject getCurrentPaint() const { return currentState->getPaint(); } jobject getImagePaint() const { return currentState->getImagePaint(); } - static const LocalRef createPath (JNIEnv* env, const Path& path) + static LocalRef createPath (JNIEnv* env, const Path& path) { - jobject p = env->NewObject (android.pathClass, android.pathClassConstructor); + jobject p = env->NewObject (PathClass, PathClass.constructor); Path::Iterator i (path); @@ -730,11 +832,11 @@ private: { switch (i.elementType) { - case Path::Iterator::startNewSubPath: env->CallVoidMethod (p, android.moveTo, i.x1, i.y1); break; - case Path::Iterator::lineTo: env->CallVoidMethod (p, android.lineTo, i.x1, i.y1); break; - case Path::Iterator::quadraticTo: env->CallVoidMethod (p, android.quadTo, i.x1, i.y1, i.x2, i.y2); break; - case Path::Iterator::cubicTo: env->CallVoidMethod (p, android.cubicTo, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; - case Path::Iterator::closePath: env->CallVoidMethod (p, android.closePath); break; + case Path::Iterator::startNewSubPath: env->CallVoidMethod (p, PathClass.moveTo, i.x1, i.y1); break; + case Path::Iterator::lineTo: env->CallVoidMethod (p, PathClass.lineTo, i.x1, i.y1); break; + case Path::Iterator::quadraticTo: env->CallVoidMethod (p, PathClass.quadTo, i.x1, i.y1, i.x2, i.y2); break; + case Path::Iterator::cubicTo: env->CallVoidMethod (p, PathClass.cubicTo, i.x1, i.y1, i.x2, i.y2, i.x3, i.y3); break; + case Path::Iterator::closePath: env->CallVoidMethod (p, PathClass.closePath); break; default: jassertfalse; break; } } @@ -742,7 +844,7 @@ private: return LocalRef (p); } - static const LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) + static LocalRef createPath (JNIEnv* env, const Path& path, const AffineTransform& transform) { if (transform.isIdentity()) return createPath (env, path); @@ -752,25 +854,25 @@ private: return createPath (env, tempPath); } - static const LocalRef createMatrixRef (JNIEnv* env, const AffineTransform& t) + static LocalRef createMatrixRef (JNIEnv* env, const AffineTransform& t) { - return LocalRef (android.createMatrix (*env, t)); + return LocalRef (android.createMatrix (env, t)); } - static const LocalRef createRect (JNIEnv* env, const Rectangle& r) + static LocalRef createRect (JNIEnv* env, const Rectangle& r) { - return LocalRef (env->NewObject (android.rectClass, android.rectConstructor, + return LocalRef (env->NewObject (RectClass, RectClass.constructor, r.getX(), r.getY(), r.getRight(), r.getBottom())); } - static const LocalRef createRegion (JNIEnv* env, const RectangleList& list) + static LocalRef createRegion (JNIEnv* env, const RectangleList& list) { - jobject region = env->NewObject (android.regionClass, android.regionConstructor); + jobject region = env->NewObject (RegionClass, RegionClass.constructor); const int numRects = list.getNumRectangles(); for (int i = 0; i < numRects; ++i) - env->CallBooleanMethod (region, android.regionUnion, createRect (env, list.getRectangle(i)).get()); + env->CallBooleanMethod (region, RegionClass.regionUnion, createRect (env, list.getRectangle(i)).get()); return LocalRef (region); } @@ -795,7 +897,7 @@ private: LowLevelGraphicsContext* AndroidImage::createLowLevelContext() { - jobject canvas = getEnv()->NewObject (android.canvasClass, android.canvasBitmapConstructor, bitmap.get()); + jobject canvas = getEnv()->NewObject (Canvas, Canvas.constructor, bitmap.get()); return new AndroidLowLevelGraphicsContext (canvas); } #endif diff --git a/src/native/android/juce_android_Messaging.cpp b/src/native/android/juce_android_Messaging.cpp index 76693268fd..74e7ee39b0 100644 --- a/src/native/android/juce_android_Messaging.cpp +++ b/src/native/android/juce_android_Messaging.cpp @@ -45,7 +45,7 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool returnIfNoPend bool MessageManager::postMessageToSystemQueue (Message* message) { message->incReferenceCount(); - getEnv()->CallVoidMethod (android.activity, android.postMessage, (jlong) (pointer_sized_uint) message); + getEnv()->CallVoidMethod (android.activity, JuceAppActivity.postMessage, (jlong) (pointer_sized_uint) message); return true; } @@ -111,7 +111,7 @@ public: void messageCallback() { - android.activity.callVoidMethod (android.finish); + android.activity.callVoidMethod (JuceAppActivity.finish); } }; diff --git a/src/native/android/juce_android_Misc.cpp b/src/native/android/juce_android_Misc.cpp index 41268c00ce..797e908230 100644 --- a/src/native/android/juce_android_Misc.cpp +++ b/src/native/android/juce_android_Misc.cpp @@ -51,7 +51,7 @@ JUCE_JNI_CALLBACK (JuceAppActivity, quitApp, void, (JNIEnv* env, jobject activit { JUCEApplication::appWillTerminateByForce(); - android.shutdown(); + android.shutdown (env); } //============================================================================== @@ -65,7 +65,7 @@ void Logger::outputDebugString (const String& text) JNIEnv* const env = getEnv(); if (env != nullptr) - env->CallStaticVoidMethod (android.activityClass, android.printToConsole, + env->CallStaticVoidMethod (JuceAppActivity, JuceAppActivity.printToConsole, javaString (text).get()); } @@ -73,14 +73,13 @@ void Logger::outputDebugString (const String& text) void SystemClipboard::copyTextToClipboard (const String& text) { const LocalRef t (javaString (text)); - android.activity.callVoidMethod (android.setClipboardContent, t.get()); + android.activity.callVoidMethod (JuceAppActivity.setClipboardContent, t.get()); } String SystemClipboard::getTextFromClipboard() { - const LocalRef text ((jstring) android.activity.callObjectMethod (android.getClipboardContent)); + const LocalRef text ((jstring) android.activity.callObjectMethod (JuceAppActivity.getClipboardContent)); return juceString (text); } - #endif diff --git a/src/native/android/juce_android_NativeCode.cpp b/src/native/android/juce_android_NativeCode.cpp index 0fe58e4d91..06d7d4b208 100644 --- a/src/native/android/juce_android_NativeCode.cpp +++ b/src/native/android/juce_android_NativeCode.cpp @@ -90,554 +90,14 @@ BEGIN_JUCE_NAMESPACE #include "../../audio/midi/juce_MidiInput.h" #include "../../containers/juce_ScopedValueSetter.h" -#define USE_ANDROID_CANVAS 0 - -//============================================================================== -#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \ - extern "C" __attribute__ ((visibility("default"))) returnType Java_com_juce_ ## className ## _ ## methodName params - -//============================================================================== -// List of basic required classes -#define JUCE_JNI_CLASSES_ESSENTIAL(JAVACLASS) \ - JAVACLASS (activityClass, "com/juce/JuceAppActivity") \ - JAVACLASS (httpStreamClass, "com/juce/JuceAppActivity$HTTPStream") \ - JAVACLASS (componentPeerViewClass, "com/juce/ComponentPeerView") \ - JAVACLASS (fileClass, "java/io/File") \ - JAVACLASS (systemClass, "java/lang/System") \ - JAVACLASS (stringBufferClass, "java/lang/StringBuffer") \ - JAVACLASS (contextClass, "android/content/Context") \ - JAVACLASS (canvasClass, "android/graphics/Canvas") \ - JAVACLASS (paintClass, "android/graphics/Paint") \ - JAVACLASS (matrixClass, "android/graphics/Matrix") \ - JAVACLASS (rectClass, "android/graphics/Rect") \ - JAVACLASS (typefaceClass, "android/graphics/Typeface") \ - JAVACLASS (audioTrackClass, "android/media/AudioTrack") \ - JAVACLASS (audioRecordClass, "android/media/AudioRecord") \ - -//============================================================================== -// List of extra classes needed when USE_ANDROID_CANVAS is enabled -#if ! USE_ANDROID_CANVAS -#define JUCE_JNI_CLASSES(JAVACLASS) JUCE_JNI_CLASSES_ESSENTIAL(JAVACLASS); -#else -#define JUCE_JNI_CLASSES(JAVACLASS) JUCE_JNI_CLASSES_ESSENTIAL(JAVACLASS); \ - JAVACLASS (pathClass, "android/graphics/Path") \ - JAVACLASS (regionClass, "android/graphics/Region") \ - JAVACLASS (bitmapClass, "android/graphics/Bitmap") \ - JAVACLASS (bitmapConfigClass, "android/graphics/Bitmap$Config") \ - JAVACLASS (bitmapShaderClass, "android/graphics/BitmapShader") \ - JAVACLASS (shaderClass, "android/graphics/Shader") \ - JAVACLASS (shaderTileModeClass, "android/graphics/Shader$TileMode") \ - JAVACLASS (linearGradientClass, "android/graphics/LinearGradient") \ - JAVACLASS (radialGradientClass, "android/graphics/RadialGradient") \ - -#endif - - -//============================================================================== -// List of required methods -#define JUCE_JNI_METHODS_ESSENTIAL(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ -\ - STATICMETHOD (activityClass, printToConsole, "printToConsole", "(Ljava/lang/String;)V") \ - METHOD (activityClass, createNewView, "createNewView", "(Z)Lcom/juce/ComponentPeerView;") \ - METHOD (activityClass, deleteView, "deleteView", "(Lcom/juce/ComponentPeerView;)V") \ - METHOD (activityClass, postMessage, "postMessage", "(J)V") \ - METHOD (activityClass, finish, "finish", "()V") \ - METHOD (activityClass, getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \ - METHOD (activityClass, setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \ - METHOD (activityClass, excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \ - METHOD (activityClass, renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \ - STATICMETHOD (activityClass, createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;ILjava/lang/StringBuffer;)Lcom/juce/JuceAppActivity$HTTPStream;") \ - METHOD (activityClass, showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ - METHOD (activityClass, showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ - METHOD (activityClass, showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \ -\ - METHOD (stringBufferClass, stringBufferConstructor, "", "()V") \ - METHOD (stringBufferClass, stringBufferToString, "toString", "()Ljava/lang/String;") \ -\ - METHOD (httpStreamClass, httpStreamRelease, "release", "()V") \ - METHOD (httpStreamClass, httpStreamRead, "read", "([BI)I") \ - METHOD (httpStreamClass, getPosition, "getPosition", "()J") \ - METHOD (httpStreamClass, getTotalLength, "getTotalLength", "()J") \ - METHOD (httpStreamClass, isExhausted, "isExhausted", "()Z") \ - METHOD (httpStreamClass, setPosition, "setPosition", "(J)Z") \ -\ - METHOD (fileClass, fileExists, "exists", "()Z") \ - STATICMETHOD (systemClass, getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;") \ -\ - METHOD (componentPeerViewClass, setViewName, "setViewName", "(Ljava/lang/String;)V") \ - METHOD (componentPeerViewClass, layout, "layout", "(IIII)V") \ - METHOD (componentPeerViewClass, getLeft, "getLeft", "()I") \ - METHOD (componentPeerViewClass, getTop, "getTop", "()I") \ - METHOD (componentPeerViewClass, getWidth, "getWidth", "()I") \ - METHOD (componentPeerViewClass, getHeight, "getHeight", "()I") \ - METHOD (componentPeerViewClass, getLocationOnScreen, "getLocationOnScreen", "([I)V") \ - METHOD (componentPeerViewClass, bringToFront, "bringToFront", "()V") \ - METHOD (componentPeerViewClass, requestFocus, "requestFocus", "()Z") \ - METHOD (componentPeerViewClass, setVisible, "setVisible", "(Z)V") \ - METHOD (componentPeerViewClass, isVisible, "isVisible", "()Z") \ - METHOD (componentPeerViewClass, hasFocus, "hasFocus", "()Z") \ - METHOD (componentPeerViewClass, invalidate, "invalidate", "(IIII)V") \ - METHOD (componentPeerViewClass, containsPoint, "containsPoint", "(II)Z") \ -\ - METHOD (canvasClass, drawMemoryBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, getClipBounds2, "getClipBounds", "()Landroid/graphics/Rect;") \ -\ - METHOD (paintClass, paintClassConstructor, "", "(I)V") \ - METHOD (paintClass, setColor, "setColor", "(I)V") \ - METHOD (paintClass, setAlpha, "setAlpha", "(I)V") \ - METHOD (paintClass, setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \ - METHOD (paintClass, ascent, "ascent", "()F") \ - METHOD (paintClass, descent, "descent", "()F") \ - METHOD (paintClass, setTextSize, "setTextSize", "(F)V") \ - METHOD (paintClass, getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \ - METHOD (paintClass, setTextScaleX, "setTextScaleX", "(F)V") \ - METHOD (paintClass, getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \ -\ - METHOD (matrixClass, matrixClassConstructor, "", "()V") \ - METHOD (matrixClass, setValues, "setValues", "([F)V") \ -\ - STATICMETHOD (typefaceClass, create, "create", "(Ljava/lang/String;I)Landroid/graphics/Typeface;") \ - STATICMETHOD (typefaceClass, createFromFile, "createFromFile", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \ -\ - METHOD (rectClass, rectConstructor, "", "(IIII)V") \ - FIELD (rectClass, rectLeft, "left", "I") \ - FIELD (rectClass, rectRight, "right", "I") \ - FIELD (rectClass, rectTop, "top", "I") \ - FIELD (rectClass, rectBottom, "bottom", "I") \ -\ - METHOD (audioTrackClass, audioTrackConstructor, "", "(IIIIII)V") \ - STATICMETHOD (audioTrackClass, getMinBufferSize, "getMinBufferSize", "(III)I") \ - STATICMETHOD (audioTrackClass, getNativeOutputSampleRate, "getNativeOutputSampleRate", "(I)I") \ - METHOD (audioTrackClass, audioTrackPlay, "play", "()V") \ - METHOD (audioTrackClass, audioTrackStop, "stop", "()V") \ - METHOD (audioTrackClass, audioTrackRelease, "release", "()V") \ - METHOD (audioTrackClass, audioTrackFlush, "flush", "()V") \ - METHOD (audioTrackClass, audioTrackWrite, "write", "([SII)I") \ -\ - METHOD (audioRecordClass, audioRecordConstructor, "", "(IIIII)V"); \ - STATICMETHOD (audioRecordClass, getMinRecordBufferSize, "getMinBufferSize", "(III)I") \ - METHOD (audioRecordClass, startRecording, "startRecording", "()V"); \ - METHOD (audioRecordClass, stopRecording, "stop", "()V"); \ - METHOD (audioRecordClass, audioRecordRead, "read", "([SII)I"); \ - METHOD (audioRecordClass, audioRecordRelease, "release", "()V"); \ - - -//============================================================================== -// List of extra methods needed when USE_ANDROID_CANVAS is enabled -#if ! USE_ANDROID_CANVAS -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) JUCE_JNI_METHODS_ESSENTIAL(METHOD, STATICMETHOD, FIELD, STATICFIELD) -#else -#define JUCE_JNI_METHODS(METHOD, STATICMETHOD, FIELD, STATICFIELD) JUCE_JNI_METHODS_ESSENTIAL(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ - METHOD (pathClass, pathClassConstructor, "", "()V") \ - METHOD (pathClass, moveTo, "moveTo", "(FF)V") \ - METHOD (pathClass, lineTo, "lineTo", "(FF)V") \ - METHOD (pathClass, quadTo, "quadTo", "(FFFF)V") \ - METHOD (pathClass, cubicTo, "cubicTo", "(FFFFFF)V") \ - METHOD (pathClass, closePath, "close", "()V") \ - METHOD (pathClass, computeBounds, "computeBounds", "(Landroid/graphics/RectF;Z)V") \ -\ - STATICMETHOD (bitmapClass, createBitmap, "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;") \ - STATICFIELD (bitmapConfigClass, ARGB_8888, "ARGB_8888", "Landroid/graphics/Bitmap$Config;") \ - STATICFIELD (bitmapConfigClass, ALPHA_8, "ALPHA_8", "Landroid/graphics/Bitmap$Config;") \ - METHOD (bitmapClass, bitmapCopy, "copy", "(Landroid/graphics/Bitmap$Config;Z)Landroid/graphics/Bitmap;") \ - METHOD (bitmapClass, getPixels, "getPixels", "([IIIIIII)V") \ - METHOD (bitmapClass, setPixels, "setPixels", "([IIIIIII)V") \ - METHOD (bitmapClass, recycle, "recycle", "()V") \ -\ - METHOD (shaderClass, setLocalMatrix, "setLocalMatrix", "(Landroid/graphics/Matrix;)V") \ - STATICFIELD (shaderTileModeClass, clampMode, "CLAMP", "Landroid/graphics/Shader$TileMode;") \ -\ - METHOD (bitmapShaderClass, bitmapShaderConstructor, "", "(Landroid/graphics/Bitmap;Landroid/graphics/Shader$TileMode;Landroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (paintClass, setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \ -\ - METHOD (canvasClass, canvasBitmapConstructor, "", "(Landroid/graphics/Bitmap;)V") \ - METHOD (canvasClass, drawRect, "drawRect", "(FFFFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, translate, "translate", "(FF)V") \ - METHOD (canvasClass, clipPath, "clipPath", "(Landroid/graphics/Path;)Z") \ - METHOD (canvasClass, clipRect, "clipRect", "(FFFF)Z") \ - METHOD (canvasClass, clipRegion, "clipRegion", "(Landroid/graphics/Region;)Z") \ - METHOD (canvasClass, concat, "concat", "(Landroid/graphics/Matrix;)V") \ - METHOD (canvasClass, drawBitmap, "drawBitmap", "(Landroid/graphics/Bitmap;Landroid/graphics/Matrix;Landroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawBitmapAt, "drawBitmap", "(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawLine, "drawLine", "(FFFFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawPath, "drawPath", "(Landroid/graphics/Path;Landroid/graphics/Paint;)V") \ - METHOD (canvasClass, drawText, "drawText", "(Ljava/lang/String;FFLandroid/graphics/Paint;)V") \ - METHOD (canvasClass, getClipBounds, "getClipBounds", "(Landroid/graphics/Rect;)Z") \ - METHOD (canvasClass, getMatrix, "getMatrix", "()Landroid/graphics/Matrix;") \ - METHOD (canvasClass, save, "save", "()I") \ - METHOD (canvasClass, restore, "restore", "()V") \ - METHOD (canvasClass, saveLayerAlpha, "saveLayerAlpha", "(FFFFII)I") \ -\ - METHOD (linearGradientClass, linearGradientConstructor, "", "(FFFF[I[FLandroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (radialGradientClass, radialGradientConstructor, "", "(FFF[I[FLandroid/graphics/Shader$TileMode;)V") \ -\ - METHOD (regionClass, regionConstructor, "", "()V"); \ - METHOD (regionClass, regionUnion, "union", "(Landroid/graphics/Rect;)Z"); \ - -#endif - - -//============================================================================== -class ThreadLocalJNIEnvHolder -{ -public: - ThreadLocalJNIEnvHolder() - : jvm (0) - { - zeromem (threads, sizeof (threads)); - zeromem (envs, sizeof (envs)); - } - - void initialise (JNIEnv* env) - { - env->GetJavaVM (&jvm); - addEnv (env); - } - - void attach() - { - JNIEnv* env = nullptr; - jvm->AttachCurrentThread (&env, 0); - - if (env != 0) - addEnv (env); - } - - void detach() - { - jvm->DetachCurrentThread(); - - const pthread_t thisThread = pthread_self(); - - SpinLock::ScopedLockType sl (addRemoveLock); - for (int i = 0; i < maxThreads; ++i) - if (threads[i] == thisThread) - threads[i] = 0; - } - - JNIEnv* get() const noexcept - { - const pthread_t thisThread = pthread_self(); - - for (int i = 0; i < maxThreads; ++i) - if (threads[i] == thisThread) - return envs[i]; - - return nullptr; - } - - enum { maxThreads = 16 }; - -private: - JavaVM* jvm; - pthread_t threads [maxThreads]; - JNIEnv* envs [maxThreads]; - SpinLock addRemoveLock; - - void addEnv (JNIEnv* env) - { - SpinLock::ScopedLockType sl (addRemoveLock); - - if (get() == 0) - { - const pthread_t thisThread = pthread_self(); - - for (int i = 0; i < maxThreads; ++i) - { - if (threads[i] == 0) - { - envs[i] = env; - threads[i] = thisThread; - return; - } - } - } - - jassertfalse; // too many threads! - } -}; - -static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; - -struct AndroidThreadScope -{ - AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } - ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } -}; - -static inline JNIEnv* getEnv() noexcept -{ - return threadLocalJNIEnvHolder.get(); -} - - -//============================================================================== -class GlobalRef -{ -public: - inline GlobalRef() noexcept - : obj (0) - { - } - - inline explicit GlobalRef (jobject obj_) - : obj (retain (obj_)) - { - } - - inline GlobalRef (const GlobalRef& other) - : obj (retain (other.obj)) - { - } - - ~GlobalRef() - { - clear(); - } - - inline void clear() - { - if (obj != 0) - { - getEnv()->DeleteGlobalRef (obj); - obj = 0; - } - } - - inline GlobalRef& operator= (const GlobalRef& other) - { - clear(); - obj = retain (other.obj); - return *this; - } - - //============================================================================== - inline operator jobject() const noexcept { return obj; } - inline jobject get() const noexcept { return obj; } - - //============================================================================== - #define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \ - returnType call##typeName##Method (jmethodID methodID, ... ) const \ - { \ - va_list args; \ - va_start (args, methodID); \ - returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \ - va_end (args); \ - return result; \ - } - - DECLARE_CALL_TYPE_METHOD (jobject, Object) - DECLARE_CALL_TYPE_METHOD (jboolean, Boolean) - DECLARE_CALL_TYPE_METHOD (jbyte, Byte) - DECLARE_CALL_TYPE_METHOD (jchar, Char) - DECLARE_CALL_TYPE_METHOD (jshort, Short) - DECLARE_CALL_TYPE_METHOD (jint, Int) - DECLARE_CALL_TYPE_METHOD (jlong, Long) - DECLARE_CALL_TYPE_METHOD (jfloat, Float) - DECLARE_CALL_TYPE_METHOD (jdouble, Double) - #undef DECLARE_CALL_TYPE_METHOD - - void callVoidMethod (jmethodID methodID, ... ) const - { - va_list args; - va_start (args, methodID); - getEnv()->CallVoidMethodV (obj, methodID, args); - va_end (args); - } - -private: - //============================================================================== - jobject obj; - - static inline jobject retain (jobject obj_) - { - return obj_ == 0 ? 0 : getEnv()->NewGlobalRef (obj_); - } -}; - -//============================================================================== -template -class LocalRef -{ -public: - explicit inline LocalRef (JavaType obj_) noexcept - : obj (obj_) - { - } - - inline LocalRef (const LocalRef& other) noexcept - : obj (retain (other.obj)) - { - } - - ~LocalRef() - { - if (obj != 0) - getEnv()->DeleteLocalRef (obj); - } - - LocalRef& operator= (const LocalRef& other) - { - if (obj != other.obj) - { - if (obj != 0) - getEnv()->DeleteLocalRef (obj); - - obj = retain (other.obj); - } - - return *this; - } - - inline operator JavaType() const noexcept { return obj; } - inline JavaType get() const noexcept { return obj; } - -private: - JavaType obj; - - static JavaType retain (JavaType obj_) - { - return obj_ == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj_); - } -}; - -//============================================================================== -static const String juceString (jstring s) -{ - JNIEnv* env = getEnv(); - - jboolean isCopy; - const char* const utf8 = env->GetStringUTFChars (s, &isCopy); - CharPointer_UTF8 utf8CP (utf8); - const String result (utf8CP); - env->ReleaseStringUTFChars (s, utf8); - return result; -} - -static const LocalRef javaString (const String& s) -{ - return LocalRef (getEnv()->NewStringUTF (s.toUTF8())); -} - -static const LocalRef javaStringFromChar (const juce_wchar c) -{ - char utf8[5] = { 0 }; - CharPointer_UTF8 (utf8).write (c); - return LocalRef (getEnv()->NewStringUTF (utf8)); -} - -//============================================================================== -class AndroidJavaCallbacks -{ -public: - AndroidJavaCallbacks() : screenWidth (0), screenHeight (0) - { - } - - void initialise (JNIEnv* env, jobject activity_, - jstring appFile_, jstring appDataDir_) - { - threadLocalJNIEnvHolder.initialise (env); - activity = GlobalRef (activity_); - appFile = juceString (appFile_); - appDataDir = juceString (appDataDir_); - - #define CREATE_JNI_CLASS(className, path) \ - className = (jclass) env->NewGlobalRef (env->FindClass (path)); \ - jassert (className != 0); - JUCE_JNI_CLASSES (CREATE_JNI_CLASS); - #undef CREATE_JNI_CLASS - - #define CREATE_JNI_METHOD(ownerClass, methodID, stringName, params) \ - methodID = env->GetMethodID (ownerClass, stringName, params); \ - jassert (methodID != 0); - #define CREATE_JNI_STATICMETHOD(ownerClass, methodID, stringName, params) \ - methodID = env->GetStaticMethodID (ownerClass, stringName, params); \ - jassert (methodID != 0); - #define CREATE_JNI_FIELD(ownerClass, fieldID, stringName, signature) \ - fieldID = env->GetFieldID (ownerClass, stringName, signature); \ - jassert (fieldID != 0); - #define CREATE_JNI_STATICFIELD(ownerClass, fieldID, stringName, signature) \ - fieldID = env->GetStaticFieldID (ownerClass, stringName, signature); \ - jassert (fieldID != 0); - JUCE_JNI_METHODS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); - #undef CREATE_JNI_METHOD - } - - void shutdown() - { - JNIEnv* env = getEnv(); - - if (env != 0) - { - #define RELEASE_JNI_CLASS(className, path) env->DeleteGlobalRef (className); - JUCE_JNI_CLASSES (RELEASE_JNI_CLASS); - #undef RELEASE_JNI_CLASS - - activity.clear(); - } - } - - //============================================================================== - GlobalRef activity; - String appFile, appDataDir; - int screenWidth, screenHeight; - - jobject createPaint (Graphics::ResamplingQuality quality) - { - jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/ - | 4 /*DITHER_FLAG*/ - | 128 /*SUBPIXEL_TEXT_FLAG*/; - - if (quality > Graphics::lowResamplingQuality) - constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/ - - return getEnv()->NewObject (paintClass, paintClassConstructor, constructorFlags); - } - - const jobject createMatrix (JNIEnv* env, const AffineTransform& t) - { - jobject m = env->NewObject (matrixClass, matrixClassConstructor); - - jfloat values[9] = { t.mat00, t.mat01, t.mat02, - t.mat10, t.mat11, t.mat12, - 0.0f, 0.0f, 1.0f }; - - jfloatArray javaArray = env->NewFloatArray (9); - env->SetFloatArrayRegion (javaArray, 0, 9, values); - - env->CallVoidMethod (m, setValues, javaArray); - env->DeleteLocalRef (javaArray); - - return m; - } - - //============================================================================== - #define DECLARE_JNI_CLASS(className, path) jclass className; - JUCE_JNI_CLASSES (DECLARE_JNI_CLASS); - #undef DECLARE_JNI_CLASS - - #define DECLARE_JNI_METHOD(ownerClass, methodID, stringName, params) jmethodID methodID; - #define DECLARE_JNI_FIELD(ownerClass, fieldID, stringName, signature) jfieldID fieldID; - JUCE_JNI_METHODS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); - #undef DECLARE_JNI_METHOD -}; - -static AndroidJavaCallbacks android; - -// This is an unsatisfactory workaround for a linker warning that appeared in NDK5c. -// If anyone actually understands what this symbol is for and why the linker gets confused by it, -// please let me know! -extern "C" { void* __dso_handle = 0; } +#include "juce_android_JNIHelpers.h" //============================================================================== #define JUCE_INCLUDED_FILE 1 // Now include the actual code files.. -#include "juce_android_Misc.cpp" #include "juce_android_SystemStats.cpp" +#include "juce_android_Misc.cpp" #include "../common/juce_posix_SharedCode.h" #include "juce_android_Files.cpp" #include "../common/juce_posix_NamedPipe.cpp" diff --git a/src/native/android/juce_android_Network.cpp b/src/native/android/juce_android_Network.cpp index 5f5aaadb8a..737d5d3977 100644 --- a/src/native/android/juce_android_Network.cpp +++ b/src/native/android/juce_android_Network.cpp @@ -27,6 +27,26 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (constructor, "", "()V") \ + METHOD (toString, "toString", "()Ljava/lang/String;") \ + +DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (release, "release", "()V") \ + METHOD (read, "read", "([BI)I") \ + METHOD (getPosition, "getPosition", "()J") \ + METHOD (getTotalLength, "getTotalLength", "()J") \ + METHOD (isExhausted, "isExhausted", "()Z") \ + METHOD (setPosition, "setPosition", "(J)Z") \ + +DECLARE_JNI_CLASS (HTTPStream, "com/juce/JuceAppActivity$HTTPStream"); +#undef JNI_CLASS_MEMBERS + //============================================================================== void MACAddress::findAllAddresses (Array& result) @@ -67,10 +87,10 @@ public: env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData()); } - LocalRef responseHeaderBuffer (env->NewObject (android.stringBufferClass, android.stringBufferConstructor)); + LocalRef responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor)); - stream = GlobalRef (env->CallStaticObjectMethod (android.activityClass, - android.createHTTPStream, + stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity, + JuceAppActivity.createHTTPStream, javaString (address).get(), (jboolean) isPost, postDataArray, @@ -87,8 +107,8 @@ public: { LocalRef headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(), - android.stringBufferToString)); - headerLines.addLines (juceString (headersString)); + StringBuffer.toString)); + headerLines.addLines (juceString (env, headersString)); } if (responseHeaders != 0) @@ -109,14 +129,14 @@ public: ~WebInputStream() { if (stream != 0) - stream.callVoidMethod (android.httpStreamRelease); + stream.callVoidMethod (HTTPStream.release); } //============================================================================== - bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (android.isExhausted); } - int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (android.getTotalLength) : 0; } - int64 getPosition() { return stream != nullptr ? stream.callLongMethod (android.getPosition) : 0; } - bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (android.setPosition, (jlong) wantedPos); } + bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); } + int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; } + int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; } + bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); } int read (void* buffer, int bytesToRead) { @@ -127,7 +147,7 @@ public: jbyteArray javaArray = env->NewByteArray (bytesToRead); - int numBytes = stream.callIntMethod (android.httpStreamRead, javaArray, (jint) bytesToRead); + int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead); if (numBytes > 0) env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast (buffer)); diff --git a/src/native/android/juce_android_SystemStats.cpp b/src/native/android/juce_android_SystemStats.cpp index 08bc778a37..9ad1f33fee 100644 --- a/src/native/android/juce_android_SystemStats.cpp +++ b/src/native/android/juce_android_SystemStats.cpp @@ -27,13 +27,234 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +JNIClassBase::JNIClassBase (const char* classPath_) + : classPath (classPath_), classRef (0) +{ + getClasses().add (this); +} + +JNIClassBase::~JNIClassBase() +{ + getClasses().removeValue (this); +} + +Array& JNIClassBase::getClasses() +{ + static Array classes; + return classes; +} + +void JNIClassBase::initialise (JNIEnv* env) +{ + classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath)); + jassert (classRef != 0); + + initialiseFields (env); +} + +void JNIClassBase::release (JNIEnv* env) +{ + env->DeleteGlobalRef (classRef); +} + +void JNIClassBase::initialiseAllClasses (JNIEnv* env) +{ + Array& classes = getClasses(); + for (int i = classes.size(); --i >= 0;) + classes.getUnchecked(i)->initialise (env); +} + +void JNIClassBase::releaseAllClasses (JNIEnv* env) +{ + Array& classes = getClasses(); + for (int i = classes.size(); --i >= 0;) + classes.getUnchecked(i)->release (env); +} + +jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params) +{ + jmethodID m = env->GetMethodID (classRef, methodName, params); + jassert (m != 0); + return m; +} + +jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params) +{ + jmethodID m = env->GetStaticMethodID (classRef, methodName, params); + jassert (m != 0); + return m; +} + +jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature) +{ + jfieldID f = env->GetFieldID (classRef, fieldName, signature); + jassert (f != 0); + return f; +} + +jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature) +{ + jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature); + jassert (f != 0); + return f; +} + +//============================================================================== +class ThreadLocalJNIEnvHolder +{ +public: + ThreadLocalJNIEnvHolder() + : jvm (nullptr) + { + zeromem (threads, sizeof (threads)); + zeromem (envs, sizeof (envs)); + } + + void initialise (JNIEnv* env) + { + env->GetJavaVM (&jvm); + addEnv (env); + } + + void attach() + { + JNIEnv* env = nullptr; + jvm->AttachCurrentThread (&env, 0); + + if (env != 0) + addEnv (env); + } + + void detach() + { + jvm->DetachCurrentThread(); + + const pthread_t thisThread = pthread_self(); + + SpinLock::ScopedLockType sl (addRemoveLock); + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + threads[i] = 0; + } + + JNIEnv* get() const noexcept + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + if (threads[i] == thisThread) + return envs[i]; + + return nullptr; + } + + enum { maxThreads = 16 }; + +private: + JavaVM* jvm; + pthread_t threads [maxThreads]; + JNIEnv* envs [maxThreads]; + SpinLock addRemoveLock; + + void addEnv (JNIEnv* env) + { + SpinLock::ScopedLockType sl (addRemoveLock); + + if (get() == nullptr) + { + const pthread_t thisThread = pthread_self(); + + for (int i = 0; i < maxThreads; ++i) + { + if (threads[i] == 0) + { + envs[i] = env; + threads[i] = thisThread; + return; + } + } + } + + jassertfalse; // too many threads! + } +}; + +static ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder; + +JNIEnv* getEnv() noexcept +{ + return threadLocalJNIEnvHolder.get(); +} + +//============================================================================== +AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0) +{ +} + +void AndroidSystem::initialise (JNIEnv* env, jobject activity_, + jstring appFile_, jstring appDataDir_) +{ + JNIClassBase::initialiseAllClasses (env); + + threadLocalJNIEnvHolder.initialise (env); + activity = GlobalRef (activity_); + appFile = juceString (env, appFile_); + appDataDir = juceString (env, appDataDir_); +} + +void AndroidSystem::shutdown (JNIEnv* env) +{ + activity.clear(); + JNIClassBase::releaseAllClasses (env); +} + +jobject AndroidSystem::createPaint (Graphics::ResamplingQuality quality) +{ + jint constructorFlags = 1 /*ANTI_ALIAS_FLAG*/ + | 4 /*DITHER_FLAG*/ + | 128 /*SUBPIXEL_TEXT_FLAG*/; + + if (quality > Graphics::lowResamplingQuality) + constructorFlags |= 2; /*FILTER_BITMAP_FLAG*/ + + return getEnv()->NewObject (Paint, Paint.constructor, constructorFlags); +} + +const jobject AndroidSystem::createMatrix (JNIEnv* env, const AffineTransform& t) +{ + jobject m = env->NewObject (Matrix, Matrix.constructor); + + jfloat values[9] = { t.mat00, t.mat01, t.mat02, + t.mat10, t.mat11, t.mat12, + 0.0f, 0.0f, 1.0f }; + + jfloatArray javaArray = env->NewFloatArray (9); + env->SetFloatArrayRegion (javaArray, 0, 9, values); + + env->CallVoidMethod (m, Matrix.setValues, javaArray); + env->DeleteLocalRef (javaArray); + + return m; +} + +AndroidSystem android; + //============================================================================== namespace AndroidStatsHelpers { + //============================================================================== + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;") + + DECLARE_JNI_CLASS (SystemClass, "java/lang/System"); + #undef JNI_CLASS_MEMBERS + + //============================================================================== String getSystemProperty (const String& name) { - return juceString (LocalRef ((jstring) getEnv()->CallStaticObjectMethod (android.systemClass, - android.getProperty, + return juceString (LocalRef ((jstring) getEnv()->CallStaticObjectMethod (SystemClass, + SystemClass.getProperty, javaString (name).get()))); } } @@ -51,11 +272,11 @@ String SystemStats::getOperatingSystemName() bool SystemStats::isOperatingSystem64Bit() { - #if JUCE_64BIT + #if JUCE_64BIT return true; - #else + #else return false; - #endif + #endif } String SystemStats::getCpuVendor() @@ -70,13 +291,11 @@ int SystemStats::getCpuSpeedInMegaherz() int SystemStats::getMemorySizeInMegabytes() { - // xxx they forgot to implement sysinfo in the library, dammit! Should put this stuff back when they fix it. -/* struct sysinfo sysi; + struct sysinfo sysi; if (sysinfo (&sysi) == 0) return (sysi.totalram * sysi.mem_unit / (1024 * 1024)); - */ - DBG ("warning! memory size is unavailable due to an Android bug!"); + return 0; } @@ -159,5 +378,10 @@ bool Time::setSystemTimeToThisTime() const return false; } +//============================================================================== +// This is an unsatisfactory workaround for a linker warning that appeared in NDK5c. +// If anyone actually understands what this symbol is for and why the linker gets confused by it, +// please let me know! +extern "C" { void* __dso_handle = 0; } #endif diff --git a/src/native/android/juce_android_Windowing.cpp b/src/native/android/juce_android_Windowing.cpp index ae7dfae94a..e2f95f702f 100644 --- a/src/native/android/juce_android_Windowing.cpp +++ b/src/native/android/juce_android_Windowing.cpp @@ -27,6 +27,34 @@ // compiled on its own). #if JUCE_INCLUDED_FILE +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ + METHOD (getClipBounds, "getClipBounds", "()Landroid/graphics/Rect;") + +DECLARE_JNI_CLASS (CanvasMinimal, "android/graphics/Canvas"); +#undef JNI_CLASS_MEMBERS + +//============================================================================== +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ + METHOD (setViewName, "setViewName", "(Ljava/lang/String;)V") \ + METHOD (layout, "layout", "(IIII)V") \ + METHOD (getLeft, "getLeft", "()I") \ + METHOD (getTop, "getTop", "()I") \ + METHOD (getWidth, "getWidth", "()I") \ + METHOD (getHeight, "getHeight", "()I") \ + METHOD (getLocationOnScreen, "getLocationOnScreen", "([I)V") \ + METHOD (bringToFront, "bringToFront", "()V") \ + METHOD (requestFocus, "requestFocus", "()Z") \ + METHOD (setVisible, "setVisible", "(Z)V") \ + METHOD (isVisible, "isVisible", "()Z") \ + METHOD (hasFocus, "hasFocus", "()Z") \ + METHOD (invalidate, "invalidate", "(IIII)V") \ + METHOD (containsPoint, "containsPoint", "(II)Z") \ + +DECLARE_JNI_CLASS (ComponentPeerView, "com/juce/ComponentPeerView"); +#undef JNI_CLASS_MEMBERS + //============================================================================== class AndroidComponentPeer : public ComponentPeer @@ -35,7 +63,7 @@ public: //============================================================================== AndroidComponentPeer (Component* const component, const int windowStyleFlags) : ComponentPeer (component, windowStyleFlags), - view (android.activity.callObjectMethod (android.createNewView, component->isOpaque())), + view (android.activity.callObjectMethod (JuceAppActivity.createNewView, component->isOpaque())), usingAndroidGraphics (false), fullScreen (false), sizeAllocated (0) @@ -48,7 +76,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - android.activity.callVoidMethod (android.deleteView, view.get()); + android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get()); } else { @@ -63,7 +91,7 @@ public: void messageCallback() { - android.activity.callVoidMethod (android.deleteView, view.get()); + android.activity.callVoidMethod (JuceAppActivity.deleteView, view.get()); } private: @@ -85,7 +113,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - view.callVoidMethod (android.setVisible, shouldBeVisible); + view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); } else { @@ -100,7 +128,7 @@ public: void messageCallback() { - view.callVoidMethod (android.setVisible, shouldBeVisible); + view.callVoidMethod (ComponentPeerView.setVisible, shouldBeVisible); } private: @@ -114,7 +142,7 @@ public: void setTitle (const String& title) { - view.callVoidMethod (android.setViewName, javaString (title).get()); + view.callVoidMethod (ComponentPeerView.setViewName, javaString (title).get()); } void setPosition (int x, int y) @@ -137,7 +165,7 @@ public: w = jmax (0, w); h = jmax (0, h); - view.callVoidMethod (android.layout, x, y, x + w, y + h); + view.callVoidMethod (ComponentPeerView.layout, x, y, x + w, y + h); } else { @@ -152,7 +180,7 @@ public: void messageCallback() { - view.callVoidMethod (android.layout, x, y, x + w, y + h); + view.callVoidMethod (ComponentPeerView.layout, x, y, x + w, y + h); } private: @@ -166,16 +194,16 @@ public: const Rectangle getBounds() const { - return Rectangle (view.callIntMethod (android.getLeft), - view.callIntMethod (android.getTop), - view.callIntMethod (android.getWidth), - view.callIntMethod (android.getHeight)); + return Rectangle (view.callIntMethod (ComponentPeerView.getLeft), + view.callIntMethod (ComponentPeerView.getTop), + view.callIntMethod (ComponentPeerView.getWidth), + view.callIntMethod (ComponentPeerView.getHeight)); } const Point getScreenPosition() const { - return Point (view.callIntMethod (android.getLeft), - view.callIntMethod (android.getTop)); + return Point (view.callIntMethod (ComponentPeerView.getLeft), + view.callIntMethod (ComponentPeerView.getTop)); } const Point localToGlobal (const Point& relativePosition) @@ -227,7 +255,8 @@ public: { return isPositiveAndBelow (position.getX(), component->getWidth()) && isPositiveAndBelow (position.getY(), component->getHeight()) - && ((! trueIfInAChildWindow) || view.callBooleanMethod (android.containsPoint, position.getX(), position.getY())); + && ((! trueIfInAChildWindow) || view.callBooleanMethod (ComponentPeerView.containsPoint, + position.getX(), position.getY())); } const BorderSize getFrameSize() const @@ -244,7 +273,7 @@ public: void toFront (bool makeActive) { - view.callVoidMethod (android.bringToFront); + view.callVoidMethod (ComponentPeerView.bringToFront); if (makeActive) grabFocus(); @@ -283,12 +312,12 @@ public: //============================================================================== bool isFocused() const { - return view.callBooleanMethod (android.hasFocus); + return view.callBooleanMethod (ComponentPeerView.hasFocus); } void grabFocus() { - view.callBooleanMethod (android.requestFocus); + view.callBooleanMethod (ComponentPeerView.requestFocus); } void handleFocusChangeCallback (bool hasFocus) @@ -307,20 +336,20 @@ public: //============================================================================== void handlePaintCallback (JNIEnv* env, jobject canvas) { -#if USE_ANDROID_CANVAS + #if USE_ANDROID_CANVAS if (usingAndroidGraphics) { AndroidLowLevelGraphicsContext g (canvas); handlePaint (g); } else -#endif + #endif { - jobject rect = env->CallObjectMethod (canvas, android.getClipBounds2); - const int left = env->GetIntField (rect, android.rectLeft); - const int top = env->GetIntField (rect, android.rectTop); - const int right = env->GetIntField (rect, android.rectRight); - const int bottom = env->GetIntField (rect, android.rectBottom); + jobject rect = env->CallObjectMethod (canvas, CanvasMinimal.getClipBounds); + const int left = env->GetIntField (rect, RectClass.left); + const int top = env->GetIntField (rect, RectClass.top); + const int right = env->GetIntField (rect, RectClass.right); + const int bottom = env->GetIntField (rect, RectClass.bottom); env->DeleteLocalRef (rect); const Rectangle clip (left, top, right - left, bottom - top); @@ -350,7 +379,7 @@ public: env->ReleaseIntArrayElements ((jintArray) buffer.get(), dest, 0); - env->CallVoidMethod (canvas, android.drawMemoryBitmap, (jintArray) buffer.get(), 0, clip.getWidth(), + env->CallVoidMethod (canvas, CanvasMinimal.drawBitmap, (jintArray) buffer.get(), 0, clip.getWidth(), (jfloat) clip.getX(), (jfloat) clip.getY(), clip.getWidth(), clip.getHeight(), true, (jobject) 0); } @@ -361,7 +390,7 @@ public: { if (MessageManager::getInstance()->isThisTheMessageThread()) { - view.callVoidMethod (android.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); + view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); } else { @@ -376,7 +405,7 @@ public: void messageCallback() { - view.callVoidMethod (android.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); + view.callVoidMethod (ComponentPeerView.invalidate, area.getX(), area.getY(), area.getRight(), area.getBottom()); } private: @@ -511,25 +540,16 @@ Point AndroidComponentPeer::lastMousePos; JUCE_JNI_CALLBACK (ComponentPeerView, javaMethodName, returnType, params) \ { \ AndroidComponentPeer* const peer = AndroidComponentPeer::findPeerForJavaView (view); \ - if (peer != 0) \ + if (peer != nullptr) \ peer->juceMethodInvocation; \ } -JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), - handlePaintCallback (env, canvas)) - -JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseDownCallback ((float) x, (float) y, (int64) time)) -JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseDragCallback ((float) x, (float) y, (int64) time)) -JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), - handleMouseUpCallback ((float) x, (float) y, (int64) time)) - -JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), - handleMovedOrResized()) - -JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), - handleFocusChangeCallback (hasFocus)) +JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jobject canvas), handlePaintCallback (env, canvas)) +JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseDownCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseDragCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv*, jobject view, jfloat x, jfloat y, jlong time), handleMouseUpCallback ((float) x, (float) y, (int64) time)) +JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv*, jobject view), handleMovedOrResized()) +JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv*, jobject view, jboolean hasFocus), handleFocusChangeCallback (hasFocus)) //============================================================================== ComponentPeer* Component::createNewPeer (int styleFlags, void*) @@ -596,7 +616,7 @@ void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIcon const String& title, const String& message, Component* associatedComponent) { - android.activity.callVoidMethod (android.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0); + android.activity.callVoidMethod (JuceAppActivity.showMessageBox, javaString (title).get(), javaString (message).get(), (jlong) 0); } bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType, @@ -606,7 +626,7 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType { jassert (callback != 0); // on android, all alerts must be non-modal!! - android.activity.callVoidMethod (android.showOkCancelBox, javaString (title).get(), javaString (message).get(), + android.activity.callVoidMethod (JuceAppActivity.showOkCancelBox, javaString (title).get(), javaString (message).get(), (jlong) (pointer_sized_int) callback); return false; } @@ -618,7 +638,7 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy { jassert (callback != 0); // on android, all alerts must be non-modal!! - android.activity.callVoidMethod (android.showYesNoCancelBox, javaString (title).get(), javaString (message).get(), + android.activity.callVoidMethod (JuceAppActivity.showYesNoCancelBox, javaString (title).get(), javaString (message).get(), (jlong) (pointer_sized_int) callback); return 0; } diff --git a/src/native/common/juce_posix_SharedCode.h b/src/native/common/juce_posix_SharedCode.h index ec8eac7346..cf7bd95fa4 100644 --- a/src/native/common/juce_posix_SharedCode.h +++ b/src/native/common/juce_posix_SharedCode.h @@ -776,6 +776,12 @@ void* threadEntryProc (void* userData) JUCE_AUTORELEASEPOOL #if JUCE_ANDROID + struct AndroidThreadScope + { + AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); } + ~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); } + }; + const AndroidThreadScope androidEnv; #endif