diff --git a/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java b/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java index 8a2bfe3f0..4b3399f66 100644 --- a/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java +++ b/app/src/main/java/org/linphone/chat/ChatRoomCreationFragment.java @@ -27,6 +27,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; +import android.widget.CompoundButton; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.LinearLayout; @@ -52,6 +53,7 @@ import org.linphone.core.Address; import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.Core; +import org.linphone.core.FriendCapability; import org.linphone.core.ProxyConfig; import org.linphone.fragments.FragmentsAvailable; import org.linphone.mediastream.Log; @@ -134,7 +136,11 @@ public class ChatRoomCreationFragment extends Fragment mSearchAdapter = new SearchContactsAdapter( - null, mContactsFetchInProgress, this, !mCreateGroupChatRoom); + null, + mContactsFetchInProgress, + this, + !mCreateGroupChatRoom, + mChatRoomEncrypted); mSearchField = view.findViewById(R.id.searchField); mSearchField.setOnQueryTextListener( @@ -155,24 +161,32 @@ public class ChatRoomCreationFragment extends Fragment mAllContactsToggle = view.findViewById(R.id.layout_all_contacts); mSecurityToggle = view.findViewById(R.id.security_toogle); + mSecurityToggle.setOnCheckedChangeListener( + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + setSecurityEnabled(isChecked); + } + }); mSecurityToggleOn = view.findViewById(R.id.security_toogle_on); mSecurityToggleOff = view.findViewById(R.id.security_toogle_off); mSecurityToggleOn.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { - mSecurityToggle.setChecked(true); + setSecurityEnabled(true); } }); mSecurityToggleOff.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { - mSecurityToggle.setChecked(false); + setSecurityEnabled(false); } }); mSecurityToggle.setChecked(mChatRoomEncrypted); + mSearchAdapter.setSecurityEnabled(mChatRoomEncrypted); ProxyConfig lpc = LinphoneManager.getLc().getDefaultProxyConfig(); if ((mChatRoomSubject != null && mChatRoomAddress != null) || (lpc == null || lpc.getConferenceFactoryUri() == null)) { @@ -236,7 +250,7 @@ public class ChatRoomCreationFragment extends Fragment mWaitLayout.setVisibility(View.GONE); LinphoneActivity.instance().displayChatRoomError(); Log.e( - "Group chat room for address " + "[Chat Room Creation] Group chat room for address " + cr.getPeerAddress() + " has failed !"); } @@ -286,6 +300,30 @@ public class ChatRoomCreationFragment extends Fragment super.onPause(); } + private void setSecurityEnabled(boolean enabled) { + mChatRoomEncrypted = enabled; + mSecurityToggle.setChecked(mChatRoomEncrypted); + mSearchAdapter.setSecurityEnabled(mChatRoomEncrypted); + + if (enabled) { + // Remove all contacts added before LIME switch was set + // and that can stay because they don't have the capability + for (ContactAddress ca : mContactsSelected) { + mContactsSelectedLayout.removeAllViews(); + if (ca.isSelect() && !ca.hasCapability(FriendCapability.LimeX3Dh)) { + mContactsSelected.remove(getIndexOfCa(ca, mContactsSelected)); + } + for (ContactAddress contactAddress : mContactsSelected) { + if (contactAddress.getView() != null) { + mContactsSelectedLayout.addView(contactAddress.getView()); + } + } + mSearchAdapter.setContactsSelectedList(mContactsSelected); + mContactsSelectedLayout.invalidate(); + } + } + } + private void displayChatCreation() { mNextButton.setVisibility(View.VISIBLE); mNextButton.setEnabled(mContactsSelected.size() > 0); @@ -507,6 +545,21 @@ public class ChatRoomCreationFragment extends Fragment Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); ProxyConfig lpc = lc.getDefaultProxyConfig(); boolean createEncryptedChatRoom = mSecurityToggle.isChecked(); + + if (createEncryptedChatRoom && !ca.hasCapability(FriendCapability.LimeX3Dh)) { + Log.w( + "[Chat Room Creation] Contact " + + ca.getContact() + + " doesn't have LIME X3DH capability !"); + return; + } else if (mCreateGroupChatRoom && !ca.hasCapability(FriendCapability.GroupChat)) { + Log.w( + "[Chat Room Creation] Contact " + + ca.getContact() + + " doesn't have group chat capability !"); + return; + } + if (lpc == null || lpc.getConferenceFactoryUri() == null || !mCreateGroupChatRoom) { if (createEncryptedChatRoom && lpc != null && lpc.getConferenceFactoryUri() != null) { mChatRoom = diff --git a/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java b/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java index 0ee390b8f..78eaa2564 100644 --- a/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java +++ b/app/src/main/java/org/linphone/contacts/AsyncContactsLoader.java @@ -245,6 +245,8 @@ class AsyncContactsLoader extends AsyncTask mContacts, mSipContacts; + private List mContacts, mSipContacts, mGroupChatContacts, mLimeX3dhContacts; private ArrayList mContactsUpdatedListeners; private MagicSearch mMagicSearch; private final Bitmap mDefaultAvatar; @@ -80,6 +81,9 @@ public class ContactsManager extends ContentObserver implements FriendListListen mContactsUpdatedListeners = new ArrayList<>(); mContacts = new ArrayList<>(); mSipContacts = new ArrayList<>(); + mGroupChatContacts = new ArrayList<>(); + mLimeX3dhContacts = new ArrayList<>(); + if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() != null) { mMagicSearch = LinphoneManager.getLcIfManagerNotDestroyedOrNull().createMagicSearch(); } @@ -127,6 +131,22 @@ public class ContactsManager extends ContentObserver implements FriendListListen mSipContacts = c; } + public synchronized List getGroupChatContacts() { + return mGroupChatContacts; + } + + synchronized void clearGroupChatContacts() { + mGroupChatContacts.clear(); + } + + public synchronized List getLimeX3dhContacts() { + return mLimeX3dhContacts; + } + + synchronized void clearLimeX3dhContacts() { + mLimeX3dhContacts.clear(); + } + public void destroy() { Core lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull(); if (lc != null) { @@ -379,10 +399,27 @@ public class ContactsManager extends ContentObserver implements FriendListListen private synchronized boolean refreshSipContact(Friend lf) { LinphoneContact contact = (LinphoneContact) lf.getUserData(); - if (contact != null && !mSipContacts.contains(contact)) { - mSipContacts.add(contact); - Collections.sort(mSipContacts); - return true; + if (contact != null) { + if (lf.hasCapability(FriendCapability.GroupChat) + && !mGroupChatContacts.contains(contact)) { + mGroupChatContacts.add(contact); + Collections.sort(mGroupChatContacts); + Log.i("[Contacts Manager] Contact " + contact + " has group chat capability"); + + // Contact may only have LimeX3DH capability if it already has GroupChat capability + if (lf.hasCapability(FriendCapability.LimeX3Dh) + && !mLimeX3dhContacts.contains(contact)) { + mLimeX3dhContacts.add(contact); + Collections.sort(mLimeX3dhContacts); + Log.i("[Contacts Manager] Contact " + contact + " has lime x3dh capability"); + } + } + + if (!mSipContacts.contains(contact)) { + mSipContacts.add(contact); + Collections.sort(mSipContacts); + return true; + } } return false; } diff --git a/app/src/main/java/org/linphone/contacts/LinphoneContact.java b/app/src/main/java/org/linphone/contacts/LinphoneContact.java index 882422bee..5ba4ea2a0 100644 --- a/app/src/main/java/org/linphone/contacts/LinphoneContact.java +++ b/app/src/main/java/org/linphone/contacts/LinphoneContact.java @@ -28,6 +28,7 @@ import org.linphone.LinphoneManager; import org.linphone.core.Address; import org.linphone.core.Core; import org.linphone.core.Friend; +import org.linphone.core.FriendCapability; import org.linphone.core.FriendList; import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceModel; @@ -487,4 +488,10 @@ public class LinphoneContact extends AndroidContact deleteFriend(); } } + + public boolean hasFriendCapability(FriendCapability capability) { + if (!isFriend()) return false; + + return getFriend().hasCapability(capability); + } } diff --git a/app/src/main/java/org/linphone/contacts/SearchContactViewHolder.java b/app/src/main/java/org/linphone/contacts/SearchContactViewHolder.java index 9ba6a1176..ded7067a3 100644 --- a/app/src/main/java/org/linphone/contacts/SearchContactViewHolder.java +++ b/app/src/main/java/org/linphone/contacts/SearchContactViewHolder.java @@ -33,16 +33,20 @@ public class SearchContactViewHolder extends RecyclerView.ViewHolder public final ImageView linphoneContact; public final ImageView isSelect; public final RelativeLayout avatarLayout; + public final View disabled; private final ClickListener mListener; public SearchContactViewHolder(View view, ClickListener listener) { super(view); + name = view.findViewById(R.id.contact_name); address = view.findViewById(R.id.contact_address); linphoneContact = view.findViewById(R.id.contact_linphone); isSelect = view.findViewById(R.id.contact_is_select); avatarLayout = view.findViewById(R.id.avatar_layout); + disabled = view.findViewById(R.id.disabled); + mListener = listener; view.setOnClickListener(this); } diff --git a/app/src/main/java/org/linphone/contacts/SearchContactsAdapter.java b/app/src/main/java/org/linphone/contacts/SearchContactsAdapter.java index 91083450a..a7fc6512d 100644 --- a/app/src/main/java/org/linphone/contacts/SearchContactsAdapter.java +++ b/app/src/main/java/org/linphone/contacts/SearchContactsAdapter.java @@ -32,6 +32,7 @@ import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.core.Address; import org.linphone.core.Factory; +import org.linphone.core.FriendCapability; import org.linphone.core.PresenceBasicStatus; import org.linphone.core.PresenceModel; import org.linphone.core.ProxyConfig; @@ -47,20 +48,23 @@ public class SearchContactsAdapter extends RecyclerView.Adapter contactsList, ProgressBar pB, SearchContactViewHolder.ClickListener clickListener, - boolean hideSelectionMark) { - mHideSelectionMark = hideSelectionMark; + boolean hideSelectionMark, + boolean isSecurityEnabled) { + mIsOnlyOnePersonSelection = hideSelectionMark; mListener = clickListener; mProgressBar = pB; setContactsSelectedList(null); setContactsList(contactsList); mPreviousSearch = null; + mSecurityEnabled = isSecurityEnabled; } public List getContacts() { @@ -71,6 +75,11 @@ public class SearchContactsAdapter extends RecyclerView.Adapter - + android:layout_height="60dp"> - - - - - - + android:orientation="vertical" + android:padding="5dp"> - + + + + + + + android:layout_alignParentTop="true" + android:layout_alignParentBottom="true" + android:layout_marginLeft="5dp" + android:layout_marginRight="70dp" + android:layout_toRightOf="@id/avatar" + android:background="@drawable/list_selector" + android:gravity="center_vertical" + android:orientation="vertical"> - + - + - + + + + + + + + android:paddingRight="20dp" + android:src="@drawable/check_selected" + android:visibility="invisible" /> - - - + + diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index 48213a8e3..2530e3a79 100644 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -23,4 +23,5 @@ #00000000 @color/colorA + #99ffffff