Sending pictures through chat
This commit is contained in:
commit
58521a4501
16 changed files with 369 additions and 25 deletions
1
Makefile
1
Makefile
|
@ -74,3 +74,4 @@ clean:
|
|||
ant clean
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
|
|
|
@ -31,4 +31,10 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
|
@ -12,6 +12,12 @@
|
|||
android:textColor="@android:color/black"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
android:autoLink="web"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<string name="default_domain">sip.linphone.org</string>
|
||||
<string name="wizard_url">https://www.linphone.org/wizard.php</string>
|
||||
<string name="upload_url">https://www.linphone.org:444/upload.php</string>
|
||||
|
||||
<!-- Interface settings -->
|
||||
<bool name="use_simple_history">true</bool>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ChatMessage> getMessages(String correspondent) {
|
||||
List<ChatMessage> chatMessages = new ArrayList<ChatMessage>();
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c2e7592a2a349104ed2aa4121e1e4d44633a0908
|
||||
Subproject commit 417d5d93e096c20ddf60da895682e412a779b572
|
Loading…
Reference in a new issue