1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-16 00:34:19 +00:00

Android: Moved more Java code into C++

This commit is contained in:
hogliux 2017-08-04 18:49:14 +01:00
parent b2db1f48c1
commit 1b7d30f0f4
14 changed files with 623 additions and 433 deletions

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -385,23 +383,6 @@ public class JuceDemo extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -965,6 +946,38 @@ public class JuceDemo extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -1268,36 +1281,6 @@ public class JuceDemo extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -1314,23 +1312,6 @@ public class MidiTest extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -1894,6 +1875,38 @@ public class MidiTest extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -2197,36 +2210,6 @@ public class MidiTest extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -385,23 +383,6 @@ public class JUCENetworkGraphicsDemo extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -965,6 +946,38 @@ public class JUCENetworkGraphicsDemo extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -1268,36 +1281,6 @@ public class JUCENetworkGraphicsDemo extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -385,23 +383,6 @@ public class OSCReceiver extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -965,6 +946,38 @@ public class OSCReceiver extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -1268,36 +1281,6 @@ public class OSCReceiver extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -385,23 +383,6 @@ public class OSCSender extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -965,6 +946,38 @@ public class OSCSender extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -1268,36 +1281,6 @@ public class OSCSender extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -1314,23 +1312,6 @@ public class JuceDemoPlugin extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -1894,6 +1875,38 @@ public class JuceDemoPlugin extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -2197,36 +2210,6 @@ public class JuceDemoPlugin extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -1314,23 +1312,6 @@ public class AudioPerformanceTest extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -1894,6 +1875,38 @@ public class AudioPerformanceTest extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -2197,36 +2210,6 @@ public class AudioPerformanceTest extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest;
import java.util.concurrent.CancellationException;
import java.util.concurrent.Future;
@ -302,23 +300,6 @@ public class JuceAppActivity extends Activity
private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
//==============================================================================
private ViewHolder viewHolder;
private MidiDeviceManager midiDeviceManager = null;
@ -882,6 +863,38 @@ public class JuceAppActivity extends Activity
private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//==============================================================================
public static class HTTPStream
{
@ -1185,36 +1198,6 @@ public class JuceAppActivity extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
{
new SingleMediaScanner (this, filename);
}
public final Typeface getTypeFaceFromAsset (String assetName)
{
try

View file

@ -20,6 +20,46 @@
==============================================================================
*/
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(Landroid/content/Context;Landroid/media/MediaScannerConnection$MediaScannerConnectionClient;)V") \
METHOD (connect, "connect", "()V") \
METHOD (disconnect, "disconnect", "()V") \
METHOD (scanFile, "scanFile", "(Ljava/lang/String;Ljava/lang/String;)V") \
DECLARE_JNI_CLASS (MediaScannerConnection, "android/media/MediaScannerConnection");
#undef JNI_CLASS_MEMBERS
//==============================================================================
class MediaScannerConnectionClient : public AndroidInterfaceImplementer
{
public:
virtual void onMediaScannerConnected() = 0;
virtual void onScanCompleted() = 0;
private:
jobject invoke (jobject proxy, jobject method, jobjectArray args) override
{
auto* env = getEnv();
auto methodName = juceString ((jstring) env->CallObjectMethod (method, Method.getName));
if (methodName == "onMediaScannerConnected")
{
onMediaScannerConnected();
return nullptr;
}
else if (methodName == "onScanCompleted")
{
onScanCompleted();
return nullptr;
}
return AndroidInterfaceImplementer::invoke (proxy, method, args);
}
};
//==============================================================================
bool File::isOnCDRomDrive() const
{
return false;
@ -100,3 +140,49 @@ JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const
void File::revealToUser() const
{
}
//==============================================================================
class SingleMediaScanner : public MediaScannerConnectionClient
{
public:
SingleMediaScanner (const String& filename)
: msc (getEnv()->NewObject (MediaScannerConnection,
MediaScannerConnection.constructor,
android.activity.get(),
CreateJavaInterface (this, "android/media/MediaScannerConnection$MediaScannerConnectionClient").get())),
file (filename)
{
getEnv()->CallVoidMethod (msc.get(), MediaScannerConnection.connect);
}
void onMediaScannerConnected() override
{
auto* env = getEnv();
env->CallVoidMethod (msc.get(), MediaScannerConnection.scanFile, javaString (file).get(), 0);
}
void onScanCompleted() override
{
getEnv()->CallVoidMethod (msc.get(), MediaScannerConnection.disconnect);
}
private:
GlobalRef msc;
String file;
};
void FileOutputStream::flushInternal()
{
if (fileHandle != 0)
{
if (fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
new SingleMediaScanner (file.getFullPathName());
}
}

View file

@ -40,10 +40,11 @@ extern JNIEnv* attachAndroidJNI() noexcept;
class GlobalRef
{
public:
inline GlobalRef() noexcept : obj (0) {}
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
~GlobalRef() { clear(); }
inline GlobalRef() noexcept : obj (0) {}
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
inline GlobalRef (GlobalRef && other) noexcept : obj (0) { std::swap (other.obj, obj); }
~GlobalRef() { clear(); }
inline void clear()
{
@ -62,6 +63,14 @@ public:
return *this;
}
inline GlobalRef& operator= (GlobalRef&& other)
{
clear();
std::swap (obj, other.obj);
return *this;
}
//==============================================================================
inline operator jobject() const noexcept { return obj; }
inline jobject get() const noexcept { return obj; }
@ -98,7 +107,7 @@ public:
private:
//==============================================================================
jobject obj;
jobject obj = 0;
static inline jobject retain (jobject obj)
{
@ -111,14 +120,19 @@ template <typename JavaType>
class LocalRef
{
public:
explicit inline LocalRef () noexcept : obj (0) {}
explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
inline LocalRef (LocalRef&& other) noexcept : obj (0) { std::swap (obj, other.obj); }
~LocalRef() { clear(); }
void clear()
{
if (obj != 0)
{
getEnv()->DeleteLocalRef (obj);
obj = 0;
}
}
LocalRef& operator= (const LocalRef& other)
@ -129,6 +143,13 @@ public:
return *this;
}
LocalRef& operator= (LocalRef&& other)
{
clear();
std::swap (other.obj, obj);
return *this;
}
inline operator JavaType() const noexcept { return obj; }
inline JavaType get() const noexcept { return obj; }
@ -261,7 +282,6 @@ extern AndroidSystem android;
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
METHOD (deleteView, "deleteView", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
METHOD (createNativeSurfaceView, "createNativeSurfaceView", "(J)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$NativeSurfaceView;") \
METHOD (postMessage, "postMessage", "(J)V") \
METHOD (finish, "finish", "()V") \
METHOD (setRequestedOrientation,"setRequestedOrientation", "(I)V") \
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
@ -279,7 +299,6 @@ extern AndroidSystem android;
STATICMETHOD (getMusicFolder, "getMusicFolder", "()Ljava/lang/String;") \
STATICMETHOD (getDownloadsFolder, "getDownloadsFolder", "()Ljava/lang/String;") \
STATICMETHOD (getMoviesFolder, "getMoviesFolder", "()Ljava/lang/String;") \
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V") \
METHOD (getTypeFaceFromAsset, "getTypeFaceFromAsset", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
METHOD (getTypeFaceFromByteArray,"getTypeFaceFromByteArray","([B)Landroid/graphics/Typeface;") \
METHOD (setScreenSaver, "setScreenSaver", "(Z)V") \
@ -293,6 +312,7 @@ extern AndroidSystem android;
METHOD (isPermissionGranted, "isPermissionGranted", "(I)Z" ) \
METHOD (isPermissionDeclaredInManifest, "isPermissionDeclaredInManifest", "(I)Z" ) \
METHOD (getSystemService, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;") \
STATICMETHOD (createInvocationHandler, "createInvocationHandler", "(J)Ljava/lang/reflect/InvocationHandler;") \
DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH);
#undef JNI_CLASS_MEMBERS
@ -332,3 +352,76 @@ DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
#undef JNI_CLASS_MEMBERS
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getName, "getName", "()Ljava/lang/String;") \
METHOD (getModifiers, "getModifiers", "()I") \
METHOD (getParameterTypes, "getParameterTypes", "()[Ljava/lang/Class;") \
METHOD (getReturnType, "getReturnType", "()Ljava/lang/Class;") \
METHOD (invoke, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;") \
METHOD (hashCode, "hashCode", "()I") \
METHOD (equals, "equals", "(Ljava/lang/Object;)Z") \
DECLARE_JNI_CLASS (Method, "java/lang/reflect/Method");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getName, "getName", "()Ljava/lang/String;") \
METHOD (getModifiers, "getModifiers", "()I") \
METHOD (isAnnotation, "isAnnotation", "()Z") \
METHOD (isAnonymousClass, "isAnonymousClass", "()Z") \
METHOD (isArray, "isArray", "()Z") \
METHOD (isEnum, "isEnum", "()Z") \
METHOD (isInterface, "isInterface", "()Z") \
METHOD (isLocalClass, "isLocalClass", "()Z") \
METHOD (isMemberClass, "isMemberClass", "()Z") \
METHOD (isPrimitive, "isPrimitive", "()Z") \
METHOD (isSynthetic, "isSynthetic", "()Z") \
METHOD (getComponentType, "getComponentType", "()Ljava/lang/Class;") \
METHOD (getSuperclass, "getSuperclass", "()Ljava/lang/Class;") \
METHOD (getClassLoader, "getClassLoader", "()Ljava/lang/ClassLoader;") \
DECLARE_JNI_CLASS (JavaClass, "java/lang/Class");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V") \
DECLARE_JNI_CLASS (JavaObject, "java/lang/Object");
#undef JNI_CLASS_MEMBERS
//==============================================================================
class AndroidInterfaceImplementer;
// This function takes ownership of the implementer. When the returned GlobalRef
// goes out of scope (and no other Java routine has a reference on the return-value)
// then the implementer will be deleted as well.
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames,
LocalRef<jobject> subclass);
//==============================================================================
jobject juce_invokeImplementer (JNIEnv*, jlong, jobject, jobject, jobjectArray);
void juce_dispatchDelete (JNIEnv*, jlong);
//==============================================================================
class AndroidInterfaceImplementer
{
protected:
virtual ~AndroidInterfaceImplementer() {}
virtual jobject invoke (jobject proxy, jobject method, jobjectArray args);
//==============================================================================
friend LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer*, const StringArray&, LocalRef<jobject>);
friend jobject juce_invokeImplementer (JNIEnv*, jlong, jobject, jobject, jobjectArray);
friend void juce_dispatchDelete (JNIEnv*, jlong);
private:
GlobalRef javaSubClass;
};
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames);
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const String& interfaceName);

View file

@ -20,6 +20,13 @@
==============================================================================
*/
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (newProxyInstance, "newProxyInstance", "(Ljava/lang/ClassLoader;[Ljava/lang/Class;Ljava/lang/reflect/InvocationHandler;)Ljava/lang/Object;") \
DECLARE_JNI_CLASS (JavaProxy, "java/lang/reflect/Proxy");
#undef JNI_CLASS_MEMBERS
JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0)
{
getClasses().add (this);
@ -91,6 +98,92 @@ jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, c
return f;
}
//==============================================================================
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames,
LocalRef<jobject> subclass)
{
auto* env = getEnv();
implementer->javaSubClass = GlobalRef (subclass);
// you need to override at least one interface
jassert (interfaceNames.size() > 0);
auto classArray = LocalRef<jobject> (env->NewObjectArray (interfaceNames.size(), JavaClass, nullptr));
LocalRef<jobject> classLoader;
for (auto i = 0; i < interfaceNames.size(); ++i)
{
auto aClass = LocalRef<jobject> (env->FindClass (interfaceNames[i].toRawUTF8()));
if (aClass != nullptr)
{
if (i == 0)
classLoader = LocalRef<jobject> (env->CallObjectMethod (aClass, JavaClass.getClassLoader));
env->SetObjectArrayElement ((jobjectArray) classArray.get(), i, aClass);
}
else
{
// interface class not found
jassertfalse;
}
}
auto invocationHandler = LocalRef<jobject> (env->CallStaticObjectMethod (JuceAppActivity,
JuceAppActivity.createInvocationHandler,
reinterpret_cast<jlong> (implementer)));
return LocalRef<jobject> (env->CallStaticObjectMethod (JavaProxy, JavaProxy.newProxyInstance,
classLoader.get(), classArray.get(),
invocationHandler.get()));
}
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames)
{
return CreateJavaInterface (implementer, interfaceNames,
LocalRef<jobject> (getEnv()->NewObject (JavaObject,
JavaObject.constructor)));
}
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const String& interfaceName)
{
return CreateJavaInterface (implementer, StringArray (interfaceName));
}
jobject AndroidInterfaceImplementer::invoke (jobject /*proxy*/, jobject method, jobjectArray args)
{
auto* env = getEnv();
return env->CallObjectMethod (method, Method.invoke, javaSubClass.get(), args);
}
jobject juce_invokeImplementer (JNIEnv* env, jlong thisPtr, jobject proxy, jobject method, jobjectArray args)
{
setEnv (env);
return reinterpret_cast<AndroidInterfaceImplementer*> (thisPtr)->invoke (proxy, method, args);
}
void juce_dispatchDelete (JNIEnv* env, jlong thisPtr)
{
setEnv (env);
delete reinterpret_cast<AndroidInterfaceImplementer*> (thisPtr);
}
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeInvocationHandler), dispatchInvoke,
jobject, (JNIEnv* env, jobject /*object*/, jlong thisPtr, jobject proxy, jobject method, jobjectArray args))
{
return juce_invokeImplementer (env, thisPtr, proxy, method, args);
}
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeInvocationHandler), dispatchFinalize,
void, (JNIEnv* env, jobject /*object*/, jlong thisPtr))
{
juce_dispatchDelete (env, thisPtr);
}
//==============================================================================
JavaVM* androidJNIJavaVM = nullptr;

