diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 39fc16100..193fc282b 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -84,6 +84,7 @@ static jmethodID loghandler_id; static jobject handler_obj=NULL; static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent *content); +static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *buffer); #ifdef ANDROID void linphone_android_log_handler(int prio, char *str) { @@ -3063,6 +3064,8 @@ extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createFileTransferM return (jlong) message; } + + extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_cancelFileTransfer(JNIEnv* env, jobject thiz, jlong ptr) { linphone_chat_message_cancel_file_transfer((LinphoneChatMessage *)ptr); } @@ -3210,6 +3213,105 @@ extern "C" jint Java_org_linphone_core_LinphoneChatMessageImpl_getStorageId(JNIE return (jint) linphone_chat_message_get_storage_id((LinphoneChatMessage*)ptr); } +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setFileTransferFilepath(JNIEnv* env + ,jobject thiz + ,jlong ptr, jstring jpath) { + const char* path = env->GetStringUTFChars(jpath, NULL); + linphone_chat_message_set_file_transfer_filepath((LinphoneChatMessage*)ptr, path); + env->ReleaseStringUTFChars(jpath, path); +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_downloadFile(JNIEnv* env + ,jobject thiz + ,jlong ptr) { + linphone_chat_message_download_file((LinphoneChatMessage*)ptr); +} + +static void message_state_changed(LinphoneChatMessage* msg, LinphoneChatMessageState state) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageStateChanged","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneChatMessage$State;)V"); + jobject jmessage = getChatMessage(env, msg); + + jclass chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State")); + jmethodID chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass, "fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;"); + env->CallVoidMethod(listener, method, jmessage, env->CallStaticObjectMethod(chatMessageStateClass, chatMessageStateFromIntId, (jint)state)); + + if (state == LinphoneChatMessageStateDelivered || state == LinphoneChatMessageStateNotDelivered) { + env->DeleteGlobalRef(listener); + } +} + +static void file_transfer_progress_indication(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t total) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferProgressChanged", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;II)V"); + jobject jmessage = getChatMessage(env, msg); + env->CallVoidMethod(listener, method, jmessage, content ? create_java_linphone_content(env, content) : NULL, offset, total); +} + +static void file_transfer_recv(LinphoneChatMessage *msg, const LinphoneContent* content, const LinphoneBuffer *buffer) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferReceived", "(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Lorg/linphone/core/LinphoneBuffer;)V"); + jobject jmessage = getChatMessage(env, msg); + env->CallVoidMethod(listener, method, jmessage, content ? create_java_linphone_content(env, content) : NULL, buffer ? create_java_linphone_buffer(env, buffer) : NULL); +} + +static LinphoneBuffer* file_transfer_send(LinphoneChatMessage *msg, const LinphoneContent* content, size_t offset, size_t size) { + JNIEnv *env = 0; + jint result = jvm->AttachCurrentThread(&env,NULL); + if (result != 0) { + ms_error("cannot attach VM\n"); + return NULL; + } + + jobject listener = (jobject) msg->cb_ud; + jclass clazz = (jclass) env->GetObjectClass(listener); + jmethodID method = env->GetMethodID(clazz, "onLinphoneChatMessageFileTransferSent","(Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;IILorg/linphone/core/LinphoneBuffer;)V"); + jobject jmessage = getChatMessage(env, msg); + jobject jbuffer = create_java_linphone_buffer(env, NULL); + env->CallVoidMethod(listener, method, jmessage, content ? create_java_linphone_content(env, content) : NULL, offset, size, jbuffer); + + //TODO + LinphoneBuffer *buffer = linphone_buffer_new(); + return buffer; +} + +extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setListener(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { + jobject listener = env->NewGlobalRef(jlistener); + LinphoneChatMessage *message = (LinphoneChatMessage *)ptr; + LinphoneChatMessageCbs *cbs; + + message->cb_ud = listener; + cbs = linphone_chat_message_get_callbacks(message); + linphone_chat_message_cbs_set_msg_state_changed(cbs, message_state_changed); + linphone_chat_message_cbs_set_file_transfer_progress_indication(cbs, file_transfer_progress_indication); + linphone_chat_message_cbs_set_file_transfer_recv(cbs, file_transfer_recv); + linphone_chat_message_cbs_set_file_transfer_send(cbs, file_transfer_send); +} + extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_unref(JNIEnv* env ,jobject thiz ,jlong ptr) { @@ -3292,11 +3394,15 @@ extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage2(JNIEnv* linphone_chat_room_send_message2((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr, chat_room_impl_callback, (void*)listener); } -extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_startFileDownload(JNIEnv* env, jobject thiz, jlong ptr, jobject jlistener) { - jobject listener = env->NewGlobalRef(jlistener); - LinphoneChatMessage * message = (LinphoneChatMessage *)ptr; - message->cb_ud = listener; - linphone_chat_message_start_file_download(message, chat_room_impl_callback, NULL); +extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendChatMessage(JNIEnv* env + ,jobject thiz + ,jlong chatroom_ptr + ,jobject message + ,jlong messagePtr) { + message = env->NewGlobalRef(message); + linphone_chat_message_ref((LinphoneChatMessage*)messagePtr); + linphone_chat_message_set_user_data((LinphoneChatMessage*)messagePtr, message); + linphone_chat_room_send_chat_message((LinphoneChatRoom*)chatroom_ptr, (LinphoneChatMessage*)messagePtr); } extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv* env @@ -4445,6 +4551,27 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent * return jobj; } +static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *buffer){ + jclass bufferClass; + jmethodID ctor; + jstring jtype, jsubtype, jencoding, jname; + jbyteArray jdata = NULL; + jint jsize = 0; + + bufferClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneBufferImpl")); + ctor = env->GetMethodID(bufferClass,"", "([BI)V"); + jsize = buffer ? (jint) buffer->size : 0; + + if (buffer && buffer->content) { + jdata = env->NewByteArray(buffer->size); + env->SetByteArrayRegion(jdata, 0, buffer->size, (jbyte*)buffer->content); + } + + jobject jobj = env->NewObject(bufferClass, ctor, jdata, jsize); + env->DeleteGlobalRef(bufferClass); + return jobj; +} + /* * Class: org_linphone_core_LinphoneInfoMessageImpl * Method: getContent diff --git a/java/common/org/linphone/core/LinphoneBuffer.java b/java/common/org/linphone/core/LinphoneBuffer.java new file mode 100644 index 000000000..1aee74c18 --- /dev/null +++ b/java/common/org/linphone/core/LinphoneBuffer.java @@ -0,0 +1,15 @@ +package org.linphone.core; + +/** + * The LinphoneContent object representing a data buffer. +**/ +public interface LinphoneBuffer { + + byte[] getContent(); + + void setContent(byte[] data); + + int getSize(); + + void setSize(int size); +} diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index b1b839b5e..b80c3a070 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -4,9 +4,38 @@ import java.util.Vector; public interface LinphoneChatMessage { - interface StateListener{ + @Deprecated + interface StateListener { void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); } + + interface LinphoneChatMessageListener { + void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); + + /** + * This function is called by the core upon an incoming File transfer is started. This function may be call several time for the same file in case of large file. + * @param content incoming content information + * @param buffer holding the received data. Empty buffer means end of file. + */ + void onLinphoneChatMessageFileTransferReceived(LinphoneChatMessage msg, LinphoneContent content, LinphoneBuffer buffer); + + /** + * This function is called by the core when an outgoing file transfer is started. This function is called until size is set to 0. + * @param content incoming content information + * @param offset the offset in the file from where to get the data to be sent + * @param size the number of bytes expected by the framework + * @param bufferToFill A LinphoneBuffer object holding the data written by the application. An empty buffer means end of file. + */ + void onLinphoneChatMessageFileTransferSent(LinphoneChatMessage msg, LinphoneContent content, int offset, int size, LinphoneBuffer bufferToFill); + + /** + * File transfer progress indication callback prototype. + * @param content incoming content information + * @param offset The number of bytes sent/received since the beginning of the transfer. + * @param total The total number of bytes to be sent/received. + */ + void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total); + } public static class State { static private Vector values = new Vector(); private final int mValue; @@ -33,6 +62,10 @@ public interface LinphoneChatMessage { * Message was received(and acknowledged) but cannot get file from server */ public final static State FileTransferError = new State(4,"FileTransferError"); + /** + * File transfer has been completed successfully. + */ + public final static State FileTransferDone = new State(5,"FileTransferDone"); private State(int value,String stringValue) { mValue = value; @@ -158,11 +191,6 @@ public interface LinphoneChatMessage { */ ErrorInfo getErrorInfo(); - /** - * Start the download of the file bundled in the message - */ - void startFileDownload(LinphoneChatMessage.StateListener listener); - /** * Cancel an ongoing file transfer attached to this message.(upload or download). */ @@ -184,4 +212,19 @@ public interface LinphoneChatMessage { */ String getAppData(); + /** + * Set the path to the file to read from or write to during the file transfer. + * @param path The path to the file to use for the file transfer. + */ + void setFileTransferFilepath(String path); + + /** + * Start the download of the file referenced in a LinphoneChatMessage from remote server. + */ + void downloadFile(); + + /** + * Set the callbacks associated with the LinphoneChatMessage. + */ + void setListener(LinphoneChatMessage.LinphoneChatMessageListener listener); } diff --git a/java/common/org/linphone/core/LinphoneChatRoom.java b/java/common/org/linphone/core/LinphoneChatRoom.java index b18e79d0c..f94f4e764 100644 --- a/java/common/org/linphone/core/LinphoneChatRoom.java +++ b/java/common/org/linphone/core/LinphoneChatRoom.java @@ -44,6 +44,7 @@ public interface LinphoneChatRoom { * Send a message to peer member of this chat room. * @param chat message */ + @Deprecated void sendMessage(LinphoneChatMessage message, LinphoneChatMessage.StateListener listener); /** @@ -144,4 +145,9 @@ public interface LinphoneChatRoom { */ LinphoneChatMessage createFileTransferMessage(LinphoneContent content); + /** + * + * @param message + */ + void sendChatMessage(LinphoneChatMessage message); } diff --git a/java/common/org/linphone/core/LinphoneCoreFactory.java b/java/common/org/linphone/core/LinphoneCoreFactory.java index f7d5ccd66..8019ec7bd 100644 --- a/java/common/org/linphone/core/LinphoneCoreFactory.java +++ b/java/common/org/linphone/core/LinphoneCoreFactory.java @@ -145,7 +145,7 @@ abstract public class LinphoneCoreFactory { /** * Create a LinphoneContent object from byte array. */ - abstract public LinphoneContent createLinphoneContent(String type, String subType,byte [] data, String encoding); + abstract public LinphoneContent createLinphoneContent(String type, String subType, byte[] data, String encoding); /** * Create a PresenceActivity object. diff --git a/java/impl/org/linphone/core/LinphoneBufferImpl.java b/java/impl/org/linphone/core/LinphoneBufferImpl.java new file mode 100644 index 000000000..143fd1e17 --- /dev/null +++ b/java/impl/org/linphone/core/LinphoneBufferImpl.java @@ -0,0 +1,33 @@ +package org.linphone.core; + +public class LinphoneBufferImpl implements LinphoneBuffer { + private byte[] mData; + private int mSize; + + public LinphoneBufferImpl(byte[] data, int size) + { + mData = data; + mSize = size; + } + + @Override + public byte[] getContent() { + return mData; + } + + @Override + public void setContent(byte[] data) { + mData = data; + } + + @Override + public int getSize() { + return mSize; + } + + @Override + public void setSize(int size) { + mSize = size; + } + +} diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java index 59a1dc509..8665e4049 100644 --- a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java @@ -15,6 +15,9 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { private native boolean isOutgoing(long ptr); private native void store(long ptr); private native int getStorageId(long ptr); + private native void setFileTransferFilepath(long ptr, String path); + private native void downloadFile(long ptr); + private native void setListener(long ptr, LinphoneChatMessageListener listener); private native void unref(long ptr); protected LinphoneChatMessageImpl(long aNativePtr) { @@ -113,12 +116,6 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { super.finalize(); } - private native void startFileDownload(long ptr, StateListener listener); - @Override - public void startFileDownload(StateListener listener) { - startFileDownload(nativePtr, listener); - } - private native Object getFileTransferInformation(long ptr); @Override public LinphoneContent getFileTransferInformation() { @@ -142,4 +139,19 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage { public void cancelFileTransfer() { cancelFileTransfer(nativePtr); } + + @Override + public void setFileTransferFilepath(String path) { + setFileTransferFilepath(nativePtr, path); + } + + @Override + public void downloadFile() { + downloadFile(nativePtr); + } + + @Override + public void setListener(LinphoneChatMessageListener listener) { + setListener(nativePtr, listener); + } } diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java index 9236bce03..cfda7b6e2 100644 --- a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java +++ b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java @@ -21,6 +21,7 @@ package org.linphone.core; import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneChatMessage.StateListener; +@SuppressWarnings("deprecation") class LinphoneChatRoomImpl implements LinphoneChatRoom { protected final long nativePtr; private native long createLinphoneChatMessage(long ptr, String message); @@ -41,6 +42,7 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { private native long createLinphoneChatMessage2(long ptr, String message, String url, int state, long timestamp, boolean isRead, boolean isIncoming); + private native void sendChatMessage(long ptr, Object message, long messagePtr); protected LinphoneChatRoomImpl(long aNativePtr) { nativePtr = aNativePtr; @@ -176,5 +178,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom { return new LinphoneChatMessageImpl(createFileTransferMessage(nativePtr, content.getName(), content.getType(), content.getSubtype(), content.getRealSize())); } } - + @Override + public void sendChatMessage(LinphoneChatMessage message) { + sendChatMessage(nativePtr, message, ((LinphoneChatMessageImpl)message).getNativePtr()); + } } diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java index 90fd5a0f6..5b2a87c55 100644 --- a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java @@ -154,7 +154,7 @@ public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory { @Override public LinphoneContent createLinphoneContent(String type, String subType, String data) { - return new LinphoneContentImpl(type,subType,data.getBytes(),null); + return new LinphoneContentImpl(type,subType,data == null ? null : data.getBytes(), null); } @Override