diff --git a/Makefile b/Makefile
index 09345fd3b..6272cf8a0 100644
--- a/Makefile
+++ b/Makefile
@@ -74,3 +74,4 @@ clean:
ant clean
.PHONY: clean
+
diff --git a/res/layout/chat_bubble_alt_incoming.xml b/res/layout/chat_bubble_alt_incoming.xml
index 8080c0c0f..de8d7bb5b 100644
--- a/res/layout/chat_bubble_alt_incoming.xml
+++ b/res/layout/chat_bubble_alt_incoming.xml
@@ -11,6 +11,13 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/chat_bubble_incoming.xml b/res/layout/chat_bubble_incoming.xml
index cb18f054e..91d3fed51 100644
--- a/res/layout/chat_bubble_incoming.xml
+++ b/res/layout/chat_bubble_incoming.xml
@@ -12,6 +12,12 @@
android:textColor="@android:color/black"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
+
+
+
+
sip.linphone.org
https://www.linphone.org/wizard.php
+ https://www.linphone.org:444/upload.php
true
diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java
index 666d77aff..8a40ded69 100644
--- a/src/org/linphone/ChatFragment.java
+++ b/src/org/linphone/ChatFragment.java
@@ -17,21 +17,41 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
import java.util.List;
+import org.apache.http.util.ByteArrayBuffer;
import org.linphone.LinphoneSimpleListener.LinphoneOnMessageReceivedListener;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatMessage.State;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
+import org.linphone.core.Log;
import org.linphone.ui.AvatarWithShadow;
import org.linphone.ui.BubbleChat;
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.provider.MediaStore;
import android.support.v4.app.Fragment;
+import android.support.v4.content.CursorLoader;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
@@ -49,6 +69,7 @@ import android.widget.TextView;
* @author Sylvain Berfini
*/
public class ChatFragment extends Fragment implements OnClickListener, LinphoneOnMessageReceivedListener, LinphoneChatMessage.StateListener {
+ private static final int ADD_PHOTO = 0;
private LinphoneChatRoom chatRoom;
private View view;
private String sipUri;
@@ -60,6 +81,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
private int previousMessageID;
private Handler mHandler = new Handler();
private BubbleChat lastSentMessageBubble;
+ private ProgressDialog mProgressDialog;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -72,6 +94,12 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
contactName = (TextView) view.findViewById(R.id.contactName);
contactPicture = (AvatarWithShadow) view.findViewById(R.id.contactPicture);
+ contactPicture.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ pickImage(); //FIXME: use a specific button instead
+ }
+ });
ImageView sendMessage = (ImageView) view.findViewById(R.id.sendMessage);
sendMessage.setOnClickListener(this);
@@ -96,7 +124,11 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
previousMessageID = -1;
ChatStorage chatStorage = LinphoneActivity.instance().getChatStorage();
for (ChatMessage msg : messagesList) {
- displayMessage(msg.getId(), msg.getMessage(), msg.getTimestamp(), msg.isIncoming(), msg.getStatus(), messagesLayout);
+ if (msg.getMessage() != null) {
+ displayMessage(msg.getId(), msg.getMessage(), msg.getTimestamp(), msg.isIncoming(), msg.getStatus(), messagesLayout);
+ } else {
+ displayImageMessage(msg.getId(), msg.getImage(), msg.getTimestamp(), msg.isIncoming(), msg.getStatus(), messagesLayout);
+ }
chatStorage.markMessageAsRead(msg.getId());
}
LinphoneActivity.instance().updateMissedChatCount();
@@ -132,7 +164,22 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
mHandler.post(new Runnable() {
@Override
public void run() {
- BubbleChat bubble = new BubbleChat(layout.getContext(), id, message, time, isIncoming, status, previousMessageID);
+ BubbleChat bubble = new BubbleChat(layout.getContext(), id, message, null, time, isIncoming, status, previousMessageID);
+ if (!isIncoming) {
+ lastSentMessageBubble = bubble;
+ }
+ previousMessageID = id;
+ layout.addView(bubble.getView());
+ registerForContextMenu(bubble.getView());
+ }
+ });
+ }
+
+ private void displayImageMessage(final int id, final Bitmap image, final String time, final boolean isIncoming, final LinphoneChatMessage.State status, final RelativeLayout layout) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ BubbleChat bubble = new BubbleChat(layout.getContext(), id, null, image, time, isIncoming, status, previousMessageID);
if (!isIncoming) {
lastSentMessageBubble = bubble;
}
@@ -173,6 +220,10 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
@Override
public void onClick(View v) {
+ sendTextMessage();
+ }
+
+ private void sendTextMessage() {
if (chatRoom != null && message != null && message.getText().length() > 0) {
String messageToSend = message.getText().toString();
message.setText("");
@@ -189,6 +240,20 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
}
}
+ private void sendImageMessage(String url, Bitmap bitmap) {
+ if (chatRoom != null && url != null && url.length() > 0) {
+ LinphoneChatMessage chatMessage = chatRoom.createLinphoneChatMessage("");
+ chatMessage.setExternalBodyUrl(url);
+ chatRoom.sendMessage(chatMessage, this);
+
+ if (LinphoneActivity.isInstanciated()) {
+ LinphoneActivity.instance().onMessageSent(sipUri, bitmap);
+ }
+ }
+ displayImageMessage(previousMessageID + 2, bitmap, String.valueOf(System.currentTimeMillis()), false, State.InProgress, messagesLayout);
+ scrollToEnd();
+ }
+
private void scrollToEnd() {
mHandler.postDelayed(new Runnable() {
@Override
@@ -199,10 +264,15 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
}
@Override
- public void onMessageReceived(LinphoneAddress from, String message) {
+ public void onMessageReceived(LinphoneAddress from, LinphoneChatMessage message) {
if (from.asStringUriOnly().equals(sipUri)) {
int id = previousMessageID + 2;
- displayMessage(id, message, String.valueOf(System.currentTimeMillis()), true, null, messagesLayout);
+ if (message.getMessage() != null) {
+ displayMessage(id, message.getMessage(), String.valueOf(System.currentTimeMillis()), true, null, messagesLayout);
+ } else if (message.getExternalBodyUrl() != null) {
+ Bitmap bm = downloadImage(message.getExternalBodyUrl());
+ displayImageMessage(id, bm, String.valueOf(System.currentTimeMillis()), true, null, messagesLayout);
+ }
scrollToEnd();
}
}
@@ -210,12 +280,17 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
@Override
public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) {
final String finalMessage = msg.getMessage();
+ final Bitmap finalImage = downloadImage(msg.getMessage());
final State finalState = state;
if (LinphoneActivity.isInstanciated() && state != State.InProgress) {
mHandler.post(new Runnable() {
@Override
public void run() {
- LinphoneActivity.instance().onMessageStateChanged(sipUri, finalMessage, finalState.toInt());
+ if (finalMessage != null) {
+ LinphoneActivity.instance().onMessageStateChanged(sipUri, finalMessage, finalState.toInt());
+ } else if (finalImage != null) {
+ LinphoneActivity.instance().onMessageStateChanged(sipUri, finalImage, finalState.toInt());
+ }
lastSentMessageBubble.updateStatusView(finalState);
}
});
@@ -225,4 +300,145 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
public String getSipUri() {
return sipUri;
}
+
+ private void pickImage() {
+ //TODO allow user to take a photo or to choose an existing one
+ Intent intent = new Intent();
+ intent.setType("image/*");
+ intent.setAction(Intent.ACTION_GET_CONTENT);
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ startActivityForResult(intent, ADD_PHOTO);
+ }
+
+ public static Bitmap downloadImage(String stringUrl) {
+ URL url;
+ Bitmap bm = null;
+ try {
+ url = new URL(stringUrl);
+ URLConnection ucon = url.openConnection();
+ InputStream is = ucon.getInputStream();
+ BufferedInputStream bis = new BufferedInputStream(is);
+
+ ByteArrayBuffer baf = new ByteArrayBuffer(50);
+ int current = 0;
+ while ((current = bis.read()) != -1) {
+ baf.append((byte) current);
+ }
+
+ byte[] rawImage = baf.toByteArray();
+ bm = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
+ bis.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return bm;
+ }
+
+ private String uploadImage(String filePath, Bitmap file) {
+ String upLoadServerUri = getActivity().getResources().getString(R.string.upload_url);
+
+ File sourceFile = new File(filePath);
+ if (!sourceFile.isFile()) {
+ Log.e("Can't read source file " + filePath + ", upload failed");
+ return null;
+ }
+
+ String response = null;
+ HttpURLConnection conn = null;
+ try {
+ String lineEnd = "\r\n";
+ String twoHyphens = "--";
+ String boundary = "---------------------------14737809831466499882746641449";
+
+ FileInputStream fileInputStream = new FileInputStream(sourceFile);
+ URL url = new URL(upLoadServerUri);
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+ conn.setUseCaches(false);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Connection", "Keep-Alive");
+ conn.setRequestProperty("ENCTYPE", "multipart/form-data");
+ conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
+ conn.setRequestProperty("uploaded_file", sourceFile.getName());
+ DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
+
+ dos.writeBytes(lineEnd + twoHyphens + boundary + lineEnd);
+ dos.writeBytes("Content-Disposition: form-data; name=\"userfile\"; filename=\""+ sourceFile.getName() + "\"" + lineEnd);
+ dos.writeBytes("Content-Type: application/octet-stream" + lineEnd);
+ dos.writeBytes(lineEnd);
+
+ file.compress(CompressFormat.JPEG, 75, dos);
+
+ dos.writeBytes(lineEnd);
+ dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
+
+ fileInputStream.close();
+ dos.flush();
+ dos.close();
+
+ InputStream is = conn.getInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ int bytesRead;
+ byte[] bytes = new byte[1024];
+ while((bytesRead = is.read(bytes)) != -1) {
+ baos.write(bytes, 0, bytesRead);
+ }
+ byte[] bytesReceived = baos.toByteArray();
+ baos.close();
+ is.close();
+
+ response = new String(bytesReceived);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+
+ return response;
+ }
+
+ public String getRealPathFromURI(Uri contentUri) {
+ String[] proj = { MediaStore.Images.Media.DATA };
+ CursorLoader loader = new CursorLoader(getActivity(), contentUri, proj, null, null, null);
+ Cursor cursor = loader.loadInBackground();
+ int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
+ cursor.moveToFirst();
+ return cursor.getString(column_index);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == ADD_PHOTO && resultCode == Activity.RESULT_OK) {
+ final String filePath = getRealPathFromURI(data.getData());
+ mProgressDialog = ProgressDialog.show(getActivity(), "Please wait", "Long operation starts...", true);
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ Bitmap bm = BitmapFactory.decodeFile(filePath);
+ final String url = uploadImage(filePath, bm);
+
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ bm.compress(CompressFormat.JPEG, 75, outStream);
+ bm.recycle();
+ byte[] bitmap = outStream.toByteArray();
+ final Bitmap fbm = BitmapFactory.decodeByteArray(bitmap, 0, bitmap.length);
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mProgressDialog.dismiss();
+ sendImageMessage(url, fbm);
+ }
+ });
+ }
+ }).start();
+ }
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java
index d4b3491df..b8da09b73 100644
--- a/src/org/linphone/ChatListFragment.java
+++ b/src/org/linphone/ChatListFragment.java
@@ -89,6 +89,9 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ if (info == null || info.targetView == null) {
+ return false;
+ }
String sipUri = (String) info.targetView.getTag();
LinphoneActivity.instance().removeFromChatList(sipUri);
diff --git a/src/org/linphone/ChatMessage.java b/src/org/linphone/ChatMessage.java
index cbd8b30fa..b089ca3b4 100644
--- a/src/org/linphone/ChatMessage.java
+++ b/src/org/linphone/ChatMessage.java
@@ -1,6 +1,9 @@
package org.linphone;
import org.linphone.core.LinphoneChatMessage;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
/*
ChatMessage.java
Copyright (C) 2012 Belledonne Communications, Grenoble, France
@@ -29,14 +32,16 @@ public class ChatMessage {
private boolean incoming;
private int status;
private int id;
+ private Bitmap image;
- public ChatMessage(int id, String message, String timestamp, boolean incoming, int status) {
+ public ChatMessage(int id, String message, byte[] rawImage, String timestamp, boolean incoming, int status) {
super();
this.id = id;
this.message = message;
this.timestamp = timestamp;
this.incoming = incoming;
this.status = status;
+ this.image = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length);
}
public int getId() {
@@ -74,4 +79,8 @@ public class ChatMessage {
public LinphoneChatMessage.State getStatus() {
return LinphoneChatMessage.State.fromInt(status);
}
+
+ public Bitmap getImage() {
+ return image;
+ }
}
diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java
index e50cfd5d0..d6e856b88 100644
--- a/src/org/linphone/ChatStorage.java
+++ b/src/org/linphone/ChatStorage.java
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -27,6 +28,8 @@ import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
/**
* @author Sylvain Berfini
@@ -56,6 +59,16 @@ public class ChatStorage {
db.update(TABLE_NAME, values, "direction LIKE " + OUTGOING + " AND remoteContact LIKE \"" + to + "\" AND message LIKE \"" + message + "\"", null);
}
+ public void updateMessageStatus(String to, Bitmap image, int status) {
+ ContentValues values = new ContentValues();
+ values.put("status", status);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ image.compress(CompressFormat.JPEG, 100, baos);
+
+ db.update(TABLE_NAME, values, "direction LIKE " + OUTGOING + " AND remoteContact LIKE \"" + to + "\" AND image LIKE \"" + baos.toByteArray() + "\"", null);
+ }
+
public int saveMessage(String from, String to, String message) {
ContentValues values = new ContentValues();
if (from.equals("")) {
@@ -76,6 +89,30 @@ public class ChatStorage {
return (int) db.insert(TABLE_NAME, null, values);
}
+ public int saveMessage(String from, String to, Bitmap image) {
+ ContentValues values = new ContentValues();
+ if (from.equals("")) {
+ values.put("localContact", from);
+ values.put("remoteContact", to);
+ values.put("direction", OUTGOING);
+ values.put("read", READ);
+ values.put("status", LinphoneChatMessage.State.InProgress.toInt());
+ } else if (to.equals("")) {
+ values.put("localContact", to);
+ values.put("remoteContact", from);
+ values.put("direction", INCOMING);
+ values.put("read", NOT_READ);
+ values.put("status", LinphoneChatMessage.State.Idle.toInt());
+ }
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ image.compress(CompressFormat.JPEG, 100, baos);
+ values.put("image", baos.toByteArray());
+
+ values.put("time", System.currentTimeMillis());
+ return (int) db.insert(TABLE_NAME, null, values);
+ }
+
public List getMessages(String correspondent) {
List chatMessages = new ArrayList();
@@ -88,8 +125,9 @@ public class ChatStorage {
message = c.getString(c.getColumnIndex("message"));
timestamp = c.getString(c.getColumnIndex("time"));
int status = c.getInt(c.getColumnIndex("status"));
+ byte[] rawImage = c.getBlob(c.getColumnIndex("image"));
- ChatMessage chatMessage = new ChatMessage(id, message, timestamp, direction == INCOMING, status);
+ ChatMessage chatMessage = new ChatMessage(id, message, rawImage, timestamp, direction == INCOMING, status);
chatMessages.add(chatMessage);
}
@@ -128,7 +166,7 @@ public class ChatStorage {
class ChatHelper extends SQLiteOpenHelper {
- private static final int DATABASE_VERSION = 3;
+ private static final int DATABASE_VERSION = 4;
private static final String DATABASE_NAME = "linphone-android";
ChatHelper(Context context) {
@@ -137,7 +175,7 @@ public class ChatStorage {
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT NOT NULL, time NUMERIC, read INTEGER, status INTEGER);");
+ db.execSQL("CREATE TABLE " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, localContact TEXT NOT NULL, remoteContact TEXT NOT NULL, direction INTEGER, message TEXT, image BLOB, time NUMERIC, read INTEGER, status INTEGER);");
}
@Override
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index 06c8a907d..d390fd2b9 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -36,6 +36,7 @@ import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallLog;
import org.linphone.core.LinphoneCallLog.CallStatus;
+import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCoreFactory;
@@ -49,6 +50,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -593,8 +595,19 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
@Override
- public void onMessageReceived(LinphoneAddress from, String message) {
- int id = getChatStorage().saveMessage(from.asStringUriOnly(), "", message);
+ public void onMessageReceived(LinphoneAddress from, LinphoneChatMessage message) {
+ String textMessage = message.getMessage();
+ String url = message.getExternalBodyUrl();
+ String notificationText = null;
+ int id = -1;
+ if (textMessage != null && textMessage.length() > 0) {
+ id = getChatStorage().saveMessage(from.asStringUriOnly(), "", textMessage);
+ notificationText = textMessage;
+ } else if (url != null && url.length() > 0) {
+ Bitmap bm = ChatFragment.downloadImage(url);
+ id = getChatStorage().saveMessage(from.asStringUriOnly(), "", bm);
+ notificationText = url;
+ }
ChatFragment chatFragment = ((ChatFragment) messageListenerFragment);
if (messageListenerFragment != null && messageListenerFragment.isVisible() && chatFragment.getSipUri().equals(from.asStringUriOnly())) {
@@ -604,7 +617,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
displayMissedChats(getChatStorage().getUnreadMessageCount());
}
LinphoneUtils.findUriPictureOfContactAndSetDisplayName(from, getContentResolver());
- LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getDisplayName(), message);
+ LinphoneService.instance().displayMessageNotification(from.asStringUriOnly(), from.getDisplayName(), notificationText);
}
public void updateMissedChatCount() {
@@ -615,9 +628,17 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
getChatStorage().saveMessage("", to, message);
}
+ public void onMessageSent(String to, Bitmap image) {
+ getChatStorage().saveMessage("", to, image);
+ }
+
public void onMessageStateChanged(String to, String message, int newState) {
getChatStorage().updateMessageStatus(to, message, newState);
}
+
+ public void onMessageStateChanged(String to, Bitmap image, int newState) {
+ getChatStorage().updateMessageStatus(to, image, newState);
+ }
@Override
public void onRegistrationStateChanged(RegistrationState state) {
@@ -908,8 +929,7 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
}
@Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(resultCode, requestCode, data);
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_FIRST_USER && requestCode == SETTINGS_ACTIVITY) {
if (data.getExtras().getBoolean("Exit", false)) {
exit();
@@ -927,6 +947,9 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
}
}
+ else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
@Override
diff --git a/src/org/linphone/LinphoneManager.java b/src/org/linphone/LinphoneManager.java
index a36b0606f..c1451b6b6 100644
--- a/src/org/linphone/LinphoneManager.java
+++ b/src/org/linphone/LinphoneManager.java
@@ -54,6 +54,7 @@ import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@@ -880,12 +881,16 @@ public final class LinphoneManager implements LinphoneCoreListener {
public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,
LinphoneAddress from, String message) {
+ //deprecated
+ }
+
+ @Override
+ public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, LinphoneChatMessage message) {
for (LinphoneSimpleListener listener : getSimpleListeners(LinphoneActivity.class)) {
((LinphoneActivity) listener).onMessageReceived(from, message);
}
}
-
public String getLastLcStatusMessage() {
return lastLcStatusMessage;
}
diff --git a/src/org/linphone/LinphoneSimpleListener.java b/src/org/linphone/LinphoneSimpleListener.java
index 75106a99c..4af9f1027 100644
--- a/src/org/linphone/LinphoneSimpleListener.java
+++ b/src/org/linphone/LinphoneSimpleListener.java
@@ -21,6 +21,7 @@ package org.linphone;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
+import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
@@ -60,7 +61,7 @@ public interface LinphoneSimpleListener {
}
public static interface LinphoneOnMessageReceivedListener extends LinphoneSimpleListener {
- void onMessageReceived(LinphoneAddress from, String message);
+ void onMessageReceived(LinphoneAddress from, LinphoneChatMessage message);
}
public static interface LinphoneOnRegistrationStateChangedListener extends LinphoneSimpleListener {
diff --git a/src/org/linphone/core/LinphoneChatMessageImpl.java b/src/org/linphone/core/LinphoneChatMessageImpl.java
index a6c54e10d..a93aae85f 100644
--- a/src/org/linphone/core/LinphoneChatMessageImpl.java
+++ b/src/org/linphone/core/LinphoneChatMessageImpl.java
@@ -5,6 +5,8 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage {
private native void setUserData(long ptr);
private native String getMessage(long ptr);
private native LinphoneAddress getPeerAddress(long ptr);
+ private native String getExternalBodyUrl(long ptr);
+ private native void setExternalBodyUrl(long ptr, String url);
protected LinphoneChatMessageImpl(long aNativePtr) {
nativePtr = aNativePtr;
@@ -35,4 +37,14 @@ public class LinphoneChatMessageImpl implements LinphoneChatMessage {
public LinphoneAddress getPeerAddress() {
return getPeerAddress(nativePtr);
}
+
+ @Override
+ public String getExternalBodyUrl() {
+ return getExternalBodyUrl(nativePtr);
+ }
+
+ @Override
+ public void setExternalBodyUrl(String url) {
+ setExternalBodyUrl(nativePtr, url);
+ }
}
diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java
index 70883c7e0..5714ca346 100644
--- a/src/org/linphone/ui/BubbleChat.java
+++ b/src/org/linphone/ui/BubbleChat.java
@@ -27,6 +27,7 @@ import org.linphone.R;
import org.linphone.core.LinphoneChatMessage;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.Color;
import android.text.Html;
import android.text.Spannable;
@@ -81,7 +82,7 @@ public class BubbleChat {
private RelativeLayout view;
private ImageView statusView;
- public BubbleChat(Context context, int id, String message, String time, boolean isIncoming, LinphoneChatMessage.State status, int previousID) {
+ public BubbleChat(Context context, int id, String message, Bitmap image, String time, boolean isIncoming, LinphoneChatMessage.State status, int previousID) {
view = new RelativeLayout(context);
LayoutParams layoutParams = new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
@@ -103,11 +104,13 @@ public class BubbleChat {
layoutParams.setMargins(0, LinphoneUtils.pixelsToDpi(context.getResources(), 10), 0, 0);
view.setLayoutParams(layoutParams);
- Spanned text;
- if (context.getResources().getBoolean(R.bool.emoticons_in_messages)) {
- text = getSmiledText(context, getTextWithHttpLinks(message));
- } else {
- text = getTextWithHttpLinks(message);
+ Spanned text = null;
+ if (message != null) {
+ if (context.getResources().getBoolean(R.bool.emoticons_in_messages)) {
+ text = getSmiledText(context, getTextWithHttpLinks(message));
+ } else {
+ text = getTextWithHttpLinks(message);
+ }
}
if (context.getResources().getBoolean(R.bool.display_messages_time_and_status)) {
@@ -127,8 +130,15 @@ public class BubbleChat {
}
TextView msgView = (TextView) layout.findViewById(R.id.message);
- msgView.setText(text);
- msgView.setMovementMethod(LinkMovementMethod.getInstance());
+ if (message != null && msgView != null) {
+ msgView.setText(text);
+ msgView.setMovementMethod(LinkMovementMethod.getInstance());
+ }
+
+ ImageView imageView = (ImageView) layout.findViewById(R.id.image);
+ if (image != null && imageView != null) {
+ imageView.setImageBitmap(image);
+ }
TextView timeView = (TextView) layout.findViewById(R.id.time);
timeView.setText(timestampToHumanDate(context, time));
diff --git a/submodules/linphone b/submodules/linphone
index c2e7592a2..417d5d93e 160000
--- a/submodules/linphone
+++ b/submodules/linphone
@@ -1 +1 @@
-Subproject commit c2e7592a2a349104ed2aa4121e1e4d44633a0908
+Subproject commit 417d5d93e096c20ddf60da895682e412a779b572