View file

@ -554,23 +554,13 @@ ssize_t FileOutputStream::writeInternal (const void* const data, const size_t nu
return result;
}
#ifndef JUCE_ANDROID
void FileOutputStream::flushInternal()
{
if (fileHandle != 0)
{
if (fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
#if JUCE_ANDROID
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
const LocalRef<jstring> t (javaString (file.getFullPathName()));
android.activity.callVoidMethod (JuceAppActivity.scanFile, t.get());
#endif
}
if (fileHandle != 0 && fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
}
#endif
Result FileOutputStream::truncate()
{

View file

@ -20,8 +20,61 @@
==============================================================================
*/
void MessageManager::doPlatformSpecificInitialisation() {}
void MessageManager::doPlatformSpecificShutdown() {}
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V") \
METHOD (post, "post", "(Ljava/lang/Runnable;)Z") \
DECLARE_JNI_CLASS (JNIHandler, "android/os/Handler");
#undef JNI_CLASS_MEMBERS
//==============================================================================
namespace Android
{
class Runnable : public juce::AndroidInterfaceImplementer
{
public:
virtual void run() = 0;
private:
jobject invoke (jobject proxy, jobject method, jobjectArray args) override
{
auto* env = getEnv();
auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, Method.getName));
if (methodName == "run")
{
run();
return nullptr;
}
// invoke base class
return AndroidInterfaceImplementer::invoke (proxy, method, args);
}
};
struct Handler
{
juce_DeclareSingleton (Handler, false)
Handler() : nativeHandler (getEnv()->NewObject (JNIHandler, JNIHandler.constructor)) {}
bool post (Runnable* runnable)
{
return (getEnv()->CallBooleanMethod (nativeHandler.get(), JNIHandler.post,
CreateJavaInterface (runnable, "java/lang/Runnable").get()) != 0);
}
GlobalRef nativeHandler;
};
juce_ImplementSingleton (Handler);
}
//==============================================================================
void MessageManager::doPlatformSpecificInitialisation() { Android::Handler::getInstance(); }
void MessageManager::doPlatformSpecificShutdown() {}
//==============================================================================
bool MessageManager::dispatchNextMessageOnSystemQueue (const bool)
@ -33,26 +86,37 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool)
}
//==============================================================================
struct AndroidMessageCallback : public Android::Runnable
{
AndroidMessageCallback (const MessageManager::MessageBase::Ptr& messageToDeliver)
: message (messageToDeliver)
{}
AndroidMessageCallback (MessageManager::MessageBase::Ptr && messageToDeliver)
: message (static_cast<MessageManager::MessageBase::Ptr&&> (messageToDeliver))
{}
void run() override
{
JUCE_TRY
{
message->messageCallback();
// delete the message already here as Java will only run the
// destructor of this runnable the next time the garbage
// collector kicks in.
message = nullptr;
}
JUCE_CATCH_EXCEPTION
}
MessageManager::MessageBase::Ptr message;
};
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
{
message->incReferenceCount();
android.activity.callVoidMethod (JuceAppActivity.postMessage, (jlong) (pointer_sized_uint) message);
return true;
return Android::Handler::getInstance()->post (new AndroidMessageCallback (message));
}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, deliverMessage, void, (JNIEnv* env, jobject, jlong value))
{
setEnv (env);
JUCE_TRY
{
MessageManager::MessageBase* const message = (MessageManager::MessageBase*) (pointer_sized_uint) value;
message->messageCallback();
message->decReferenceCount();
}
JUCE_CATCH_EXCEPTION
}
//==============================================================================
void MessageManager::broadcastMessage (const String&)
{

View file

@ -284,7 +284,7 @@ char OnlineUnlockStatus::MachineIDUtilities::getPlatformPrefix()
String OnlineUnlockStatus::MachineIDUtilities::getEncodedIDString (const String& input)
{
const String platform (String::charToString (getPlatformPrefix()));
const String platform (String::charToString (static_cast<juce_wchar> (getPlatformPrefix())));
return platform + MD5 ((input + "salt_1" + platform).toUTF8())
.toHexString().substring (0, 9).toUpperCase();