diff --git a/res/layout/chat_bubble_alt_outgoing.xml b/res/layout/chat_bubble_alt_outgoing.xml
index 8b2d3ae6a..8a0f994b4 100644
--- a/res/layout/chat_bubble_alt_outgoing.xml
+++ b/res/layout/chat_bubble_alt_outgoing.xml
@@ -5,6 +5,13 @@
android:layout_height="wrap_content"
android:orientation="horizontal" >
+
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1b3454476..001fe9aea 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -301,6 +301,7 @@
+
Account Setup Assistant
diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java
index e76ff7e46..666d77aff 100644
--- a/src/org/linphone/ChatFragment.java
+++ b/src/org/linphone/ChatFragment.java
@@ -21,6 +21,8 @@ import java.util.List;
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.ui.AvatarWithShadow;
@@ -46,7 +48,7 @@ import android.widget.TextView;
/**
* @author Sylvain Berfini
*/
-public class ChatFragment extends Fragment implements OnClickListener, LinphoneOnMessageReceivedListener {
+public class ChatFragment extends Fragment implements OnClickListener, LinphoneOnMessageReceivedListener, LinphoneChatMessage.StateListener {
private LinphoneChatRoom chatRoom;
private View view;
private String sipUri;
@@ -57,6 +59,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
private ScrollView messagesScrollView;
private int previousMessageID;
private Handler mHandler = new Handler();
+ private BubbleChat lastSentMessageBubble;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -93,7 +96,7 @@ 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(), messagesLayout);
+ displayMessage(msg.getId(), msg.getMessage(), msg.getTimestamp(), msg.isIncoming(), msg.getStatus(), messagesLayout);
chatStorage.markMessageAsRead(msg.getId());
}
LinphoneActivity.instance().updateMissedChatCount();
@@ -125,11 +128,14 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
invalidate();
}
- private void displayMessage(final int id, final String message, final String time, final boolean isIncoming, final RelativeLayout layout) {
+ private void displayMessage(final int id, final String message, 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, message, time, isIncoming, previousMessageID);
+ BubbleChat bubble = new BubbleChat(layout.getContext(), id, message, time, isIncoming, status, previousMessageID);
+ if (!isIncoming) {
+ lastSentMessageBubble = bubble;
+ }
previousMessageID = id;
layout.addView(bubble.getView());
registerForContextMenu(bubble.getView());
@@ -170,14 +176,15 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
if (chatRoom != null && message != null && message.getText().length() > 0) {
String messageToSend = message.getText().toString();
message.setText("");
-
- chatRoom.sendMessage(messageToSend);
+
+ LinphoneChatMessage chatMessage = chatRoom.createLinphoneChatMessage(messageToSend);
+ chatRoom.sendMessage(chatMessage, this);
if (LinphoneActivity.isInstanciated()) {
LinphoneActivity.instance().onMessageSent(sipUri, messageToSend);
}
- displayMessage(previousMessageID + 2, messageToSend, String.valueOf(System.currentTimeMillis()), false, messagesLayout);
+ displayMessage(previousMessageID + 2, messageToSend, String.valueOf(System.currentTimeMillis()), false, State.InProgress, messagesLayout);
scrollToEnd();
}
}
@@ -195,10 +202,25 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneO
public void onMessageReceived(LinphoneAddress from, String message) {
if (from.asStringUriOnly().equals(sipUri)) {
int id = previousMessageID + 2;
- displayMessage(id, message, String.valueOf(System.currentTimeMillis()), true, messagesLayout);
+ displayMessage(id, message, String.valueOf(System.currentTimeMillis()), true, null, messagesLayout);
scrollToEnd();
}
}
+
+ @Override
+ public void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state) {
+ final String finalMessage = 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());
+ lastSentMessageBubble.updateStatusView(finalState);
+ }
+ });
+ }
+ }
public String getSipUri() {
return sipUri;
diff --git a/src/org/linphone/ChatMessage.java b/src/org/linphone/ChatMessage.java
index 1b6bc42b3..cbd8b30fa 100644
--- a/src/org/linphone/ChatMessage.java
+++ b/src/org/linphone/ChatMessage.java
@@ -1,4 +1,6 @@
package org.linphone;
+
+import org.linphone.core.LinphoneChatMessage;
/*
ChatMessage.java
Copyright (C) 2012 Belledonne Communications, Grenoble, France
@@ -25,14 +27,16 @@ public class ChatMessage {
private String message;
private String timestamp;
private boolean incoming;
+ private int status;
private int id;
- public ChatMessage(int id, String message, String timestamp, boolean incoming) {
+ public ChatMessage(int id, String message, String timestamp, boolean incoming, int status) {
super();
this.id = id;
this.message = message;
this.timestamp = timestamp;
this.incoming = incoming;
+ this.status = status;
}
public int getId() {
@@ -62,4 +66,12 @@ public class ChatMessage {
public void setIncoming(boolean incoming) {
this.incoming = incoming;
}
+
+ public void setStatus(int status) {
+ this.status = status;
+ }
+
+ public LinphoneChatMessage.State getStatus() {
+ return LinphoneChatMessage.State.fromInt(status);
+ }
}
diff --git a/src/org/linphone/ChatStorage.java b/src/org/linphone/ChatStorage.java
index 8df0b5c23..e50cfd5d0 100644
--- a/src/org/linphone/ChatStorage.java
+++ b/src/org/linphone/ChatStorage.java
@@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import java.util.ArrayList;
import java.util.List;
+import org.linphone.core.LinphoneChatMessage;
+
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@@ -48,6 +50,12 @@ public class ChatStorage {
db.close();
}
+ public void updateMessageStatus(String to, String message, int status) {
+ ContentValues values = new ContentValues();
+ values.put("status", status);
+ db.update(TABLE_NAME, values, "direction LIKE " + OUTGOING + " AND remoteContact LIKE \"" + to + "\" AND message LIKE \"" + message + "\"", null);
+ }
+
public int saveMessage(String from, String to, String message) {
ContentValues values = new ContentValues();
if (from.equals("")) {
@@ -55,11 +63,13 @@ public class ChatStorage {
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());
}
values.put("message", message);
values.put("time", System.currentTimeMillis());
@@ -77,8 +87,9 @@ public class ChatStorage {
int direction = c.getInt(c.getColumnIndex("direction"));
message = c.getString(c.getColumnIndex("message"));
timestamp = c.getString(c.getColumnIndex("time"));
+ int status = c.getInt(c.getColumnIndex("status"));
- ChatMessage chatMessage = new ChatMessage(id, message, timestamp, direction == INCOMING);
+ ChatMessage chatMessage = new ChatMessage(id, message, timestamp, direction == INCOMING, status);
chatMessages.add(chatMessage);
}
@@ -117,7 +128,7 @@ public class ChatStorage {
class ChatHelper extends SQLiteOpenHelper {
- private static final int DATABASE_VERSION = 2;
+ private static final int DATABASE_VERSION = 3;
private static final String DATABASE_NAME = "linphone-android";
ChatHelper(Context context) {
@@ -126,7 +137,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);");
+ 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);");
}
@Override
diff --git a/src/org/linphone/LinphoneActivity.java b/src/org/linphone/LinphoneActivity.java
index eb952a462..06c8a907d 100644
--- a/src/org/linphone/LinphoneActivity.java
+++ b/src/org/linphone/LinphoneActivity.java
@@ -614,6 +614,10 @@ public class LinphoneActivity extends FragmentActivity implements OnClickListene
public void onMessageSent(String to, String message) {
getChatStorage().saveMessage("", to, message);
}
+
+ public void onMessageStateChanged(String to, String message, int newState) {
+ getChatStorage().updateMessageStatus(to, message, newState);
+ }
@Override
public void onRegistrationStateChanged(RegistrationState state) {
diff --git a/src/org/linphone/StatusFragment.java b/src/org/linphone/StatusFragment.java
index d01d45c9b..925ca4557 100644
--- a/src/org/linphone/StatusFragment.java
+++ b/src/org/linphone/StatusFragment.java
@@ -372,7 +372,6 @@ public class StatusFragment extends Fragment {
zrtpToast = new Toast(getActivity());
zrtpToast.setGravity(Gravity.TOP | Gravity.RIGHT, 0, LinphoneUtils.pixelsToDpi(getResources(), 40));
zrtpToast.setDuration(Toast.LENGTH_LONG);
- zrtpToast.setView(layout);
ImageView ok = (ImageView) layout.findViewById(R.id.toastOK);
ok.setOnClickListener(new OnClickListener() {
@@ -419,8 +418,9 @@ public class StatusFragment extends Fragment {
};
- zrtpToast.show();
+ zrtpToast.setView(layout);
hideZrtpToast = false;
+ zrtpToast.show();
zrtpHack.start();
}
diff --git a/src/org/linphone/core/LinphoneChatMessageImpl.java b/src/org/linphone/core/LinphoneChatMessageImpl.java
new file mode 100644
index 000000000..a6c54e10d
--- /dev/null
+++ b/src/org/linphone/core/LinphoneChatMessageImpl.java
@@ -0,0 +1,38 @@
+package org.linphone.core;
+
+public class LinphoneChatMessageImpl implements LinphoneChatMessage {
+ protected final long nativePtr;
+ private native void setUserData(long ptr);
+ private native String getMessage(long ptr);
+ private native LinphoneAddress getPeerAddress(long ptr);
+
+ protected LinphoneChatMessageImpl(long aNativePtr) {
+ nativePtr = aNativePtr;
+ setUserData();
+ }
+
+ public long getNativePtr() {
+ return nativePtr;
+ }
+
+ @Override
+ public Object getUserData() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setUserData() {
+ setUserData(nativePtr);
+ }
+
+ @Override
+ public String getMessage() {
+ return getMessage(nativePtr);
+ }
+
+ @Override
+ public LinphoneAddress getPeerAddress() {
+ return getPeerAddress(nativePtr);
+ }
+}
diff --git a/src/org/linphone/core/LinphoneChatRoomImpl.java b/src/org/linphone/core/LinphoneChatRoomImpl.java
index 3513f3283..806e8b68a 100644
--- a/src/org/linphone/core/LinphoneChatRoomImpl.java
+++ b/src/org/linphone/core/LinphoneChatRoomImpl.java
@@ -22,8 +22,10 @@ import org.linphone.core.LinphoneChatMessage.StateListener;
class LinphoneChatRoomImpl implements LinphoneChatRoom {
protected final long nativePtr;
+ private native long createLinphoneChatMessage(long ptr, String message);
private native long getPeerAddress(long ptr);
private native void sendMessage(long ptr, String message);
+ private native void sendMessage2(long ptr, long message, StateListener listener);
protected LinphoneChatRoomImpl(long aNativePtr) {
nativePtr = aNativePtr;
@@ -36,9 +38,10 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom {
public void sendMessage(String message) {
sendMessage(nativePtr,message);
}
+
@Override
- public void sendMessage(LinphoneChatMessage msg, StateListener listener) {
- // TODO To be implemened
+ public void sendMessage(LinphoneChatMessage message, StateListener listener) {
+ sendMessage2(nativePtr, message.getNativePtr(), listener);
}
@Override
@@ -46,4 +49,8 @@ class LinphoneChatRoomImpl implements LinphoneChatRoom {
// ignore, deprecated.
}
+ @Override
+ public LinphoneChatMessage createLinphoneChatMessage(String message) {
+ return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message));
+ }
}
diff --git a/src/org/linphone/ui/BubbleChat.java b/src/org/linphone/ui/BubbleChat.java
index 69cf44e1e..0e69cb28e 100644
--- a/src/org/linphone/ui/BubbleChat.java
+++ b/src/org/linphone/ui/BubbleChat.java
@@ -24,6 +24,7 @@ import java.util.Map.Entry;
import org.linphone.LinphoneUtils;
import org.linphone.R;
+import org.linphone.core.LinphoneChatMessage;
import android.content.Context;
import android.graphics.Color;
@@ -32,6 +33,7 @@ import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
@@ -74,8 +76,9 @@ public class BubbleChat {
}
private RelativeLayout view;
+ private ImageView statusView;
- public BubbleChat(Context context, int id, String message, String time, boolean isIncoming, int previousID) {
+ public BubbleChat(Context context, int id, String message, String time, boolean isIncoming, LinphoneChatMessage.State status, int previousID) {
view = new RelativeLayout(context);
LayoutParams layoutParams = new LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
@@ -98,45 +101,43 @@ public class BubbleChat {
view.setLayoutParams(layoutParams);
if (context.getResources().getBoolean(R.bool.display_messages_time)) {
+ LinearLayout layout;
if (context.getResources().getBoolean(R.bool.display_time_aside)) {
- LinearLayout layout;
if (isIncoming) {
layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_alt_incoming, null);
} else {
layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_alt_outgoing, null);
}
-
- TextView msgView = (TextView) layout.findViewById(R.id.message);
- if (context.getResources().getBoolean(R.bool.emoticons_in_messages)) {
- msgView.setText(getSmiledText(context, message));
- } else {
- msgView.setText(message);
- }
-
- TextView timeView = (TextView) layout.findViewById(R.id.time);
- timeView.setText(timestampToHumanDate(context, time));
-
- view.addView(layout);
} else {
- LinearLayout layout;
if (isIncoming) {
layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_incoming, null);
} else {
layout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.chat_bubble_outgoing, null);
}
-
- TextView msgView = (TextView) layout.findViewById(R.id.message);
- if (context.getResources().getBoolean(R.bool.emoticons_in_messages)) {
- msgView.setText(getSmiledText(context, message));
- } else {
- msgView.setText(message);
- }
-
- TextView timeView = (TextView) layout.findViewById(R.id.time);
- timeView.setText(timestampToHumanDate(context, time));
-
- view.addView(layout);
}
+
+ TextView msgView = (TextView) layout.findViewById(R.id.message);
+ if (context.getResources().getBoolean(R.bool.emoticons_in_messages)) {
+ msgView.setText(getSmiledText(context, message));
+ } else {
+ msgView.setText(message);
+ }
+
+ TextView timeView = (TextView) layout.findViewById(R.id.time);
+ timeView.setText(timestampToHumanDate(context, time));
+
+ statusView = (ImageView) layout.findViewById(R.id.status);
+ if (statusView != null) {
+ if (status == LinphoneChatMessage.State.Delivered) {
+ statusView.setImageResource(R.drawable.led_connected); //FIXME
+ } else if (status == LinphoneChatMessage.State.NotDelivered) {
+ statusView.setImageResource(R.drawable.led_error); //FIXME
+ } else {
+ statusView.setImageResource(R.drawable.led_inprogress); //FIXME
+ }
+ }
+
+ view.addView(layout);
} else {
TextView messageView = new TextView(context);
messageView.setId(id);
@@ -153,6 +154,21 @@ public class BubbleChat {
}
}
+ public void updateStatusView(LinphoneChatMessage.State status) {
+ if (statusView == null) {
+ return;
+ }
+
+ if (status == LinphoneChatMessage.State.Delivered) {
+ statusView.setImageResource(R.drawable.led_connected); //FIXME
+ } else if (status == LinphoneChatMessage.State.NotDelivered) {
+ statusView.setImageResource(R.drawable.led_error); //FIXME
+ } else {
+ statusView.setImageResource(R.drawable.led_inprogress); //FIXME
+ }
+ view.invalidate();
+ }
+
public View getView() {
return view;
}
diff --git a/submodules/linphone b/submodules/linphone
index 3e7882dab..d74083cfa 160000
--- a/submodules/linphone
+++ b/submodules/linphone
@@ -1 +1 @@
-Subproject commit 3e7882dabf2b486f60d5e0516c50ce195ebd0ac5
+Subproject commit d74083cfaa2d757ab16588490c1844b090687f18