/* * Copyright (c) 2010-2019 Belledonne Communications SARL. * * This file is part of linphone-android * (see https://www.linphone.org). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.linphone.chat; import static android.content.Context.INPUT_METHOD_SERVICE; import android.app.Dialog; import android.app.Fragment; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import java.util.ArrayList; import org.linphone.LinphoneManager; import org.linphone.R; import org.linphone.call.views.LinphoneLinearLayoutManager; import org.linphone.contacts.ContactAddress; import org.linphone.contacts.ContactsManager; import org.linphone.contacts.LinphoneContact; import org.linphone.core.Address; import org.linphone.core.ChatRoom; import org.linphone.core.ChatRoomCapabilities; import org.linphone.core.ChatRoomListenerStub; import org.linphone.core.ChatRoomParams; import org.linphone.core.Core; import org.linphone.core.EventLog; import org.linphone.core.Factory; import org.linphone.core.Participant; import org.linphone.core.tools.Log; import org.linphone.utils.LinphoneUtils; public class GroupInfoFragment extends Fragment { private ImageView mConfirmButton; private ImageView mAddParticipantsButton; private Address mGroupChatRoomAddress; private EditText mSubjectField; private RecyclerView mParticipantsList; private RelativeLayout mWaitLayout; private GroupInfoAdapter mAdapter; private boolean mIsAlreadyCreatedGroup; private boolean mIsEditionEnabled; private ArrayList mParticipants; private String mSubject; private ChatRoom mChatRoom, mTempChatRoom; private Dialog mAdminStateChangedDialog; private ChatRoomListenerStub mChatRoomCreationListener; private boolean mIsEncryptionEnabled; private ChatRoomListenerStub mListener; @Override public View onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.chat_infos, container, false); if (getArguments() == null || getArguments().isEmpty()) { return null; } mParticipants = (ArrayList) getArguments().getSerializable("Participants"); mGroupChatRoomAddress = null; mChatRoom = null; String address = getArguments().getString("RemoteSipUri"); if (address != null && address.length() > 0) { mGroupChatRoomAddress = Factory.instance().createAddress(address); } mIsAlreadyCreatedGroup = mGroupChatRoomAddress != null; if (mIsAlreadyCreatedGroup) { mChatRoom = LinphoneManager.getCore().getChatRoom(mGroupChatRoomAddress); } if (mChatRoom == null) { mIsAlreadyCreatedGroup = false; mIsEditionEnabled = true; mSubject = getArguments().getString("Subject", ""); mIsEncryptionEnabled = getArguments().getBoolean("Encrypted", false); } else { mIsEditionEnabled = mChatRoom.getMe() != null && mChatRoom.getMe().isAdmin() && !mChatRoom.hasBeenLeft(); mSubject = mChatRoom.getSubject(); mIsEncryptionEnabled = mChatRoom.hasCapability(ChatRoomCapabilities.Encrypted.toInt()); } mParticipantsList = view.findViewById(R.id.chat_room_participants); mAdapter = new GroupInfoAdapter(mParticipants, !mIsEditionEnabled, !mIsAlreadyCreatedGroup); mAdapter.setOnDeleteClickListener( new View.OnClickListener() { @Override public void onClick(View view) { ContactAddress ca = (ContactAddress) view.getTag(); mParticipants.remove(ca); mAdapter.updateDataSet(mParticipants); mParticipantsList.setAdapter(mAdapter); mConfirmButton.setEnabled( mSubjectField.getText().length() > 0 && mParticipants.size() > 0); } }); mParticipantsList.setAdapter(mAdapter); mAdapter.setChatRoom(mChatRoom); LinearLayoutManager layoutManager = new LinphoneLinearLayoutManager(getActivity()); mParticipantsList.setLayoutManager(layoutManager); // Divider between items DividerItemDecoration dividerItemDecoration = new DividerItemDecoration( mParticipantsList.getContext(), layoutManager.getOrientation()); dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.divider)); mParticipantsList.addItemDecoration(dividerItemDecoration); ImageView backButton = view.findViewById(R.id.back); backButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (mIsAlreadyCreatedGroup) { ((ChatActivity) getActivity()).goBack(); } else { goBackToChatCreationFragment(); } } }); mConfirmButton = view.findViewById(R.id.confirm); mConfirmButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { applyChanges(); } }); mConfirmButton.setEnabled(!mSubject.isEmpty() && mParticipants.size() > 0); LinearLayout leaveGroupButton = view.findViewById(R.id.leaveGroupLayout); leaveGroupButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { showLeaveGroupDialog(); } }); leaveGroupButton.setVisibility( mIsAlreadyCreatedGroup && mChatRoom.hasBeenLeft() ? View.GONE : mIsAlreadyCreatedGroup ? View.VISIBLE : View.GONE); RelativeLayout addParticipantsLayout = view.findViewById(R.id.addParticipantsLayout); addParticipantsLayout.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (mIsEditionEnabled && mIsAlreadyCreatedGroup) { goBackToChatCreationFragment(); } } }); mAddParticipantsButton = view.findViewById(R.id.addParticipants); mAddParticipantsButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (mIsEditionEnabled && mIsAlreadyCreatedGroup) { goBackToChatCreationFragment(); } } }); mAddParticipantsButton.setVisibility(mIsAlreadyCreatedGroup ? View.VISIBLE : View.GONE); mSubjectField = view.findViewById(R.id.subjectField); mSubjectField.addTextChangedListener( new TextWatcher() { @Override public void beforeTextChanged( CharSequence charSequence, int i, int i1, int i2) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void afterTextChanged(Editable editable) { mConfirmButton.setEnabled( mSubjectField.getText().length() > 0 && mParticipants.size() > 0); } }); mSubjectField.setText(mSubject); mChatRoomCreationListener = new ChatRoomListenerStub() { @Override public void onStateChanged(ChatRoom cr, ChatRoom.State newState) { if (newState == ChatRoom.State.Created) { mWaitLayout.setVisibility(View.GONE); // Pop the back stack twice so we don't have in stack Creation -> Group // Behind the chat room, so a back press will take us back to the rooms getFragmentManager().popBackStack(); getFragmentManager().popBackStack(); ((ChatActivity) getActivity()) .showChatRoom(cr.getLocalAddress(), cr.getPeerAddress()); } else if (newState == ChatRoom.State.CreationFailed) { mWaitLayout.setVisibility(View.GONE); ((ChatActivity) getActivity()).displayChatRoomError(); Log.e( "[Group Info] Group chat room for address " + cr.getPeerAddress() + " has failed !"); } } }; if (!mIsEditionEnabled) { mSubjectField.setEnabled(false); mConfirmButton.setVisibility(View.INVISIBLE); mAddParticipantsButton.setVisibility(View.GONE); } mWaitLayout = view.findViewById(R.id.waitScreen); mWaitLayout.setVisibility(View.GONE); mListener = new ChatRoomListenerStub() { @Override public void onParticipantAdminStatusChanged(ChatRoom cr, EventLog event_log) { if (mChatRoom.getMe().isAdmin() != mIsEditionEnabled) { // Either we weren't admin and we are now or the other way around mIsEditionEnabled = mChatRoom.getMe().isAdmin(); displayMeAdminStatusUpdated(); refreshAdminRights(); } refreshParticipantsList(); } @Override public void onSubjectChanged(ChatRoom cr, EventLog event_log) { mSubjectField.setText(event_log.getSubject()); } @Override public void onParticipantAdded(ChatRoom cr, EventLog eventLog) { refreshParticipantsList(); } @Override public void onParticipantRemoved(ChatRoom cr, EventLog eventLog) { refreshParticipantsList(); } }; if (mChatRoom != null) { mChatRoom.addListener(mListener); } return view; } @Override public void onResume() { super.onResume(); InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE); if (getActivity().getCurrentFocus() != null) { inputMethodManager.hideSoftInputFromWindow( getActivity().getCurrentFocus().getWindowToken(), 0); } } @Override public void onPause() { if (mTempChatRoom != null) { mTempChatRoom.removeListener(mChatRoomCreationListener); } super.onPause(); } @Override public void onDestroy() { if (mChatRoom != null) { mChatRoom.removeListener(mListener); } super.onDestroy(); } private void goBackToChatCreationFragment() { ((ChatActivity) getActivity()) .showChatRoomCreation( mGroupChatRoomAddress, mParticipants, mSubject, mIsEncryptionEnabled, true, !mIsAlreadyCreatedGroup); } private void refreshParticipantsList() { if (mChatRoom == null) return; mParticipants = new ArrayList<>(); for (Participant p : mChatRoom.getParticipants()) { Address a = p.getAddress(); LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(a); if (c == null) { c = new LinphoneContact(); String displayName = LinphoneUtils.getAddressDisplayName(a); c.setFullName(displayName); } ContactAddress ca = new ContactAddress(c, a.asString(), "", p.isAdmin()); mParticipants.add(ca); } mAdapter.updateDataSet(mParticipants); mAdapter.setChatRoom(mChatRoom); } private void refreshAdminRights() { mAdapter.setAdminFeaturesVisible(mIsEditionEnabled); mAdapter.setChatRoom(mChatRoom); mSubjectField.setEnabled(mIsEditionEnabled); mConfirmButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.INVISIBLE); mAddParticipantsButton.setVisibility(mIsEditionEnabled ? View.VISIBLE : View.GONE); } private void displayMeAdminStatusUpdated() { if (mAdminStateChangedDialog != null) mAdminStateChangedDialog.dismiss(); mAdminStateChangedDialog = ((ChatActivity) getActivity()) .displayDialog( getString( mIsEditionEnabled ? R.string.chat_room_you_are_now_admin : R.string.chat_room_you_are_no_longer_admin)); Button cancel = mAdminStateChangedDialog.findViewById(R.id.dialog_cancel_button); mAdminStateChangedDialog.findViewById(R.id.dialog_delete_button).setVisibility(View.GONE); cancel.setText(getString(R.string.ok)); cancel.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { mAdminStateChangedDialog.dismiss(); } }); mAdminStateChangedDialog.show(); } private void showLeaveGroupDialog() { final Dialog dialog = ((ChatActivity) getActivity()) .displayDialog(getString(R.string.chat_room_leave_dialog)); Button delete = dialog.findViewById(R.id.dialog_delete_button); delete.setText(getString(R.string.chat_room_leave_button)); Button cancel = dialog.findViewById(R.id.dialog_cancel_button); delete.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { if (mChatRoom != null) { mChatRoom.leave(); ((ChatActivity) getActivity()) .showChatRoom( mChatRoom.getLocalAddress(), mChatRoom.getPeerAddress()); } else { Log.e( "[Group Info] Can't leave, chatRoom for address " + mGroupChatRoomAddress.asString() + " is null..."); } dialog.dismiss(); } }); cancel.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View view) { dialog.dismiss(); } }); dialog.show(); } private void applyChanges() { if (!mIsAlreadyCreatedGroup) { mWaitLayout.setVisibility(View.VISIBLE); Core core = LinphoneManager.getCore(); int i = 0; Address[] participants = new Address[mParticipants.size()]; for (ContactAddress ca : mParticipants) { participants[i] = ca.getAddress(); i++; } ChatRoomParams params = core.createDefaultChatRoomParams(); params.enableEncryption(mIsEncryptionEnabled); params.enableGroup(true); mTempChatRoom = core.createChatRoom(params, mSubjectField.getText().toString(), participants); if (mTempChatRoom != null) { mTempChatRoom.addListener(mChatRoomCreationListener); } else { Log.w("[Group Info] createChatRoom returned null..."); mWaitLayout.setVisibility(View.GONE); } } else { // Subject String newSubject = mSubjectField.getText().toString(); if (!newSubject.equals(mSubject)) { mChatRoom.setSubject(newSubject); } // Participants removed ArrayList toRemove = new ArrayList<>(); for (Participant p : mChatRoom.getParticipants()) { boolean found = false; for (ContactAddress c : mParticipants) { if (c.getAddress().weakEqual(p.getAddress())) { found = true; break; } } if (!found) { toRemove.add(p); } } Participant[] participantsToRemove = new Participant[toRemove.size()]; toRemove.toArray(participantsToRemove); mChatRoom.removeParticipants(participantsToRemove); // Participants added ArrayList
toAdd = new ArrayList<>(); for (ContactAddress c : mParticipants) { boolean found = false; for (Participant p : mChatRoom.getParticipants()) { if (p.getAddress().weakEqual(c.getAddress())) { // Admin rights if (c.isAdmin() != p.isAdmin()) { mChatRoom.setParticipantAdminStatus(p, c.isAdmin()); } found = true; break; } } if (!found) { Address addr = c.getAddress(); if (addr != null) { toAdd.add(addr); } else { // TODO error } } } Address[] participantsToAdd = new Address[toAdd.size()]; toAdd.toArray(participantsToAdd); if (!mChatRoom.addParticipants(participantsToAdd)) { // TODO error } // Pop back stack to go back to the Messages fragment getFragmentManager().popBackStack(); } } }