Browse Source

Refactored the android JNI mechanism.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
b88a1a1815
19 changed files with 1340 additions and 1320 deletions
  1. +2
    -0
      Builds/MacOSX/Juce.xcodeproj/project.pbxproj
  2. +1
    -0
      Builds/VisualStudio2005/Juce.vcproj
  3. +1
    -0
      Builds/VisualStudio2008/Juce.vcproj
  4. +1
    -0
      Builds/VisualStudio2008_DLL/Juce.vcproj
  5. +1
    -0
      Builds/VisualStudio2010/Juce.vcxproj
  6. +3
    -0
      Builds/VisualStudio2010/Juce.vcxproj.filters
  7. +2
    -0
      Builds/iOS/Juce.xcodeproj/project.pbxproj
  8. +2
    -0
      Juce.jucer
  9. +748
    -606
      juce_amalgamated.cpp
  10. +40
    -14
      src/native/android/juce_android_Audio.cpp
  11. +22
    -14
      src/native/android/juce_android_Fonts.cpp
  12. +172
    -70
      src/native/android/juce_android_GraphicsContext.cpp
  13. +2
    -2
      src/native/android/juce_android_Messaging.cpp
  14. +4
    -5
      src/native/android/juce_android_Misc.cpp
  15. +2
    -542
      src/native/android/juce_android_NativeCode.cpp
  16. +31
    -11
      src/native/android/juce_android_Network.cpp
  17. +233
    -9
      src/native/android/juce_android_SystemStats.cpp
  18. +67
    -47
      src/native/android/juce_android_Windowing.cpp
  19. +6
    -0
      src/native/common/juce_posix_SharedCode.h

+ 2
- 0
Builds/MacOSX/Juce.xcodeproj/project.pbxproj View File

@@ -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,


+ 1
- 0
Builds/VisualStudio2005/Juce.vcproj View File

@@ -951,6 +951,7 @@
<File RelativePath="..\..\src\native\android\juce_android_Files.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Fonts.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_GraphicsContext.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_JNIHelpers.h"/>
<File RelativePath="..\..\src\native\android\juce_android_Messaging.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Midi.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Misc.cpp"/>


+ 1
- 0
Builds/VisualStudio2008/Juce.vcproj View File

@@ -951,6 +951,7 @@
<File RelativePath="..\..\src\native\android\juce_android_Files.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Fonts.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_GraphicsContext.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_JNIHelpers.h"/>
<File RelativePath="..\..\src\native\android\juce_android_Messaging.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Midi.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Misc.cpp"/>


+ 1
- 0
Builds/VisualStudio2008_DLL/Juce.vcproj View File

@@ -953,6 +953,7 @@
<File RelativePath="..\..\src\native\android\juce_android_Files.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Fonts.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_GraphicsContext.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_JNIHelpers.h"/>
<File RelativePath="..\..\src\native\android\juce_android_Messaging.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Midi.cpp"/>
<File RelativePath="..\..\src\native\android\juce_android_Misc.cpp"/>


+ 1
- 0
Builds/VisualStudio2010/Juce.vcxproj View File

@@ -794,6 +794,7 @@
<ClInclude Include="..\..\src\native\windows\juce_win32_ComSmartPtr.h"/>
<ClInclude Include="..\..\src\native\windows\juce_win32_HiddenMessageWindow.h"/>
<ClInclude Include="..\..\src\native\windows\juce_win32_NativeIncludes.h"/>
<ClInclude Include="..\..\src\native\android\juce_android_JNIHelpers.h"/>
<ClInclude Include="..\..\src\native\android\juce_android_NativeIncludes.h"/>
<ClInclude Include="..\..\src\text\juce_CharacterFunctions.h"/>
<ClInclude Include="..\..\src\text\juce_CharPointer_ASCII.h"/>


+ 3
- 0
Builds/VisualStudio2010/Juce.vcxproj.filters View File

@@ -2313,6 +2313,9 @@
<ClInclude Include="..\..\src\native\windows\juce_win32_NativeIncludes.h">
<Filter>Juce\Source\native\windows</Filter>
</ClInclude>
<ClInclude Include="..\..\src\native\android\juce_android_JNIHelpers.h">
<Filter>Juce\Source\native\android</Filter>
</ClInclude>
<ClInclude Include="..\..\src\native\android\juce_android_NativeIncludes.h">
<Filter>Juce\Source\native\android</Filter>
</ClInclude>


+ 2
- 0
Builds/iOS/Juce.xcodeproj/project.pbxproj View File

@@ -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,


+ 2
- 0
Juce.jucer View File

@@ -1478,6 +1478,8 @@
file="src/native/android/juce_android_Fonts.cpp"/>
<FILE id="VFjwst" name="juce_android_GraphicsContext.cpp" compile="1"
resource="0" file="src/native/android/juce_android_GraphicsContext.cpp"/>
<FILE id="HolDOi" name="juce_android_JNIHelpers.h" compile="0" resource="0"
file="src/native/android/juce_android_JNIHelpers.h"/>
<FILE id="TV84om" name="juce_android_Messaging.cpp" compile="1" resource="0"
file="src/native/android/juce_android_Messaging.cpp"/>
<FILE id="mJh1wV" name="juce_android_Midi.cpp" compile="1" resource="0"


+ 748
- 606
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 40
- 14
src/native/android/juce_android_Audio.cpp View File

@@ -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, "<init>", "(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, "<init>", "(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();
}
}


+ 22
- 14
src/native/android/juce_android_Fonts.cpp View File

@@ -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<jobject> ignored (paint.callObjectMethod (android.setTypeface, typeface.get()));
const LocalRef<jobject> 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<jfloat> 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<jfloat> 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<int> bounds (left, top, right - left, bottom - top);


