blob: d25c9485fd568b336312accf377045a43aa33716 [file] [log] [blame]
Loïc Siret0202fbf2017-09-28 16:34:28 -04001/*
Adrien Béraude552f692020-11-03 14:30:52 -05002 * Copyright (C) 2004-2020 Savoir-faire Linux Inc.
Loïc Siret0202fbf2017-09-28 16:34:28 -04003 *
Adrien Béraud64538722018-03-15 17:34:00 -04004 * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
5 *
Loïc Siret0202fbf2017-09-28 16:34:28 -04006 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
Aline Bonnet9c6defe2016-12-21 13:21:02 -050020package cx.ring.fragments;
21
Pierre Duchemin4af6b392018-02-02 11:23:56 -050022import android.Manifest;
Adrien Béraud5477ce82020-02-24 11:13:54 -050023import android.animation.LayoutTransition;
Adrien Béraud772e2162019-02-12 16:00:21 -050024import android.animation.ValueAnimator;
Adrien Béraud5477ce82020-02-24 11:13:54 -050025import android.annotation.SuppressLint;
Adrien Béraud21a3ea22020-04-01 16:06:09 -040026import android.app.Activity;
Rayan Osseirane4450272019-06-03 14:17:19 -040027import android.content.ActivityNotFoundException;
Adrien Béraudae45ffa2018-07-06 16:21:29 -040028import android.content.ClipData;
Adrien Béraud5477ce82020-02-24 11:13:54 -050029import android.content.ComponentName;
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -040030import android.content.Context;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050031import android.content.Intent;
Adrien Béraud5477ce82020-02-24 11:13:54 -050032import android.content.ServiceConnection;
Adrien Béraud3a875a02018-07-18 17:54:17 -040033import android.content.SharedPreferences;
Adrien Béraud4f542f92019-01-03 12:17:53 -050034import android.content.pm.PackageManager;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050035import android.graphics.Typeface;
Adrien Béraud5477ce82020-02-24 11:13:54 -050036import android.content.res.Resources;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050037import android.os.Bundle;
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -040038import android.os.Environment;
Adrien Béraud5477ce82020-02-24 11:13:54 -050039import android.os.IBinder;
Adrien Béraud64538722018-03-15 17:34:00 -040040import android.provider.MediaStore;
Adrien Béraud3a875a02018-07-18 17:54:17 -040041import android.text.Editable;
Adrien Béraud58bd92b2018-08-23 10:54:25 -040042import android.text.TextUtils;
Adrien Béraud3a875a02018-07-18 17:54:17 -040043import android.text.TextWatcher;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050044import android.util.Log;
Adrien Béraudb28c4912018-12-02 22:58:52 -050045import android.view.LayoutInflater;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050046import android.view.Menu;
47import android.view.MenuInflater;
48import android.view.MenuItem;
49import android.view.View;
50import android.view.ViewGroup;
Amirhossein7bb77aa2020-12-18 16:30:44 -050051import android.view.WindowManager;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050052import android.view.inputmethod.EditorInfo;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050053import android.widget.ImageView;
54import android.widget.RelativeLayout;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050055import android.widget.Spinner;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050056import android.widget.TextView;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050057import android.widget.Toast;
58
Rayan Osseirane4450272019-06-03 14:17:19 -040059import com.google.android.material.snackbar.Snackbar;
60
amine younes7c56f312019-06-10 11:34:25 -040061import androidx.annotation.NonNull;
62import androidx.annotation.Nullable;
63import androidx.appcompat.app.ActionBar;
64import androidx.appcompat.app.AppCompatActivity;
Adrien Béraud898c2bf2019-09-26 14:49:33 -040065import androidx.appcompat.view.menu.MenuBuilder;
66import androidx.appcompat.view.menu.MenuPopupHelper;
67import androidx.appcompat.widget.PopupMenu;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050068import androidx.appcompat.widget.Toolbar;
Adrien Béraud91f88742019-09-09 00:46:46 -040069import androidx.core.view.ViewCompat;
Adrien Béraud5477ce82020-02-24 11:13:54 -050070import androidx.fragment.app.Fragment;
71import androidx.fragment.app.FragmentManager;
amine younes7c56f312019-06-10 11:34:25 -040072import androidx.recyclerview.widget.DefaultItemAnimator;
73
Pierre Duchemine0c3a492018-02-01 16:22:45 -050074import java.io.File;
75import java.io.IOException;
Andreas Traczykcee415a2019-12-03 15:45:04 -050076import java.util.HashMap;
Adrien Béraudace37a22018-06-22 14:58:36 -040077import java.util.List;
Andreas Traczykcee415a2019-12-03 15:45:04 -050078import java.util.Map;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050079
Adrien Béraud5b47cb52018-07-06 16:24:14 -040080import cx.ring.BuildConfig;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050081import cx.ring.R;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050082import cx.ring.adapters.ConversationAdapter;
83import cx.ring.adapters.NumberAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040084import cx.ring.application.JamiApplication;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050085import cx.ring.client.CallActivity;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -050086import cx.ring.client.ContactDetailsActivity;
Aline Bonnet830c4c62016-12-27 14:02:02 -050087import cx.ring.client.ConversationActivity;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050088import cx.ring.client.HomeActivity;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040089import cx.ring.contacts.AvatarFactory;
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -040090import cx.ring.conversation.ConversationPresenter;
91import cx.ring.conversation.ConversationView;
Adrien Béraudb28c4912018-12-02 22:58:52 -050092import cx.ring.databinding.FragConversationBinding;
Adrien Béraud171ba362018-12-14 21:35:40 -050093import cx.ring.interfaces.Colorable;
Adrien Béraudfd458ea2020-02-28 13:40:18 -050094import cx.ring.model.Account;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050095import cx.ring.model.CallContact;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050096import cx.ring.model.Conversation;
Rayan Osseiran6f415662019-10-25 14:23:25 -040097import cx.ring.model.Interaction;
Adrien Béraud21533292018-03-22 14:11:35 -040098import cx.ring.model.DataTransfer;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050099import cx.ring.model.Phone;
Adrien Bérauda0226ff2019-11-21 15:24:42 -0500100import cx.ring.model.Error;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500101import cx.ring.model.Uri;
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500102import cx.ring.mvp.BaseSupportFragment;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500103import cx.ring.services.LocationSharingService;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400104import cx.ring.services.NotificationService;
Amirhossein68916382020-07-19 11:23:59 -0400105import cx.ring.services.NotificationServiceImpl;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500106import cx.ring.utils.ActionHelper;
Adrien Béraud64538722018-03-15 17:34:00 -0400107import cx.ring.utils.AndroidFileUtils;
Adrien Béraud64538722018-03-15 17:34:00 -0400108import cx.ring.utils.ContentUriHandler;
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500109import cx.ring.utils.DeviceUtils;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500110import cx.ring.utils.ConversationPath;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500111import cx.ring.utils.MediaButtonsHelper;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500112import cx.ring.views.AvatarDrawable;
Adrien Béraud44939482019-02-13 21:42:08 -0500113import io.reactivex.Completable;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400114import io.reactivex.Single;
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400115import io.reactivex.android.schedulers.AndroidSchedulers;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500116import io.reactivex.disposables.CompositeDisposable;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500117
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500118import static android.app.Activity.RESULT_OK;
119
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500120public class ConversationFragment extends BaseSupportFragment<ConversationPresenter> implements
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500121 MediaButtonsHelper.MediaButtonsHelperCallback,
Rayan Osseirane634a562019-05-29 13:44:55 -0400122 ConversationView, SharedPreferences.OnSharedPreferenceChangeListener {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500123 private static final String TAG = ConversationFragment.class.getSimpleName();
Adrien Béraud64538722018-03-15 17:34:00 -0400124
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400125 public static final int REQ_ADD_CONTACT = 42;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400126
Adrien Béraud6ac63632018-12-09 00:11:21 -0500127 public static final String KEY_CONTACT_RING_ID = BuildConfig.APPLICATION_ID + ".CONTACT_RING_ID";
128 public static final String KEY_ACCOUNT_ID = BuildConfig.APPLICATION_ID + ".ACCOUNT_ID";
Adrien Béraud3a875a02018-07-18 17:54:17 -0400129 public static final String KEY_PREFERENCE_PENDING_MESSAGE = "pendingMessage";
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500130 public static final String KEY_PREFERENCE_CONVERSATION_COLOR = "color";
Adrien Béraud5477ce82020-02-24 11:13:54 -0500131 public static final String EXTRA_SHOW_MAP = "showMap";
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500132
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500133 private static final int REQUEST_CODE_FILE_PICKER = 1000;
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500134 private static final int REQUEST_PERMISSION_CAMERA = 1001;
Adrien Béraud64538722018-03-15 17:34:00 -0400135 private static final int REQUEST_CODE_TAKE_PICTURE = 1002;
amine younes7c56f312019-06-10 11:34:25 -0400136 private static final int REQUEST_CODE_SAVE_FILE = 1003;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400137 private static final int REQUEST_CODE_CAPTURE_AUDIO = 1004;
138 private static final int REQUEST_CODE_CAPTURE_VIDEO = 1005;
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500139
Adrien Béraud5477ce82020-02-24 11:13:54 -0500140 private ServiceConnection locationServiceConnection = null;
141
Adrien Béraudb28c4912018-12-02 22:58:52 -0500142 private FragConversationBinding binding;
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400143 private MenuItem mAudioCallBtn = null;
144 private MenuItem mVideoCallBtn = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500145
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400146 private View currentBottomView = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500147 private ConversationAdapter mAdapter = null;
Adrien Béraud772e2162019-02-12 16:00:21 -0500148 private int marginPx;
Adrien Béraud91f88742019-09-09 00:46:46 -0400149 private int marginPxTotal;
Adrien Béraud772e2162019-02-12 16:00:21 -0500150 private final ValueAnimator animation = new ValueAnimator();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500151
Adrien Béraud3a875a02018-07-18 17:54:17 -0400152 private SharedPreferences mPreferences;
153
Adrien Béraud64538722018-03-15 17:34:00 -0400154 private File mCurrentPhoto = null;
amine younes7c56f312019-06-10 11:34:25 -0400155 private String mCurrentFileAbsolutePath = null;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500156 private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
Adrien Béraud742d3202019-11-15 14:28:59 -0500157 private int mSelectedPosition;
Adrien Béraud64538722018-03-15 17:34:00 -0400158
Amirhossein68916382020-07-19 11:23:59 -0400159 private boolean mIsBubble;
160
Andreas Traczykcee415a2019-12-03 15:45:04 -0500161 private AvatarDrawable mConversationAvatar;
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400162 private final Map<String, AvatarDrawable> mParticipantAvatars = new HashMap<>();
163 private final Map<String, AvatarDrawable> mSmallParticipantAvatars = new HashMap<>();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500164 private int mapWidth, mapHeight;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500165
166 public AvatarDrawable getConversationAvatar(String uri) {
167 return mParticipantAvatars.get(uri);
168 }
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400169 public AvatarDrawable getSmallConversationAvatar(String uri) {
170 synchronized (mSmallParticipantAvatars) {
171 return mSmallParticipantAvatars.get(uri);
172 }
173 }
Andreas Traczykcee415a2019-12-03 15:45:04 -0500174
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500175 private static int getIndex(Spinner spinner, Uri myString) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500176 for (int i = 0, n = spinner.getCount(); i < n; i++)
177 if (((Phone) spinner.getItemAtPosition(i)).getNumber().equals(myString)) {
178 return i;
179 }
180 return 0;
181 }
182
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400183 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400184 public void refreshView(final List<Interaction> conversation) {
Adrien Béraud20d42212018-03-02 14:40:38 -0500185 if (conversation == null) {
186 return;
187 }
Adrien Béraudb28c4912018-12-02 22:58:52 -0500188 if (binding != null)
189 binding.pbLoading.setVisibility(View.GONE);
Adrien Béraudace37a22018-06-22 14:58:36 -0400190 if (mAdapter != null) {
191 mAdapter.updateDataset(conversation);
192 }
Rayan Osseiran6f415662019-10-25 14:23:25 -0400193 requireActivity().invalidateOptionsMenu();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500194 }
195
Aline Bonnete8e87f62016-12-26 10:54:37 -0500196 @Override
Adrien Béraud64538722018-03-15 17:34:00 -0400197 public void scrollToEnd() {
Adrien Béraudace37a22018-06-22 14:58:36 -0400198 if (mAdapter.getItemCount() > 0) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500199 binding.histList.scrollToPosition(mAdapter.getItemCount() - 1);
Adrien Béraudace37a22018-06-22 14:58:36 -0400200 }
Adrien Béraud64538722018-03-15 17:34:00 -0400201 }
202
Adrien Béraud91f88742019-09-09 00:46:46 -0400203 private static void setBottomPadding(@NonNull View view, int padding) {
204 view.setPadding(
205 view.getPaddingLeft(),
206 view.getPaddingTop(),
207 view.getPaddingRight(),
208 padding);
209 }
210
211 private void updateListPadding() {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500212 if (currentBottomView != null && currentBottomView.getHeight() != 0) {
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400213 setBottomPadding(binding.histList, currentBottomView.getHeight() + marginPxTotal);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500214 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
215 params.bottomMargin = currentBottomView.getHeight() + marginPxTotal;
216 binding.mapCard.setLayoutParams(params);
217 }
Adrien Béraud91f88742019-09-09 00:46:46 -0400218 }
219
Adrien Béraudb28c4912018-12-02 22:58:52 -0500220 @Nullable
221 @Override
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500222 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Adrien Béraud7307cd52020-04-13 23:29:11 -0400223 ((JamiApplication) getActivity().getApplication()).getInjectionComponent().inject(this);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500224 Resources res = getResources();
225 marginPx = res.getDimensionPixelSize(R.dimen.conversation_message_input_margin);
226 mapWidth = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_width);
227 mapHeight = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_height);
Adrien Béraud91f88742019-09-09 00:46:46 -0400228 marginPxTotal = marginPx;
Adrien Béraudfd083672019-10-31 13:52:38 -0400229
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500230 binding = FragConversationBinding.inflate(inflater, container, false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500231 binding.setPresenter(this);
Adrien Béraud91f88742019-09-09 00:46:46 -0400232
Adrien Béraudfd083672019-10-31 13:52:38 -0400233 animation.setDuration(150);
234 animation.addUpdateListener(valueAnimator -> setBottomPadding(binding.histList, (Integer)valueAnimator.getAnimatedValue()));
235
Adrien Béraud91f88742019-09-09 00:46:46 -0400236 ViewCompat.setOnApplyWindowInsetsListener(binding.histList, (v, insets) -> {
237 marginPxTotal = marginPx + insets.getSystemWindowInsetBottom();
238 updateListPadding();
239 insets.consumeSystemWindowInsets();
240 return insets;
241 });
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500242 View layout = binding.conversationLayout;
243
244 // remove action bar height for tablet layout
245 if (DeviceUtils.isTablet(getContext())) {
246 layout.setPadding(layout.getPaddingLeft(), 0, layout.getPaddingRight(), layout.getPaddingBottom());
247 }
248
249 int paddingTop = layout.getPaddingTop();
250 ViewCompat.setOnApplyWindowInsetsListener(layout, (v, insets) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400251 v.setPadding(
252 v.getPaddingLeft(),
253 paddingTop + insets.getSystemWindowInsetTop(),
254 v.getPaddingRight(),
255 v.getPaddingBottom());
256 insets.consumeSystemWindowInsets();
257 return insets;
258 });
259
Adrien Béraudfd083672019-10-31 13:52:38 -0400260 binding.ongoingcallPane.setVisibility(View.GONE);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400261 binding.msgInputTxt.setMediaListener(contentInfo -> startFileSend(AndroidFileUtils
Adrien Béraudfd083672019-10-31 13:52:38 -0400262 .getCacheFile(requireContext(), contentInfo.getContentUri())
263 .flatMapCompletable(this::sendFile)
264 .doFinally(contentInfo::releasePermission)));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500265 binding.msgInputTxt.setOnEditorActionListener((v, actionId, event) -> actionSendMsgText(actionId));
Adrien Béraud5477ce82020-02-24 11:13:54 -0500266 binding.msgInputTxt.setOnFocusChangeListener((view, hasFocus) -> {
267 if (hasFocus) {
268 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
269 if (fragment != null) {
270 ((LocationSharingFragment) fragment).hideControls();
271 }
272 }
273 });
Adrien Béraudb28c4912018-12-02 22:58:52 -0500274 binding.msgInputTxt.addTextChangedListener(new TextWatcher() {
Adrien Béraud3a875a02018-07-18 17:54:17 -0400275 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500276 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
277 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400278
279 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500280 public void onTextChanged(CharSequence s, int start, int before, int count) {
281 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400282
283 @Override
284 public void afterTextChanged(Editable s) {
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400285 String message = s.toString();
Adrien Béraude09dd012019-11-15 14:57:18 -0500286 boolean hasMessage = !TextUtils.isEmpty(message);
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500287 presenter.onComposingChanged(hasMessage);
Rayan Osseiran6f415662019-10-25 14:23:25 -0400288 if (hasMessage) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500289 binding.msgSend.setVisibility(View.VISIBLE);
290 binding.emojiSend.setVisibility(View.GONE);
Adrien Béraude09dd012019-11-15 14:57:18 -0500291 } else {
292 binding.msgSend.setVisibility(View.GONE);
293 binding.emojiSend.setVisibility(View.VISIBLE);
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400294 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400295 if (mPreferences != null) {
Rayan Osseiran6f415662019-10-25 14:23:25 -0400296 if (hasMessage)
297 mPreferences.edit().putString(KEY_PREFERENCE_PENDING_MESSAGE, message).apply();
298 else
299 mPreferences.edit().remove(KEY_PREFERENCE_PENDING_MESSAGE).apply();
Adrien Béraud3a875a02018-07-18 17:54:17 -0400300 }
301 }
302 });
Adrien Béraud9d4a81f2018-07-09 01:19:52 -0400303
Adrien Béraudfd083672019-10-31 13:52:38 -0400304 setHasOptionsMenu(true);
305 return binding.getRoot();
306 }
307
308 @Override
309 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
310 super.onViewCreated(view, savedInstanceState);
Adrien Béraudfd083672019-10-31 13:52:38 -0400311 if (mPreferences != null) {
312 String pendingMessage = mPreferences.getString(KEY_PREFERENCE_PENDING_MESSAGE, null);
313 if (!TextUtils.isEmpty(pendingMessage)) {
314 binding.msgInputTxt.setText(pendingMessage);
315 binding.msgSend.setVisibility(View.VISIBLE);
316 binding.emojiSend.setVisibility(View.GONE);
317 }
318 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500319
320 binding.msgInputTxt.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400321 if (oldBottom == 0 && oldTop == 0) {
322 updateListPadding();
323 } else {
324 if (animation.isStarted())
325 animation.cancel();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400326 animation.setIntValues(binding.histList.getPaddingBottom(), (currentBottomView == null ? 0 : currentBottomView.getHeight()) + marginPxTotal);
Adrien Béraud91f88742019-09-09 00:46:46 -0400327 animation.start();
328 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500329 });
330
Adrien Béraudb28c4912018-12-02 22:58:52 -0500331 DefaultItemAnimator animator = (DefaultItemAnimator) binding.histList.getItemAnimator();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500332 if (animator != null)
333 animator.setSupportsChangeAnimations(false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500334 binding.histList.setAdapter(mAdapter);
Amirhossein7bb77aa2020-12-18 16:30:44 -0500335
336 if (presenter.isRecordingBlocked()) {
337 getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
338 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500339 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500340
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500341 @Override
342 public void setConversationColor(int color) {
Adrien Béraud171ba362018-12-14 21:35:40 -0500343 Colorable activity = (Colorable) getActivity();
344 if (activity != null)
345 activity.setColor(color);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500346 mAdapter.setPrimaryColor(color);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500347 }
348
Adrien Béraud7c505112018-03-20 16:03:28 -0400349 @Override
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500350 public void onDestroyView() {
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500351 if (mPreferences != null)
352 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
Adrien Béraud772e2162019-02-12 16:00:21 -0500353 animation.removeAllUpdateListeners();
Adrien Béraudb28c4912018-12-02 22:58:52 -0500354 binding.histList.setAdapter(null);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500355 mCompositeDisposable.clear();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500356 if (locationServiceConnection != null) {
357 try {
358 requireContext().unbindService(locationServiceConnection);
359 } catch (Exception e) {
360 Log.w(TAG, "Error unbinding service: " + e.getMessage());
361 }
362 }
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500363 mAdapter = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500364 super.onDestroyView();
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400365 binding = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500366 }
367
368 @Override
Adrien Béraudfd083672019-10-31 13:52:38 -0400369 public boolean onContextItemSelected(@NonNull MenuItem item) {
Adrien Béraud7c505112018-03-20 16:03:28 -0400370 if (mAdapter.onContextItemSelected(item))
371 return true;
372 return super.onContextItemSelected(item);
373 }
374
Rayan Osseirane634a562019-05-29 13:44:55 -0400375 public void updateAdapterItem() {
Adrien Béraud742d3202019-11-15 14:28:59 -0500376 if (mSelectedPosition != -1) {
377 mAdapter.notifyItemChanged(mSelectedPosition);
378 mSelectedPosition = -1;
Rayan Osseirane634a562019-05-29 13:44:55 -0400379 }
380 }
381
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500382 public void sendMessageText() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500383 String message = binding.msgInputTxt.getText().toString();
Adrien Béraudace37a22018-06-22 14:58:36 -0400384 clearMsgEdit();
385 presenter.sendTextMessage(message);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500386 }
387
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400388 public void sendEmoji() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500389 presenter.sendTextMessage(binding.emojiSend.getText().toString());
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400390 }
391
Adrien Béraud5477ce82020-02-24 11:13:54 -0500392 @SuppressLint("RestrictedApi")
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400393 public void expandMenu(View v) {
394 Context context = requireContext();
395 PopupMenu popup = new PopupMenu(context, v);
396 popup.inflate(R.menu.conversation_share_actions);
397 popup.setOnMenuItemClickListener(item -> {
398 switch(item.getItemId()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400399 case R.id.conv_send_audio:
400 sendAudioMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400401 break;
Adrien Béraudd5637f22020-05-14 12:41:50 -0400402 case R.id.conv_send_video:
403 sendVideoMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400404 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400405 case R.id.conv_send_file:
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400406 presenter.selectFile();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400407 break;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500408 case R.id.conv_share_location:
409 shareLocation();
410 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400411 }
412 return false;
413 });
414 MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), v);
415 menuHelper.setForceShowIcon(true);
416 menuHelper.show();
417 }
418
Adrien Béraud5477ce82020-02-24 11:13:54 -0500419 public void shareLocation() {
420 presenter.shareLocation();
421 }
422
423 public void closeLocationSharing(boolean isSharing) {
424 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
425 if (params.width != mapWidth) {
426 params.width = mapWidth;
427 params.height = mapHeight;
428 binding.mapCard.setLayoutParams(params);
429 }
430 if (!isSharing)
431 hideMap();
432 }
433
434 public void openLocationSharing() {
435 binding.conversationLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
436 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
437 if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
438 params.width = ViewGroup.LayoutParams.MATCH_PARENT;
439 params.height = ViewGroup.LayoutParams.MATCH_PARENT;
440 binding.mapCard.setLayoutParams(params);
441 }
442 }
443
444 @Override
445 public void startShareLocation(String accountId, String conversationId) {
446 showMap(accountId, conversationId, true);
447 }
448
Rayan Osseirane634a562019-05-29 13:44:55 -0400449 /**
450 * Used to update with the past adapter position when a long click was registered
Rayan Osseirane634a562019-05-29 13:44:55 -0400451 */
452 public void updatePosition(int position) {
Adrien Béraud742d3202019-11-15 14:28:59 -0500453 mSelectedPosition = position;
Rayan Osseirane634a562019-05-29 13:44:55 -0400454 }
455
Adrien Béraud5477ce82020-02-24 11:13:54 -0500456 @Override
457 public void showMap(String accountId, String contactId, boolean open) {
458 if (binding.mapCard.getVisibility() == View.GONE) {
459 Log.w(TAG, "showMap " + accountId + " " + contactId);
460
461 FragmentManager fragmentManager = getChildFragmentManager();
462 LocationSharingFragment fragment = LocationSharingFragment.newInstance(accountId, contactId, open);
463 fragmentManager.beginTransaction()
464 .add(R.id.mapLayout, fragment, "map")
465 .commit();
466 binding.mapCard.setVisibility(View.VISIBLE);
467 }
468 if (open) {
469 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
470 if (fragment != null) {
471 ((LocationSharingFragment) fragment).showControls();
472 }
473 }
474 }
475
476 @Override
477 public void hideMap() {
478 if (binding.mapCard.getVisibility() != View.GONE) {
479 binding.mapCard.setVisibility(View.GONE);
480
481 FragmentManager fragmentManager = getChildFragmentManager();
482 Fragment fragment = fragmentManager.findFragmentById(R.id.mapLayout);
483
484 if (fragment != null) {
485 fragmentManager.beginTransaction()
486 .remove(fragment)
487 .commit();
488 }
489 }
490 }
491
Adrien Béraudd5637f22020-05-14 12:41:50 -0400492 public void sendAudioMessage() {
493 if (!presenter.getDeviceRuntimeService().hasAudioPermission()) {
494 requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE_CAPTURE_AUDIO);
495 } else {
496 Context ctx = requireContext();
497 Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
498
499 if (intent.resolveActivity(ctx.getPackageManager()) != null) {
500 try {
501 mCurrentPhoto = AndroidFileUtils.createAudioFile(ctx);
502 } catch (IOException ex) {
503 Log.e(TAG, "takePicture: error creating temporary file", ex);
504 return;
505 }
506 startActivityForResult(intent, REQUEST_CODE_CAPTURE_AUDIO);
507 } else {
508 Toast.makeText(getActivity(), "Can't find audio recorder app", Toast.LENGTH_SHORT).show();
509 }
510 }
511 }
512
513 public void sendVideoMessage() {
514 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
515 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_CAPTURE_VIDEO);
516 } else {
517 Context context = requireContext();
518 Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
519 intent.putExtra("android.intent.extras.CAMERA_FACING", android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
520 intent.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
521 intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
522 if (intent.resolveActivity(context.getPackageManager()) != null) {
523 try {
524 mCurrentPhoto = AndroidFileUtils.createVideoFile(context);
525 } catch (IOException ex) {
526 Log.e(TAG, "takePicture: error creating temporary file", ex);
527 return;
528 }
529 intent.putExtra(MediaStore.EXTRA_OUTPUT, ContentUriHandler.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, mCurrentPhoto));
530 startActivityForResult(intent, REQUEST_CODE_CAPTURE_VIDEO);
531 } else {
532 Toast.makeText(getActivity(), "Can't find video recorder app", Toast.LENGTH_SHORT).show();
533 }
534 }
535 }
536
Adrien Béraud64538722018-03-15 17:34:00 -0400537 public void takePicture() {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500538 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400539 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_TAKE_PICTURE);
Adrien Béraud24027dd2020-10-19 18:21:31 -0400540 return;
541 }
542 Context c = getContext();
543 if (c == null)
544 return;
545 try {
546 File photoFile = AndroidFileUtils.createImageFile(c);
547 Log.i(TAG, "takePicture: trying to save to " + photoFile);
548 android.net.Uri photoURI = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, photoFile);
549 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
550 .putExtra("android.intent.extras.CAMERA_FACING", 1)
551 .putExtra("android.intent.extras.LENS_FACING_FRONT", 1)
552 .putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
553 mCurrentPhoto = photoFile;
554 startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE);
555 } catch (Exception e) {
556 Toast.makeText(c, "Error taking picture: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
Adrien Béraud64538722018-03-15 17:34:00 -0400557 }
558 }
559
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500560 @Override
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500561 public void askWriteExternalStoragePermission() {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400562 requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, JamiApplication.PERMISSIONS_REQUEST);
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500563 }
564
565 @Override
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500566 public void openFilePicker() {
567 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
568 intent.addCategory(Intent.CATEGORY_OPENABLE);
569 intent.setType("*/*");
570
571 startActivityForResult(intent, REQUEST_CODE_FILE_PICKER);
572 }
573
Adrien Béraud44939482019-02-13 21:42:08 -0500574 private Completable sendFile(File file) {
575 return Completable.fromAction(() -> presenter.sendFile(file));
576 }
577
Adrien Béraud44939482019-02-13 21:42:08 -0500578 private void startFileSend(Completable op) {
579 setLoading(true);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400580 op.observeOn(AndroidSchedulers.mainThread())
Adrien Béraud44939482019-02-13 21:42:08 -0500581 .doFinally(() -> setLoading(false))
582 .subscribe(() -> {}, e -> {
583 Log.e(TAG, "startFileSend: not able to create cache file", e);
Adrien Bérauda0226ff2019-11-21 15:24:42 -0500584 displayErrorToast(Error.INVALID_FILE);
Adrien Béraud44939482019-02-13 21:42:08 -0500585 });
586 }
587
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500588 @Override
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400589 public void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
Adrien Béraud64538722018-03-15 17:34:00 -0400590 Log.w(TAG, "onActivityResult: " + requestCode + " " + resultCode + " " + resultData);
Adrien Béraud70dd5aa2020-12-04 15:18:47 -0500591 android.net.Uri uri = resultData == null ? null : resultData.getData();
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400592 if (requestCode == REQUEST_CODE_FILE_PICKER) {
593 if (resultCode == RESULT_OK && uri != null) {
594 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri)
595 .observeOn(AndroidSchedulers.mainThread())
596 .flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500597 }
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400598 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE
599 || requestCode == REQUEST_CODE_CAPTURE_AUDIO
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400600 || requestCode == REQUEST_CODE_CAPTURE_VIDEO)
601 {
Adrien Béraud64538722018-03-15 17:34:00 -0400602 if (resultCode != RESULT_OK) {
603 mCurrentPhoto = null;
604 return;
605 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500606 Log.w(TAG, "onActivityResult: mCurrentPhoto " + mCurrentPhoto.getAbsolutePath() + " " + mCurrentPhoto.exists() + " " + mCurrentPhoto.length());
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400607 Single<File> file = null;
Adrien Béraud64538722018-03-15 17:34:00 -0400608 if (mCurrentPhoto == null || !mCurrentPhoto.exists() || mCurrentPhoto.length() == 0) {
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400609 if (uri != null) {
610 file = AndroidFileUtils.getCacheFile(requireContext(), uri);
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400611 }
612 } else {
613 file = Single.just(mCurrentPhoto);
Adrien Béraud64538722018-03-15 17:34:00 -0400614 }
Adrien Béraud44939482019-02-13 21:42:08 -0500615 mCurrentPhoto = null;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400616 if (file == null) {
617 Toast.makeText(getActivity(), "Can't find picture", Toast.LENGTH_SHORT).show();
618 return;
619 }
620 startFileSend(file.flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500621 }
amine younes7c56f312019-06-10 11:34:25 -0400622 // File download trough SAF
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400623 else if (requestCode == ConversationFragment.REQUEST_CODE_SAVE_FILE) {
624 if (resultCode == RESULT_OK && uri != null) {
625 writeToFile(uri);
amine younes7c56f312019-06-10 11:34:25 -0400626 }
627 }
Pierre Duchemin17542a72018-02-14 16:38:36 -0500628 }
629
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -0400630 private void writeToFile(android.net.Uri data) {
631 File input = new File(mCurrentFileAbsolutePath);
632 if (requireContext().getContentResolver() != null)
633 mCompositeDisposable.add(AndroidFileUtils.copyFileToUri(requireContext().getContentResolver(), input, data).
634 observeOn(AndroidSchedulers.mainThread()).
635 subscribe(() -> Toast.makeText(getContext(), R.string.file_saved_successfully, Toast.LENGTH_SHORT).show(),
636 error -> Toast.makeText(getContext(), R.string.generic_error, Toast.LENGTH_SHORT).show()));
637 }
638
Pierre Duchemin17542a72018-02-14 16:38:36 -0500639 @Override
Adrien Béraud4f542f92019-01-03 12:17:53 -0500640 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500641 for (int i = 0, n = permissions.length; i < n; i++) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400642 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500643 switch (permissions[i]) {
644 case Manifest.permission.CAMERA:
Rayan Osseiran38206c62019-05-15 14:49:03 -0400645 presenter.cameraPermissionChanged(granted);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500646 if (granted) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400647 if (requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
648 sendVideoMessage();
649 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE) {
650 takePicture();
651 }
652 }
653 return;
654 case Manifest.permission.RECORD_AUDIO:
655 if (granted) {
656 if (requestCode == REQUEST_CODE_CAPTURE_AUDIO) {
657 sendAudioMessage();
658 }
Adrien Béraud4f542f92019-01-03 12:17:53 -0500659 }
660 return;
661 default:
662 break;
663 }
664 }
665 }
666
667 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400668 public void addElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400669 mAdapter.add(element);
670 scrollToEnd();
671 }
Adrien Béraud3cbc7fa2018-07-18 18:36:21 -0400672
Adrien Béraudace37a22018-06-22 14:58:36 -0400673 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400674 public void updateElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400675 mAdapter.update(element);
676 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500677
Adrien Béraudace37a22018-06-22 14:58:36 -0400678 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400679 public void removeElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400680 mAdapter.remove(element);
Adrien Béraud21533292018-03-22 14:11:35 -0400681 }
682
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400683 @Override
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500684 public void setComposingStatus(Account.ComposingStatus composingStatus) {
685 mAdapter.setComposingStatus(composingStatus);
686 if (composingStatus == Account.ComposingStatus.Active)
687 scrollToEnd();
688 }
689
690 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400691 public void setLastDisplayed(Interaction interaction) {
692 mAdapter.setLastDisplayed(interaction);
693 }
694
695 @Override
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400696 public void shareFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500697 Context c = getContext();
698 if (c == null)
699 return;
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400700 android.net.Uri fileUri = null;
701 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500702 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400703 } catch (IllegalArgumentException e) {
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500704 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400705 }
706 if (fileUri != null) {
707 Intent sendIntent = new Intent();
708 sendIntent.setAction(Intent.ACTION_SEND);
709 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500710 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400711 sendIntent.setDataAndType(fileUri, type);
712 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
713 startActivity(Intent.createChooser(sendIntent, null));
714 }
715 }
716
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500717 @Override
718 public void openFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500719 Context c = getContext();
720 if (c == null)
721 return;
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500722 android.net.Uri fileUri = null;
723 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500724 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500725 } catch (IllegalArgumentException e) {
726 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
727 }
728 if (fileUri != null) {
729 Intent sendIntent = new Intent();
730 sendIntent.setAction(Intent.ACTION_VIEW);
731 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500732 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500733 sendIntent.setDataAndType(fileUri, type);
734 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
735 //startActivity(Intent.createChooser(sendIntent, null));
Rayan Osseirane4450272019-06-03 14:17:19 -0400736 try {
737 startActivity(sendIntent);
738 } catch (ActivityNotFoundException e) {
739 Snackbar.make(getView(), R.string.conversation_open_file_error, Snackbar.LENGTH_LONG).show();
740 Log.e("File Loader", "File of unknown type, could not open: " + path.getName());
741 }
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500742 }
743 }
744
Adrien Béraud44939482019-02-13 21:42:08 -0500745 boolean actionSendMsgText(int actionId) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500746 switch (actionId) {
747 case EditorInfo.IME_ACTION_SEND:
Adrien Béraudace37a22018-06-22 14:58:36 -0400748 sendMessageText();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500749 return true;
750 }
751 return false;
752 }
753
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500754 public void onClick() {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400755 presenter.clickOnGoingPane();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500756 }
757
758 @Override
759 public void onPause() {
760 super.onPause();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400761 presenter.pause();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500762 }
763
764 @Override
765 public void onResume() {
766 super.onResume();
Amirhossein68916382020-07-19 11:23:59 -0400767 presenter.resume(mIsBubble);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500768 }
769
770 @Override
Andreas Traczykcee415a2019-12-03 15:45:04 -0500771 public void onDestroy() {
772 mCompositeDisposable.dispose();
773 super.onDestroy();
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400774 }
775
776 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400777 public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
778 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500779 return;
780 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400781 inflater.inflate(R.menu.conversation_actions, menu);
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400782 mAudioCallBtn = menu.findItem(R.id.conv_action_audiocall);
783 mVideoCallBtn = menu.findItem(R.id.conv_action_videocall);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500784 }
785
786 @Override
787 public boolean onOptionsItemSelected(MenuItem item) {
788 switch (item.getItemId()) {
789 case android.R.id.home:
790 startActivity(new Intent(getActivity(), HomeActivity.class));
791 return true;
792 case R.id.conv_action_audiocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500793 presenter.goToCall(true);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500794 return true;
795 case R.id.conv_action_videocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500796 presenter.goToCall(false);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500797 return true;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500798 case R.id.conv_contact_details:
799 presenter.openContact();
Aline Bonnet54cf69b2017-03-28 12:03:45 -0400800 return true;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500801 default:
802 return super.onOptionsItemSelected(item);
803 }
804 }
805
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500806 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400807 protected void initPresenter(ConversationPresenter presenter) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400808 ConversationPath path = ConversationPath.fromBundle(getArguments());
Amirhossein68916382020-07-19 11:23:59 -0400809 mIsBubble = getArguments().getBoolean(NotificationServiceImpl.EXTRA_BUBBLE);
Adrien Béraudbba76582020-05-15 19:18:23 -0400810 if (path == null)
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500811 return;
Adrien Béraud2d8a8a82020-10-15 11:05:38 -0400812
813 Uri contactUri = path.getConversationUri();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500814 mAdapter = new ConversationAdapter(this, presenter);
Adrien Béraudbba76582020-05-15 19:18:23 -0400815 presenter.init(contactUri, path.getAccountId());
Adrien Béraud56c34132018-11-29 13:32:00 -0500816 try {
Adrien Béraudbba76582020-05-15 19:18:23 -0400817 mPreferences = requireActivity().getSharedPreferences(path.getAccountId() + "_" + contactUri.getRawRingId(), Context.MODE_PRIVATE);
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500818 mPreferences.registerOnSharedPreferenceChangeListener(this);
819 presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
Adrien Béraud56c34132018-11-29 13:32:00 -0500820 } catch (Exception e) {
821 Log.e(TAG, "Can't load conversation preferences");
822 }
Adrien Béraud5477ce82020-02-24 11:13:54 -0500823
824 if (locationServiceConnection == null) {
825 locationServiceConnection = new ServiceConnection() {
826 @Override
827 public void onServiceConnected(ComponentName name, IBinder service) {
828 Log.w(TAG, "onServiceConnected");
829 LocationSharingService.LocalBinder binder = (LocationSharingService.LocalBinder) service;
830 LocationSharingService locationService = binder.getService();
831 ConversationPath path = new ConversationPath(presenter.getPath());
832 if (locationService.isSharing(path)) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400833 showMap(path.getAccountId(), contactUri.getUri(), false);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500834 }
835 try {
836 requireContext().unbindService(locationServiceConnection);
837 } catch (Exception e) {
838 Log.w(TAG, "Error unbinding service", e);
839 }
840 }
841
842 @Override
843 public void onServiceDisconnected(ComponentName name) {
844 Log.w(TAG, "onServiceDisconnected");
845 locationServiceConnection = null;
846 }
847 };
848
849 Log.w(TAG, "bindService");
850 requireContext().bindService(new Intent(requireContext(), LocationSharingService.class), locationServiceConnection, 0);
851 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500852 }
853
854 @Override
855 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
856 switch (key) {
857 case KEY_PREFERENCE_CONVERSATION_COLOR:
858 presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
859 break;
860 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400861 }
862
863 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400864 public void displayContact(final CallContact contact) {
Andreas Traczykcee415a2019-12-03 15:45:04 -0500865 mCompositeDisposable.clear();
866 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact)
867 .doOnSuccess(d -> {
868 mConversationAvatar = (AvatarDrawable) d;
869 mParticipantAvatars.put(contact.getPrimaryNumber(),
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500870 new AvatarDrawable((AvatarDrawable) d));
Andreas Traczykcee415a2019-12-03 15:45:04 -0500871 })
872 .flatMapObservable(d -> contact.getUpdatesSubject())
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400873 .observeOn(AndroidSchedulers.mainThread())
Andreas Traczykcee415a2019-12-03 15:45:04 -0500874 .subscribe(c -> {
875 mConversationAvatar.update(c);
876 String uri = contact.getPrimaryNumber();
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400877 AvatarDrawable ad = mParticipantAvatars.get(uri);
878 if (ad != null)
879 ad.update(c);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500880 setupActionbar(contact);
881 mAdapter.setPhoto();
882 }));
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400883 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact, false)
884 .doOnSuccess(d -> mSmallParticipantAvatars.put(contact.getPrimaryNumber(), new AvatarDrawable((AvatarDrawable) d)))
885 .flatMapObservable(d -> contact.getUpdatesSubject())
886 .subscribe(c -> {
887 synchronized (mSmallParticipantAvatars) {
888 String uri = contact.getPrimaryNumber();
889 AvatarDrawable ad = mSmallParticipantAvatars.get(uri);
890 if (ad != null)
891 ad.update(c);
892 }
893 }));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400894 }
895
896 @Override
897 public void displayOnGoingCallPane(final boolean display) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500898 binding.ongoingcallPane.setVisibility(display ? View.VISIBLE : View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400899 }
900
901 @Override
902 public void displayNumberSpinner(final Conversation conversation, final Uri number) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500903 binding.numberSelector.setVisibility(View.VISIBLE);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500904 binding.numberSelector.setAdapter(new NumberAdapter(getActivity(),
905 conversation.getContact(), false));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500906 binding.numberSelector.setSelection(getIndex(binding.numberSelector, number));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400907 }
908
909 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400910 public void hideNumberSpinner() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500911 binding.numberSelector.setVisibility(View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400912 }
913
914 @Override
915 public void clearMsgEdit() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500916 binding.msgInputTxt.setText("");
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400917 }
918
919 @Override
920 public void goToHome() {
921 if (getActivity() instanceof ConversationActivity) {
922 getActivity().finish();
Aline Bonneteb5f7ff2017-01-17 11:09:17 -0500923 }
924 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400925
926 @Override
927 public void goToAddContact(CallContact callContact) {
928 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact), REQ_ADD_CONTACT);
929 }
930
931 @Override
932 public void goToCallActivity(String conferenceId) {
933 startActivity(new Intent(Intent.ACTION_VIEW)
Adrien Béraud44939482019-02-13 21:42:08 -0500934 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400935 .putExtra(NotificationService.KEY_CALL_ID, conferenceId));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400936 }
937
938 @Override
Adrien Béraud770ef472020-10-19 16:47:14 -0400939 public void goToContactActivity(String accountId, String contactId) {
940 startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactId),
941 requireActivity().getApplicationContext(), ContactDetailsActivity.class));
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500942 }
943
944 @Override
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500945 public void goToCallActivityWithResult(String accountId, String contactRingId, boolean audioOnly) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400946 Intent intent = new Intent(CallActivity.ACTION_CALL)
Adrien Béraud44939482019-02-13 21:42:08 -0500947 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500948 .putExtra(KEY_ACCOUNT_ID, accountId)
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500949 .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500950 .putExtra(KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400951 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
952 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500953
Andreas Traczykcee415a2019-12-03 15:45:04 -0500954 private void setupActionbar(CallContact contact) {
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400955 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500956 return;
957 }
958
Andreas Traczykcee415a2019-12-03 15:45:04 -0500959 ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar();
960 if (actionBar == null) {
961 return;
962 }
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500963
Andreas Traczykcee415a2019-12-03 15:45:04 -0500964 Context context = actionBar.getThemedContext();
965 String displayName = contact.getDisplayName();
966 String identity = contact.getRingUsername();
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500967
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400968 Activity activity = getActivity();
969 if (activity instanceof HomeActivity) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500970 Toolbar toolbar = getActivity().findViewById(R.id.main_toolbar);
971 TextView title = toolbar.findViewById(R.id.contact_title);
972 TextView subtitle = toolbar.findViewById(R.id.contact_subtitle);
973 ImageView logo = toolbar.findViewById(R.id.contact_image);
974
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400975 if (!((HomeActivity) activity).isConversationSelected()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500976 title.setText("");
977 subtitle.setText("");
978 logo.setImageDrawable(null);
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500979 return;
980 }
981
982 logo.setVisibility(View.VISIBLE);
983 title.setText(displayName);
984 title.setTextSize(15);
985 title.setTypeface(null, Typeface.NORMAL);
986
987 if (identity != null && !identity.equals(displayName)) {
988 subtitle.setText(identity);
989
990 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
991 params.addRule(RelativeLayout.ALIGN_TOP, R.id.contact_image);
992 title.setLayoutParams(params);
993 } else {
994 subtitle.setText("");
995
996 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
997 params.removeRule(RelativeLayout.ALIGN_TOP);
998 params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
999 title.setLayoutParams(params);
1000 }
1001
1002 logo.setImageDrawable(mConversationAvatar);
1003 } else {
1004 if (identity != null && !identity.equals(displayName)) {
1005 actionBar.setSubtitle(identity);
1006 }
1007 actionBar.setTitle(displayName);
1008 int targetSize = (int) (AvatarFactory.SIZE_AB * context.getResources().getDisplayMetrics().density);
1009 mConversationAvatar.setInSize(targetSize);
1010 actionBar.setLogo(null);
1011 actionBar.setLogo(mConversationAvatar);
Andreas Traczykcee415a2019-12-03 15:45:04 -05001012 }
Andreas Traczykcee415a2019-12-03 15:45:04 -05001013 }
1014
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001015 public void blockContactRequest() {
1016 presenter.onBlockIncomingContactRequest();
1017 }
1018
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001019 public void refuseContactRequest() {
1020 presenter.onRefuseIncomingContactRequest();
1021 }
1022
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001023 public void acceptContactRequest() {
1024 presenter.onAcceptIncomingContactRequest();
1025 }
1026
Adrien Béraudace37a22018-06-22 14:58:36 -04001027 public void addContact() {
1028 presenter.onAddContact();
1029 }
1030
1031 @Override
Adrien Béraud5477ce82020-02-24 11:13:54 -05001032 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001033 super.onPrepareOptionsMenu(menu);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001034 boolean visible = binding.cvMessageInput.getVisibility() == View.VISIBLE;
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001035 if (mAudioCallBtn != null)
1036 mAudioCallBtn.setVisible(visible);
1037 if (mVideoCallBtn != null)
1038 mVideoCallBtn.setVisible(visible);
1039 }
1040
1041 @Override
Adrien Béraudace37a22018-06-22 14:58:36 -04001042 public void switchToUnknownView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001043 binding.cvMessageInput.setVisibility(View.GONE);
1044 binding.unknownContactPrompt.setVisibility(View.VISIBLE);
1045 binding.trustRequestPrompt.setVisibility(View.GONE);
1046 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted), contactDisplayName));
1047 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001048 currentBottomView = binding.unknownContactPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001049 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001050 updateListPadding();
Adrien Béraudace37a22018-06-22 14:58:36 -04001051 }
1052
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001053 @Override
1054 public void switchToIncomingTrustRequestView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001055 binding.cvMessageInput.setVisibility(View.GONE);
1056 binding.unknownContactPrompt.setVisibility(View.GONE);
1057 binding.trustRequestPrompt.setVisibility(View.VISIBLE);
1058 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted_yet), contactDisplayName));
1059 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001060 currentBottomView = binding.trustRequestPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001061 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001062 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001063 }
1064
1065 @Override
1066 public void switchToConversationView() {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001067 binding.cvMessageInput.setVisibility(View.VISIBLE);
1068 binding.unknownContactPrompt.setVisibility(View.GONE);
1069 binding.trustRequestPrompt.setVisibility(View.GONE);
1070 binding.trustRequestMessageLayout.setVisibility(View.GONE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001071 currentBottomView = binding.cvMessageInput;
Adrien Béraud44939482019-02-13 21:42:08 -05001072 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001073 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001074 }
1075
1076 @Override
1077 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001078 presenter.clickOnGoingPane();
1079 }
1080
1081 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001082 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001083 presenter.clickOnGoingPane();
1084 }
1085
1086 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001087 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001088 presenter.clickOnGoingPane();
1089 }
Pierre Duchemin17542a72018-02-14 16:38:36 -05001090
1091 private void setLoading(boolean isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001092 if (binding == null)
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001093 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -05001094 if (isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001095 binding.btnTakePicture.setVisibility(View.GONE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001096 binding.pbDataTransfer.setVisibility(View.VISIBLE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001097 } else {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001098 binding.btnTakePicture.setVisibility(View.VISIBLE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001099 binding.pbDataTransfer.setVisibility(View.GONE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001100 }
1101 }
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -04001102
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001103 public void handleShareIntent(Intent intent) {
Adrien Béraud5477ce82020-02-24 11:13:54 -05001104 Log.w(TAG, "handleShareIntent " + intent);
1105
1106 String action = intent.getAction();
1107 if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
1108 String type = intent.getType();
1109 if (type == null) {
1110 Log.w(TAG, "Can't share with no type");
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001111 return;
Adrien Béraud5477ce82020-02-24 11:13:54 -05001112 }
1113 if (type.startsWith("text/plain")) {
1114 binding.msgInputTxt.setText(intent.getStringExtra(Intent.EXTRA_TEXT));
1115 } else {
1116 android.net.Uri uri = intent.getData();
1117 ClipData clip = intent.getClipData();
1118 if (uri == null && clip != null && clip.getItemCount() > 0)
1119 uri = clip.getItemAt(0).getUri();
1120 if (uri == null)
1121 return;
1122 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri).flatMapCompletable(this::sendFile));
1123 }
1124 } else if (Intent.ACTION_VIEW.equals(action)) {
1125 ConversationPath path = ConversationPath.fromIntent(intent);
1126 if (path != null && intent.getBooleanExtra(EXTRA_SHOW_MAP, false)) {
1127 shareLocation();
1128 }
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001129 }
1130 }
amine younes7c56f312019-06-10 11:34:25 -04001131
1132 /**
1133 * Creates an intent using Android Storage Access Framework
1134 * This intent is then received by applications that can handle it like
1135 * Downloads or Google drive
1136 * @param file DataTransfer of the file that is going to be stored
1137 * @param currentFileAbsolutePath absolute path of the file we want to save
1138 */
1139 public void startSaveFile(DataTransfer file, String currentFileAbsolutePath){
1140 //Get the current file absolute path and store it
1141 mCurrentFileAbsolutePath = currentFileAbsolutePath;
1142
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001143 try {
1144 //Use Android Storage File Access to download the file
1145 Intent downloadFileIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
1146 downloadFileIntent.setType(AndroidFileUtils.getMimeTypeFromExtension(file.getExtension()));
1147 downloadFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
1148 downloadFileIntent.putExtra(Intent.EXTRA_TITLE,file.getDisplayName());
amine younes7c56f312019-06-10 11:34:25 -04001149
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001150 startActivityForResult(downloadFileIntent, ConversationFragment.REQUEST_CODE_SAVE_FILE);
1151 } catch (Exception e) {
1152 Log.i(TAG, "No app detected for saving files.");
1153 File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
1154 if (!directory.exists()) {
1155 directory.mkdirs();
1156 }
1157 writeToFile(android.net.Uri.fromFile(new File(directory, file.getDisplayName())));
1158 }
amine younes7c56f312019-06-10 11:34:25 -04001159 }
1160
Amirhosseine0846c52020-03-12 15:34:35 -04001161 @Override
1162 public void displayNetworkErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001163 if (binding != null) {
1164 binding.errorMsgPane.setVisibility(View.VISIBLE);
Adrien Béraudc2790922020-04-28 17:34:03 -04001165 binding.errorMsgPane.setOnClickListener(null);
1166 binding.errorMsgPane.setText(R.string.error_no_network);
Amirhosseine0846c52020-03-12 15:34:35 -04001167 }
1168 }
1169
1170 @Override
Amirhossein85b3f2e2020-12-01 13:05:43 -05001171 public void setReadIndicatorStatus(boolean show) {
1172 if (mAdapter != null) {
1173 mAdapter.setReadIndicatorStatus(show);
1174 }
1175 }
1176
1177 @Override
Amirhosseine0846c52020-03-12 15:34:35 -04001178 public void hideErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001179 if (binding != null) {
1180 binding.errorMsgPane.setVisibility(View.GONE);
Amirhosseine0846c52020-03-12 15:34:35 -04001181 }
Amirhosseine0846c52020-03-12 15:34:35 -04001182 }
1183
Adrien Béraude32ab742018-08-25 21:15:08 -04001184}