/*
* 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();
}
}
}