2017-11-08 21:15:07 +01:00
|
|
|
// Author: Ben Lau (https://github.com/benlau)
|
|
|
|
package androidnative;
|
|
|
|
import android.app.Activity;
|
|
|
|
import org.qtproject.qt5.android.QtNative;
|
|
|
|
import java.lang.String;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Queue;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.lang.ClassLoader;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import java.lang.Thread;
|
|
|
|
import android.util.Log;
|
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.Looper;
|
|
|
|
import android.content.Intent;
|
2018-04-11 21:50:43 +02:00
|
|
|
import android.os.*;
|
2017-11-08 21:15:07 +01:00
|
|
|
import java.util.concurrent.Semaphore;
|
|
|
|
import java.io.StringWriter;
|
|
|
|
import java.io.PrintWriter;
|
|
|
|
|
|
|
|
public class SystemDispatcher {
|
|
|
|
|
|
|
|
public interface Listener {
|
|
|
|
/** Every messages posted on SystemMessenger will trigger this function.
|
|
|
|
|
|
|
|
@return true if the message is handled. Otherwise, it should be false.
|
|
|
|
*/
|
|
|
|
public void onDispatched(String type , Map message);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
@threadsafe
|
|
|
|
@remarks: The function may not be running from the UI thread. It is listener's duty to handle multiple threading issue.
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static void dispatch(String name) {
|
|
|
|
dispatch(name,null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Dispatch a message.
|
|
|
|
@threadsafe
|
|
|
|
@remarks: The function may not be running from the UI thread. It is listener's duty to handle multiple threading issue.
|
|
|
|
*/
|
|
|
|
public static void dispatch(String type,Map message) {
|
|
|
|
try {
|
|
|
|
|
|
|
|
Payload payload;
|
|
|
|
|
|
|
|
mutex.acquire();
|
|
|
|
|
|
|
|
if (dispatching) {
|
|
|
|
payload = new Payload();
|
|
|
|
payload.type = type;
|
|
|
|
payload.message = message;
|
|
|
|
queue.add(payload);
|
|
|
|
mutex.release();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispatching = true;
|
|
|
|
mutex.release();
|
|
|
|
|
|
|
|
emit(type,message); // Emit
|
|
|
|
|
|
|
|
mutex.acquire(); // Process queued message
|
|
|
|
|
|
|
|
while (queue.size() > 0 ) {
|
|
|
|
payload = queue.poll();
|
|
|
|
mutex.release();
|
|
|
|
|
|
|
|
emit(payload.type,payload.message);
|
|
|
|
|
|
|
|
mutex.acquire();
|
|
|
|
}
|
|
|
|
dispatching = false;
|
|
|
|
mutex.release();
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(TAG,"exception",e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void addListener(Listener listener ) {
|
|
|
|
try {
|
|
|
|
mutex.acquire();
|
|
|
|
listeners.add(listener);
|
|
|
|
mutex.release();
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(TAG,"exception",e);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void removeListener(Listener listener ) {
|
|
|
|
try {
|
|
|
|
mutex.acquire();
|
|
|
|
listeners.remove(listener);
|
|
|
|
mutex.release();
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.e(TAG,"exception",e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String ACTIVITY_RESUME_MESSAGE = "androidnative.Activity.onResume";
|
|
|
|
|
|
|
|
public static String ACTIVITY_RESULT_MESSAGE = "androidnative.Activity.onActivityResult";
|
|
|
|
|
|
|
|
public static String SYSTEM_DISPATCHER_LOAD_CLASS_MESSAGE = "androidnative.SystemDispatcher.loadClass";
|
|
|
|
|
2018-04-11 21:50:43 +02:00
|
|
|
public static String SYSTEM_DISPATCHER_SET_INITIALIZED_MESSAGE = "androidnative.SystemDispatcher.setInitialized";
|
|
|
|
|
|
|
|
public static boolean isIntentPending=false;
|
|
|
|
|
|
|
|
public static boolean isInitialized=false;
|
|
|
|
|
|
|
|
private static Map waitingIntent;
|
|
|
|
|
2017-11-08 21:15:07 +01:00
|
|
|
/** A helper function to dispatch a massage when onResume is invoked in the Activity class
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static void onActivityResume() {
|
|
|
|
dispatch(ACTIVITY_RESUME_MESSAGE);
|
|
|
|
}
|
|
|
|
|
2018-04-11 21:50:43 +02:00
|
|
|
|
2017-11-08 21:15:07 +01:00
|
|
|
/** A helper function to dispatch a message based on the input argument fron Activity.onActivityResult
|
|
|
|
*/
|
|
|
|
public static void onActivityResult (int requestCode, int resultCode, Intent data) {
|
|
|
|
Map message = new HashMap();
|
2018-04-22 21:12:40 +02:00
|
|
|
|
2017-11-08 21:15:07 +01:00
|
|
|
message.put("requestCode",requestCode);
|
|
|
|
message.put("resultCode",resultCode);
|
|
|
|
message.put("data",data);
|
2018-04-11 21:50:43 +02:00
|
|
|
if(isInitialized) {
|
2017-11-08 21:15:07 +01:00
|
|
|
dispatch(ACTIVITY_RESULT_MESSAGE,message);
|
2018-04-11 21:50:43 +02:00
|
|
|
waitingIntent=null;
|
|
|
|
isIntentPending=false;
|
|
|
|
} else { //onIntent start
|
2018-04-22 21:12:40 +02:00
|
|
|
message.put("text",data.getStringExtra(Intent.EXTRA_TEXT));
|
|
|
|
message.put("subject",data.getStringExtra(Intent.EXTRA_SUBJECT));
|
2018-04-11 21:50:43 +02:00
|
|
|
waitingIntent = message;
|
|
|
|
isIntentPending = true;
|
2018-04-22 21:12:40 +02:00
|
|
|
|
2018-04-11 21:50:43 +02:00
|
|
|
}
|
|
|
|
//onIntent end
|
|
|
|
|
2017-11-08 21:15:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private static class Payload {
|
|
|
|
public String type;
|
|
|
|
public Map message;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static String TAG = "AndroidNative";
|
|
|
|
|
|
|
|
private static final Semaphore mutex = new Semaphore(1);
|
|
|
|
|
|
|
|
private static Queue<Payload> queue = new LinkedList();
|
|
|
|
|
|
|
|
private static List<Listener> listeners = new ArrayList<Listener>();
|
|
|
|
|
|
|
|
private static boolean dispatching = false;
|
|
|
|
|
|
|
|
private static native void jniEmit(String name,Map message);
|
|
|
|
|
|
|
|
/** Emit onDispatched signal to registered listenter
|
|
|
|
*/
|
|
|
|
private static void emit(String name,Map message) {
|
|
|
|
for (int i = 0 ; i < listeners.size() ; i++ ) {
|
|
|
|
Listener listener = listeners.get(i);
|
|
|
|
try {
|
|
|
|
listener.onDispatched(name,message);
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.d(TAG, Log.getStackTraceString(e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
jniEmit(name,message);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void printMap(Map data) {
|
|
|
|
if (data == null)
|
|
|
|
return;
|
|
|
|
try {
|
|
|
|
for (Map.Entry entry : (Set<Map.Entry>) data.entrySet()) {
|
|
|
|
String key = (String) entry.getKey();
|
|
|
|
Object value = entry.getValue();
|
|
|
|
if (value == null)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (value instanceof String) {
|
|
|
|
String stringValue = (String) value;
|
|
|
|
Log.d(TAG,String.format("%s : %s",key,stringValue));
|
|
|
|
} else if (value instanceof Integer) {
|
|
|
|
int intValue = (Integer) value;
|
|
|
|
Log.d(TAG,String.format("%s : %d",key,intValue));
|
|
|
|
} else if (value instanceof Boolean) {
|
|
|
|
Boolean booleanValue = (Boolean) value;
|
|
|
|
Log.d(TAG,String.format("%s : %b",key,booleanValue));
|
|
|
|
} else {
|
|
|
|
Log.d(TAG,String.format("%s : Non-supported data type[%s] is passed",key,value.getClass().getName()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
Log.d(TAG,e.getMessage());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void loadClass(String className) {
|
|
|
|
try {
|
|
|
|
ClassLoader classLoader = SystemDispatcher.class.getClassLoader();
|
|
|
|
Class aClass = Class.forName(className,true,classLoader);
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
|
Log.e(TAG,"Failed to load class: " + className);
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-11 21:50:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
public static void setInitialized() {
|
|
|
|
isInitialized = true;
|
|
|
|
if(isIntentPending) {
|
|
|
|
isIntentPending = false;
|
|
|
|
dispatch(ACTIVITY_RESULT_MESSAGE,waitingIntent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-11-08 21:15:07 +01:00
|
|
|
public static void init() {
|
|
|
|
SystemDispatcher.addListener(new SystemDispatcher.Listener() {
|
|
|
|
public void onDispatched(String type , Map message) {
|
|
|
|
// Log.d(TAG,String.format("%s %b",type ,type.equals(SYSTEM_DISPATCHER_LOAD_CLASS_MESSAGE)));
|
|
|
|
|
|
|
|
if (type.equals(SYSTEM_DISPATCHER_LOAD_CLASS_MESSAGE)) {
|
|
|
|
String className = (String) message.get("className");
|
|
|
|
loadClass(className);
|
|
|
|
}
|
2018-04-11 21:50:43 +02:00
|
|
|
if (type.equals(SYSTEM_DISPATCHER_SET_INITIALIZED_MESSAGE)) {
|
|
|
|
setInitialized();
|
|
|
|
}
|
2017-11-08 21:15:07 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|