diff --git a/res/drawable-xhdpi/chat_attachment_default.png b/res/drawable-xhdpi/chat_attachment_default.png new file mode 100644 index 000000000..8cba3b8c9 Binary files /dev/null and b/res/drawable-xhdpi/chat_attachment_default.png differ diff --git a/res/drawable-xhdpi/chat_attachment_over.png b/res/drawable-xhdpi/chat_attachment_over.png new file mode 100644 index 000000000..97245b742 Binary files /dev/null and b/res/drawable-xhdpi/chat_attachment_over.png differ diff --git a/res/drawable-xhdpi/chat_send_default.png b/res/drawable-xhdpi/chat_send_default.png index 05a49484f..d197d1504 100644 Binary files a/res/drawable-xhdpi/chat_send_default.png and b/res/drawable-xhdpi/chat_send_default.png differ diff --git a/res/drawable-xhdpi/chat_send_over.png b/res/drawable-xhdpi/chat_send_over.png index 3ef4ae40c..a3354fa2b 100644 Binary files a/res/drawable-xhdpi/chat_send_over.png and b/res/drawable-xhdpi/chat_send_over.png differ diff --git a/res/drawable/chat_send_picture.xml b/res/drawable/chat_send_file.xml similarity index 57% rename from res/drawable/chat_send_picture.xml rename to res/drawable/chat_send_file.xml index 84c43169c..a26285ecf 100644 --- a/res/drawable/chat_send_picture.xml +++ b/res/drawable/chat_send_file.xml @@ -1,8 +1,8 @@ + android:drawable="@drawable/chat_attachment_over" /> + android:drawable="@drawable/chat_attachment_default" /> diff --git a/res/drawable/wizard_notok.png b/res/drawable/wizard_notok.png deleted file mode 100644 index c174df390..000000000 Binary files a/res/drawable/wizard_notok.png and /dev/null differ diff --git a/res/drawable/wizard_ok.png b/res/drawable/wizard_ok.png deleted file mode 100644 index f8edc012d..000000000 Binary files a/res/drawable/wizard_ok.png and /dev/null differ diff --git a/res/layout/chat.xml b/res/layout/chat.xml index 079b67d58..a7f38b995 100644 --- a/res/layout/chat.xml +++ b/res/layout/chat.xml @@ -97,7 +97,7 @@ - + android:src="@drawable/chat_send_file" /> - + - + + + \ No newline at end of file diff --git a/res/layout/chat_activity.xml b/res/layout/chat_activity.xml index b70f9391a..34e3c7ae8 100644 --- a/res/layout/chat_activity.xml +++ b/res/layout/chat_activity.xml @@ -1,8 +1,16 @@ + + \ No newline at end of file diff --git a/res/layout/search_contact_cell.xml b/res/layout/search_contact_cell.xml new file mode 100644 index 000000000..ee8b6a27c --- /dev/null +++ b/res/layout/search_contact_cell.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/org/linphone/ChatActivity.java b/src/org/linphone/ChatActivity.java index a29b5ab14..a3114f654 100644 --- a/src/org/linphone/ChatActivity.java +++ b/src/org/linphone/ChatActivity.java @@ -28,32 +28,41 @@ import android.os.Bundle; public class ChatActivity extends Activity { private static final String CHAT_FRAGMENT = "chatFragment"; private ChatFragment chatFragment; + private StatusFragment status; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.chat_activity); - + Bundle extras = new Bundle(); - extras.putString("SipUri", getIntent().getExtras().getString("SipUri")); - extras.putString("DisplayName", getIntent().getExtras().getString("DisplayName")); - extras.putString("PictureUri", getIntent().getExtras().getString("PictureUri")); - extras.putString("ThumbnailUri", getIntent().getExtras().getString("ThumbnailUri")); - + if( getIntent().getExtras() != null) { + extras.putString("SipUri", getIntent().getExtras().getString("SipUri")); + extras.putString("DisplayName", getIntent().getExtras().getString("DisplayName")); + extras.putString("PictureUri", getIntent().getExtras().getString("PictureUri")); + extras.putString("ThumbnailUri", getIntent().getExtras().getString("ThumbnailUri")); + } + ChatFragment fragment = new ChatFragment(); fragment.setArguments(extras); getFragmentManager().beginTransaction().add(R.id.fragmentContainer, fragment, "ChatFragment").commit(); - + FragmentManager fm = getFragmentManager(); chatFragment = (ChatFragment) fm.findFragmentByTag(CHAT_FRAGMENT); - // If the Fragment is non-null, then it is currently being - // retained across a configuration change. + // If the Fragment is non-null, then it is currently being + // retained across a configuration change. if (chatFragment == null) { chatFragment = new ChatFragment(); chatFragment.setArguments(extras); fm.beginTransaction().add(R.id.fragmentContainer, chatFragment, CHAT_FRAGMENT).commit(); - } + } + } + + public void updateStatusFragment(StatusFragment fragment) { + status = fragment; + } + } diff --git a/src/org/linphone/ChatFragment.java b/src/org/linphone/ChatFragment.java index 75548f3ef..4cf39cdf9 100644 --- a/src/org/linphone/ChatFragment.java +++ b/src/org/linphone/ChatFragment.java @@ -25,7 +25,10 @@ import java.io.File; import android.app.Fragment; import android.graphics.Matrix; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.zip.Inflater; import org.linphone.compatibility.Compatibility; @@ -39,6 +42,8 @@ import org.linphone.core.LinphoneChatMessage.State; import org.linphone.core.LinphoneCoreException; import org.linphone.core.LinphoneCoreFactory; import org.linphone.core.LinphoneCoreListenerBase; +import org.linphone.core.LinphoneFriend; +import org.linphone.core.PresenceActivityType; import org.linphone.mediastream.Log; import org.linphone.ui.BubbleChat; @@ -73,13 +78,18 @@ import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import android.widget.ArrayAdapter; +import android.widget.AutoCompleteTextView; import android.widget.BaseAdapter; import android.widget.EditText; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RelativeLayout; +import android.widget.SectionIndexer; import android.widget.TextView; import android.widget.Toast; @@ -100,6 +110,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC private ImageView cancelUpload, edit, selectAll, deselectAll, startCall, delete, sendImage, sendMessage; private TextView contactName, remoteComposing; private ImageView back; + private AutoCompleteTextView searchContactField; private RelativeLayout uploadLayout, textLayout, topBar; private ListView messagesList; @@ -112,6 +123,7 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC private LinphoneCoreListenerBase mListener; private ByteArrayInputStream mUploadingImageStream; private LinphoneChatMessage currentMessageInFileTransferUploadState; + private boolean newChatConversation = false; public static boolean isInstanciated() { return instance != null; @@ -127,15 +139,21 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC // Retain the fragment across configuration changes setRetainInstance(true); - //Retrieve parameter from intent - sipUri = getArguments().getString("SipUri"); - displayName = getArguments().getString("DisplayName"); - pictureUri = getArguments().getString("PictureUri"); + if(getArguments() == null || getArguments().getString("SipUri") == null) { + newChatConversation = true; + } else { + //Retrieve parameter from intent + sipUri = getArguments().getString("SipUri"); + displayName = getArguments().getString("DisplayName"); + pictureUri = getArguments().getString("PictureUri"); + } //Initialize UI contactName = (TextView) view.findViewById(R.id.contact_name); //contactPicture = (ImageView) view.findViewById(R.id.contactPicture); messagesList = (ListView) view.findViewById(R.id.chatMessageList); + searchContactField = (AutoCompleteTextView) view.findViewById(R.id.searchContactField); + textLayout = (RelativeLayout) view.findViewById(R.id.messageLayout); progressBar = (ProgressBar) view.findViewById(R.id.progressbar); topBar = (RelativeLayout) view.findViewById(R.id.topBar); @@ -164,8 +182,20 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC delete = (ImageView) view.findViewById(R.id.delete); delete.setOnClickListener(this); - - displayChatHeader(displayName, pictureUri); + if (newChatConversation) { + messagesList.setVisibility(View.GONE); + searchContactField.setVisibility(View.VISIBLE); + searchContactField.setAdapter(new SearchContactsListAdapter(ContactsManager.getInstance().getAllContacts(), null, inflater)); + edit.setVisibility(View.INVISIBLE); + startCall.setVisibility(View.INVISIBLE); + } else { + displayChatHeader(displayName, pictureUri); + LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); + if (lc != null) { + chatRoom = lc.getOrCreateChatRoom(sipUri); + chatRoom.markAsRead(); + } + } //Manage multiline message = (EditText) view.findViewById(R.id.message); @@ -210,13 +240,6 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC } } }); - - LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); - if (lc != null) { - chatRoom = lc.getOrCreateChatRoom(sipUri); - //Only works if using liblinphone storage - chatRoom.markAsRead(); - } mListener = new LinphoneCoreListenerBase(){ @Override @@ -534,8 +557,11 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC String draft = getArguments().getString("messageDraft"); message.setText(draft); - remoteComposing.setVisibility(chatRoom.isRemoteComposing() ? View.VISIBLE : View.GONE); - dispayMessageList(); + + if(!newChatConversation) { + remoteComposing.setVisibility(chatRoom.isRemoteComposing() ? View.VISIBLE : View.GONE); + dispayMessageList(); + } super.onResume(); } @@ -585,20 +611,52 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); boolean isNetworkReachable = lc == null ? false : lc.isNetworkReachable(); - if (chatRoom != null && messageToSend != null && messageToSend.length() > 0 && isNetworkReachable) { - LinphoneChatMessage message = chatRoom.createLinphoneChatMessage(messageToSend); - chatRoom.sendChatMessage(message); + if(newChatConversation){ + String address = searchContactField.getText().toString(); + if(address != null && !address.equals("")) { + if (!LinphoneUtils.isSipAddress(address)) { + if (LinphoneManager.getLc().getDefaultProxyConfig() == null) { + Log.w("Error"); + } + address = address + "@" + LinphoneManager.getLc().getDefaultProxyConfig().getDomain(); + if (!LinphoneUtils.isStrictSipAddress(address)) { + address = "sip:" + address; + } + } - if (LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().onMessageSent(sipUri, messageToSend); + Log.w(address); + LinphoneAddress lAddress; + try { + lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(address); + } catch (LinphoneCoreException e) { + Log.e("Cannot display chat",e); + return; + } + + chatRoom = lc.getOrCreateChatRoom(lAddress.toString()); + + if (chatRoom != null && messageToSend != null && messageToSend.length() > 0 && isNetworkReachable) { + LinphoneChatMessage message = chatRoom.createLinphoneChatMessage(messageToSend); + chatRoom.sendChatMessage(message); + LinphoneActivity.instance().displayChat(lAddress.toString()); + } } + } else { - message.setListener(LinphoneManager.getInstance()); + if (chatRoom != null && messageToSend != null && messageToSend.length() > 0 && isNetworkReachable) { + LinphoneChatMessage message = chatRoom.createLinphoneChatMessage(messageToSend); + chatRoom.sendChatMessage(message); - invalidate(); - Log.i("Sent message current status: " + message.getStatus()); - } else if (!isNetworkReachable && LinphoneActivity.isInstanciated()) { - LinphoneActivity.instance().displayCustomToast(getString(R.string.error_network_unreachable), Toast.LENGTH_LONG); + if (LinphoneActivity.isInstanciated()) { + LinphoneActivity.instance().onMessageSent(sipUri, messageToSend); + } + + message.setListener(LinphoneManager.getInstance()); + invalidate(); + Log.i("Sent message current status: " + message.getStatus()); + } else if (!isNetworkReachable && LinphoneActivity.isInstanciated()) { + LinphoneActivity.instance().displayCustomToast(getString(R.string.error_network_unreachable), Toast.LENGTH_LONG); + } } } @@ -810,4 +868,111 @@ public class ChatFragment extends Fragment implements OnClickListener, LinphoneC public void onLinphoneChatMessageFileTransferProgressChanged(LinphoneChatMessage msg, LinphoneContent content, int offset, int total) { progressBar.setProgress(offset * 100 / total); } + + class SearchContactsListAdapter extends BaseAdapter implements Filterable { + private List contacts; + private Cursor cursor; + private LayoutInflater mInflater; + + SearchContactsListAdapter(List contactsList, Cursor c, LayoutInflater inflater) { + cursor = c; + mInflater = inflater; + contacts = new ArrayList(); + for(Contact con: ContactsManager.getInstance().getAllContacts()){ + for(String numberOrAddress : con.getNumbersOrAddresses()){ + contacts.add(new ContactAddress(con,numberOrAddress)); + } + } + } + + @Override + public Filter getFilter() { + return new Filter() { + @Override + protected void publishResults(CharSequence constraint, + FilterResults results) { + if (results.count > 0) { + notifyDataSetChanged(); + } else { + notifyDataSetInvalidated(); + } + } + + @Override + protected FilterResults performFiltering(CharSequence constraint) { + List result = new ArrayList(); + Log.w(constraint); + if(constraint != null) { + for (ContactAddress c : contacts) { + Log.w(c.mAddress); + Log.w(c.mContact.getName()); + if (c.mContact.getName().startsWith(constraint.toString()) || c.mAddress.startsWith(constraint.toString())) { + result.add(c); + } + } + } + FilterResults r = new FilterResults(); + r.values = result; + r.count = result.size(); + return r; + } + }; + } + + class ContactAddress { + public Contact mContact; + public String mAddress; + + ContactAddress(Contact contact, String address){ + mContact = contact; + mAddress = address; + } + } + + public int getCount() { + return contacts.size(); + } + + public Object getItem(int position) { + if (contacts == null || position >= contacts.size()) { + List contacts_list = new ArrayList(); + for(Contact c: ContactsManager.getInstance().getAllContacts()){ + for(String numberOrAddress : c.getNumbersOrAddresses()){ + contacts_list.add(new ContactAddress(c,numberOrAddress)); + } + } + return contacts_list; + } else { + return contacts.get(position); + } + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + View view = null; + ContactAddress contact = null; + do { + contact = (ContactAddress) getItem(position); + } while (contact == null); + + if (convertView != null) { + view = convertView; + } else { + view = mInflater.inflate(R.layout.search_contact_cell, parent, false); + } + + TextView name = (TextView) view.findViewById(R.id.Contact_name); + name.setText(contact.mContact.getName()); + + TextView address = (TextView) view.findViewById(R.id.contact_address); + address.setText(contact.mAddress); + + return view; + } + } + + } diff --git a/src/org/linphone/ChatListFragment.java b/src/org/linphone/ChatListFragment.java index 9e28c60d4..f995d7f25 100644 --- a/src/org/linphone/ChatListFragment.java +++ b/src/org/linphone/ChatListFragment.java @@ -234,6 +234,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte hideAndDisplayMessageIfNoChat(); } else if (id == R.id.new_discussion) { + LinphoneActivity.instance().displayChat(null); /*String sipUri = fastNewChat.getText().toString(); if (sipUri.equals("")) { LinphoneActivity.instance().displayContacts(true); @@ -247,7 +248,7 @@ public class ChatListFragment extends Fragment implements OnClickListener, OnIte if (!LinphoneUtils.isStrictSipAddress(sipUri)) { sipUri = "sip:" + sipUri; } - LinphoneActivity.instance().displayChat(sipUri); + }*/ } }