+ 172
- 70
src/native/android/juce_android_GraphicsContext.cpp View File

@@ -28,6 +28,107 @@
#if JUCE_INCLUDED_FILE
#if USE_ANDROID_CANVAS
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(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, "<init>", "()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, "<init>", "()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, "<init>", "(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, "<init>", "(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, "<init>", "(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<int>& 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<int>& 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<int> 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<int> 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<int> (left, top, right - left, bottom - top);
@@ -286,8 +388,8 @@ public:
bool isClipEmpty() const
{
LocalRef<jobject> tempRect (getEnv()->NewObject (android.rectClass, android.rectConstructor, 0, 0, 0, 0));
return ! getCanvas().callBooleanMethod (android.getClipBounds, tempRect.get());
LocalRef<jobject> 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<int>& 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 <float>& 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<int> 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<jobject> 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<jobject> createPath (JNIEnv* env, const Path& path)
static LocalRef<jobject> 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<jobject> (p);
}
static const LocalRef<jobject> createPath (JNIEnv* env, const Path& path, const AffineTransform& transform)
static LocalRef<jobject> 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<jobject> createMatrixRef (JNIEnv* env, const AffineTransform& t)
static LocalRef<jobject> createMatrixRef (JNIEnv* env, const AffineTransform& t)
{
return LocalRef<jobject> (android.createMatrix (*env, t));
return LocalRef<jobject> (android.createMatrix (env, t));
}
static const LocalRef<jobject> createRect (JNIEnv* env, const Rectangle<int>& r)
static LocalRef<jobject> createRect (JNIEnv* env, const Rectangle<int>& r)
{
return LocalRef<jobject> (env->NewObject (android.rectClass, android.rectConstructor,
return LocalRef<jobject> (env->NewObject (RectClass, RectClass.constructor,
r.getX(), r.getY(), r.getRight(), r.getBottom()));
}
static const LocalRef<jobject> createRegion (JNIEnv* env, const RectangleList& list)
static LocalRef<jobject> 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<jobject> (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


+ 2
- 2
src/native/android/juce_android_Messaging.cpp View File

@@ -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);
}
};


+ 4
- 5
src/native/android/juce_android_Misc.cpp View File

@@ -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<jstring> t (javaString (text));
android.activity.callVoidMethod (android.setClipboardContent, t.get());
android.activity.callVoidMethod (JuceAppActivity.setClipboardContent, t.get());
}
String SystemClipboard::getTextFromClipboard()
{
const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (android.getClipboardContent));
const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.getClipboardContent));
return juceString (text);
}
#endif

+ 2
- 542
src/native/android/juce_android_NativeCode.cpp View File

@@ -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, "<init>", "()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, "<init>", "(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, "<init>", "()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, "<init>", "(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, "<init>", "(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, "<init>", "(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, "<init>", "()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, "<init>", "(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, "<init>", "(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, "<init>", "(FFFF[I[FLandroid/graphics/Shader$TileMode;)V") \
\
METHOD (radialGradientClass, radialGradientConstructor, "<init>", "(FFF[I[FLandroid/graphics/Shader$TileMode;)V") \
\
METHOD (regionClass, regionConstructor, "<init>", "()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 <typename JavaType>
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<jstring> javaString (const String& s)
{
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
}
static const LocalRef<jstring> javaStringFromChar (const juce_wchar c)
{
char utf8[5] = { 0 };
CharPointer_UTF8 (utf8).write (c);
return LocalRef<jstring> (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"


+ 31
- 11
src/native/android/juce_android_Network.cpp View File

@@ -27,6 +27,26 @@
// compiled on its own).
#if JUCE_INCLUDED_FILE
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()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<MACAddress>& result)
@@ -67,10 +87,10 @@ public:
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
}
LocalRef<jobject> responseHeaderBuffer (env->NewObject (android.stringBufferClass, android.stringBufferConstructor));
LocalRef<jobject> 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<jstring> 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 <jbyte*> (buffer));


+ 233
- 9
src/native/android/juce_android_SystemStats.cpp View File

@@ -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*>& JNIClassBase::getClasses()
{
static Array<JNIClassBase*> 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<JNIClassBase*>& classes = getClasses();
for (int i = classes.size(); --i >= 0;)
classes.getUnchecked(i)->initialise (env);
}
void JNIClassBase::releaseAllClasses (JNIEnv* env)
{
Array<JNIClassBase*>& 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> ((jstring) getEnv()->CallStaticObjectMethod (android.systemClass,
android.getProperty,
return juceString (LocalRef<jstring> ((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

+ 67
- 47
src/native/android/juce_android_Windowing.cpp View File

@@ -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<int> getBounds() const
{
return Rectangle<int> (view.callIntMethod (android.getLeft),
view.callIntMethod (android.getTop),
view.callIntMethod (android.getWidth),
view.callIntMethod (android.getHeight));
return Rectangle<int> (view.callIntMethod (ComponentPeerView.getLeft),
view.callIntMethod (ComponentPeerView.getTop),
view.callIntMethod (ComponentPeerView.getWidth),
view.callIntMethod (ComponentPeerView.getHeight));
}
const Point<int> getScreenPosition() const
{
return Point<int> (view.callIntMethod (android.getLeft),
view.callIntMethod (android.getTop));
return Point<int> (view.callIntMethod (ComponentPeerView.getLeft),
view.callIntMethod (ComponentPeerView.getTop));
}
const Point<int> localToGlobal (const Point<int>& 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<int> 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<int> 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<int> 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;
}


+ 6
- 0
src/native/common/juce_posix_SharedCode.h View File

@@ -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


Loading…
Cancel
Save