blob: dd1046b8c0ca04892851cf46bafdc70ca7b09378 [file] [log] [blame]
Loïc Siret0202fbf2017-09-28 16:34:28 -04001/*
Sébastien Blinab53ada2019-01-02 17:23:00 -05002 * Copyright (C) 2004-2019 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;
51import android.view.inputmethod.EditorInfo;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050052import android.widget.ImageView;
53import android.widget.RelativeLayout;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050054import android.widget.Spinner;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050055import android.widget.TextView;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050056import android.widget.Toast;
57
Rayan Osseirane4450272019-06-03 14:17:19 -040058import com.google.android.material.snackbar.Snackbar;
59
amine younes7c56f312019-06-10 11:34:25 -040060import androidx.annotation.NonNull;
61import androidx.annotation.Nullable;
62import androidx.appcompat.app.ActionBar;
63import androidx.appcompat.app.AppCompatActivity;
Adrien Béraud898c2bf2019-09-26 14:49:33 -040064import androidx.appcompat.view.menu.MenuBuilder;
65import androidx.appcompat.view.menu.MenuPopupHelper;
66import androidx.appcompat.widget.PopupMenu;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050067import androidx.appcompat.widget.Toolbar;
Adrien Béraud91f88742019-09-09 00:46:46 -040068import androidx.core.view.ViewCompat;
Adrien Béraud5477ce82020-02-24 11:13:54 -050069import androidx.fragment.app.Fragment;
70import androidx.fragment.app.FragmentManager;
amine younes7c56f312019-06-10 11:34:25 -040071import androidx.recyclerview.widget.DefaultItemAnimator;
72
Pierre Duchemine0c3a492018-02-01 16:22:45 -050073import java.io.File;
74import java.io.IOException;
Andreas Traczykcee415a2019-12-03 15:45:04 -050075import java.util.HashMap;
Adrien Béraudace37a22018-06-22 14:58:36 -040076import java.util.List;
Andreas Traczykcee415a2019-12-03 15:45:04 -050077import java.util.Map;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050078
Adrien Béraud5b47cb52018-07-06 16:24:14 -040079import cx.ring.BuildConfig;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050080import cx.ring.R;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050081import cx.ring.adapters.ConversationAdapter;
82import cx.ring.adapters.NumberAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040083import cx.ring.application.JamiApplication;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050084import cx.ring.client.CallActivity;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -050085import cx.ring.client.ContactDetailsActivity;
Aline Bonnet830c4c62016-12-27 14:02:02 -050086import cx.ring.client.ConversationActivity;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050087import cx.ring.client.HomeActivity;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040088import cx.ring.contacts.AvatarFactory;
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -040089import cx.ring.conversation.ConversationPresenter;
90import cx.ring.conversation.ConversationView;
Adrien Béraudb28c4912018-12-02 22:58:52 -050091import cx.ring.databinding.FragConversationBinding;
Adrien Béraud171ba362018-12-14 21:35:40 -050092import cx.ring.interfaces.Colorable;
Adrien Béraudfd458ea2020-02-28 13:40:18 -050093import cx.ring.model.Account;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050094import cx.ring.model.CallContact;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050095import cx.ring.model.Conversation;
Rayan Osseiran6f415662019-10-25 14:23:25 -040096import cx.ring.model.Interaction;
Adrien Béraud21533292018-03-22 14:11:35 -040097import cx.ring.model.DataTransfer;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050098import cx.ring.model.Phone;
Adrien Bérauda0226ff2019-11-21 15:24:42 -050099import cx.ring.model.Error;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500100import cx.ring.model.Uri;
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500101import cx.ring.mvp.BaseSupportFragment;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500102import cx.ring.services.LocationSharingService;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400103import cx.ring.services.NotificationService;
Amirhossein68916382020-07-19 11:23:59 -0400104import cx.ring.services.NotificationServiceImpl;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500105import cx.ring.utils.ActionHelper;
Adrien Béraud64538722018-03-15 17:34:00 -0400106import cx.ring.utils.AndroidFileUtils;
Adrien Béraud64538722018-03-15 17:34:00 -0400107import cx.ring.utils.ContentUriHandler;
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500108import cx.ring.utils.DeviceUtils;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500109import cx.ring.utils.ConversationPath;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500110import cx.ring.utils.MediaButtonsHelper;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500111import cx.ring.views.AvatarDrawable;
Adrien Béraud44939482019-02-13 21:42:08 -0500112import io.reactivex.Completable;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400113import io.reactivex.Single;
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400114import io.reactivex.android.schedulers.AndroidSchedulers;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500115import io.reactivex.disposables.CompositeDisposable;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500116
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500117import static android.app.Activity.RESULT_OK;
118
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500119public class ConversationFragment extends BaseSupportFragment<ConversationPresenter> implements
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500120 MediaButtonsHelper.MediaButtonsHelperCallback,
Rayan Osseirane634a562019-05-29 13:44:55 -0400121 ConversationView, SharedPreferences.OnSharedPreferenceChangeListener {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500122 private static final String TAG = ConversationFragment.class.getSimpleName();
Adrien Béraud64538722018-03-15 17:34:00 -0400123
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400124 public static final int REQ_ADD_CONTACT = 42;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400125
Adrien Béraud6ac63632018-12-09 00:11:21 -0500126 public static final String KEY_CONTACT_RING_ID = BuildConfig.APPLICATION_ID + ".CONTACT_RING_ID";
127 public static final String KEY_ACCOUNT_ID = BuildConfig.APPLICATION_ID + ".ACCOUNT_ID";
Adrien Béraud3a875a02018-07-18 17:54:17 -0400128 public static final String KEY_PREFERENCE_PENDING_MESSAGE = "pendingMessage";
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500129 public static final String KEY_PREFERENCE_CONVERSATION_COLOR = "color";
Adrien Béraud5477ce82020-02-24 11:13:54 -0500130 public static final String EXTRA_SHOW_MAP = "showMap";
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500131
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500132 private static final int REQUEST_CODE_FILE_PICKER = 1000;
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500133 private static final int REQUEST_PERMISSION_CAMERA = 1001;
Adrien Béraud64538722018-03-15 17:34:00 -0400134 private static final int REQUEST_CODE_TAKE_PICTURE = 1002;
amine younes7c56f312019-06-10 11:34:25 -0400135 private static final int REQUEST_CODE_SAVE_FILE = 1003;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400136 private static final int REQUEST_CODE_CAPTURE_AUDIO = 1004;
137 private static final int REQUEST_CODE_CAPTURE_VIDEO = 1005;
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500138
Adrien Béraud5477ce82020-02-24 11:13:54 -0500139 private ServiceConnection locationServiceConnection = null;
140
Adrien Béraudb28c4912018-12-02 22:58:52 -0500141 private FragConversationBinding binding;
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400142 private MenuItem mAudioCallBtn = null;
143 private MenuItem mVideoCallBtn = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500144
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400145 private View currentBottomView = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500146 private ConversationAdapter mAdapter = null;
Adrien Béraud772e2162019-02-12 16:00:21 -0500147 private int marginPx;
Adrien Béraud91f88742019-09-09 00:46:46 -0400148 private int marginPxTotal;
Adrien Béraud772e2162019-02-12 16:00:21 -0500149 private final ValueAnimator animation = new ValueAnimator();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500150
Adrien Béraud3a875a02018-07-18 17:54:17 -0400151 private SharedPreferences mPreferences;
152
Adrien Béraud64538722018-03-15 17:34:00 -0400153 private File mCurrentPhoto = null;
amine younes7c56f312019-06-10 11:34:25 -0400154 private String mCurrentFileAbsolutePath = null;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500155 private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
Adrien Béraud742d3202019-11-15 14:28:59 -0500156 private int mSelectedPosition;
Adrien Béraud64538722018-03-15 17:34:00 -0400157
Amirhossein68916382020-07-19 11:23:59 -0400158 private boolean mIsBubble;
159
Andreas Traczykcee415a2019-12-03 15:45:04 -0500160 private AvatarDrawable mConversationAvatar;
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400161 private final Map<String, AvatarDrawable> mParticipantAvatars = new HashMap<>();
162 private final Map<String, AvatarDrawable> mSmallParticipantAvatars = new HashMap<>();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500163 private int mapWidth, mapHeight;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500164
165 public AvatarDrawable getConversationAvatar(String uri) {
166 return mParticipantAvatars.get(uri);
167 }
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400168 public AvatarDrawable getSmallConversationAvatar(String uri) {
169 synchronized (mSmallParticipantAvatars) {
170 return mSmallParticipantAvatars.get(uri);
171 }
172 }
Andreas Traczykcee415a2019-12-03 15:45:04 -0500173
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500174 private static int getIndex(Spinner spinner, Uri myString) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500175 for (int i = 0, n = spinner.getCount(); i < n; i++)
176 if (((Phone) spinner.getItemAtPosition(i)).getNumber().equals(myString)) {
177 return i;
178 }
179 return 0;
180 }
181
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400182 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400183 public void refreshView(final List<Interaction> conversation) {
Adrien Béraud20d42212018-03-02 14:40:38 -0500184 if (conversation == null) {
185 return;
186 }
Adrien Béraudb28c4912018-12-02 22:58:52 -0500187 if (binding != null)
188 binding.pbLoading.setVisibility(View.GONE);
Adrien Béraudace37a22018-06-22 14:58:36 -0400189 if (mAdapter != null) {
190 mAdapter.updateDataset(conversation);
191 }
Rayan Osseiran6f415662019-10-25 14:23:25 -0400192 requireActivity().invalidateOptionsMenu();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500193 }
194
Aline Bonnete8e87f62016-12-26 10:54:37 -0500195 @Override
Adrien Béraud64538722018-03-15 17:34:00 -0400196 public void scrollToEnd() {
Adrien Béraudace37a22018-06-22 14:58:36 -0400197 if (mAdapter.getItemCount() > 0) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500198 binding.histList.scrollToPosition(mAdapter.getItemCount() - 1);
Adrien Béraudace37a22018-06-22 14:58:36 -0400199 }
Adrien Béraud64538722018-03-15 17:34:00 -0400200 }
201
Adrien Béraud91f88742019-09-09 00:46:46 -0400202 private static void setBottomPadding(@NonNull View view, int padding) {
203 view.setPadding(
204 view.getPaddingLeft(),
205 view.getPaddingTop(),
206 view.getPaddingRight(),
207 padding);
208 }
209
210 private void updateListPadding() {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500211 if (currentBottomView != null && currentBottomView.getHeight() != 0) {
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400212 setBottomPadding(binding.histList, currentBottomView.getHeight() + marginPxTotal);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500213 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
214 params.bottomMargin = currentBottomView.getHeight() + marginPxTotal;
215 binding.mapCard.setLayoutParams(params);
216 }
Adrien Béraud91f88742019-09-09 00:46:46 -0400217 }
218
Adrien Béraudb28c4912018-12-02 22:58:52 -0500219 @Nullable
220 @Override
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500221 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Adrien Béraud7307cd52020-04-13 23:29:11 -0400222 ((JamiApplication) getActivity().getApplication()).getInjectionComponent().inject(this);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500223 Resources res = getResources();
224 marginPx = res.getDimensionPixelSize(R.dimen.conversation_message_input_margin);
225 mapWidth = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_width);
226 mapHeight = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_height);
Adrien Béraud91f88742019-09-09 00:46:46 -0400227 marginPxTotal = marginPx;
Adrien Béraudfd083672019-10-31 13:52:38 -0400228
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500229 binding = FragConversationBinding.inflate(inflater, container, false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500230 binding.setPresenter(this);
Adrien Béraud91f88742019-09-09 00:46:46 -0400231
Adrien Béraudfd083672019-10-31 13:52:38 -0400232 animation.setDuration(150);
233 animation.addUpdateListener(valueAnimator -> setBottomPadding(binding.histList, (Integer)valueAnimator.getAnimatedValue()));
234
Adrien Béraud91f88742019-09-09 00:46:46 -0400235 ViewCompat.setOnApplyWindowInsetsListener(binding.histList, (v, insets) -> {
236 marginPxTotal = marginPx + insets.getSystemWindowInsetBottom();
237 updateListPadding();
238 insets.consumeSystemWindowInsets();
239 return insets;
240 });
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500241 View layout = binding.conversationLayout;
242
243 // remove action bar height for tablet layout
244 if (DeviceUtils.isTablet(getContext())) {
245 layout.setPadding(layout.getPaddingLeft(), 0, layout.getPaddingRight(), layout.getPaddingBottom());
246 }
247
248 int paddingTop = layout.getPaddingTop();
249 ViewCompat.setOnApplyWindowInsetsListener(layout, (v, insets) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400250 v.setPadding(
251 v.getPaddingLeft(),
252 paddingTop + insets.getSystemWindowInsetTop(),
253 v.getPaddingRight(),
254 v.getPaddingBottom());
255 insets.consumeSystemWindowInsets();
256 return insets;
257 });
258
Adrien Béraudfd083672019-10-31 13:52:38 -0400259 binding.ongoingcallPane.setVisibility(View.GONE);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400260 binding.msgInputTxt.setMediaListener(contentInfo -> startFileSend(AndroidFileUtils
Adrien Béraudfd083672019-10-31 13:52:38 -0400261 .getCacheFile(requireContext(), contentInfo.getContentUri())
262 .flatMapCompletable(this::sendFile)
263 .doFinally(contentInfo::releasePermission)));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500264 binding.msgInputTxt.setOnEditorActionListener((v, actionId, event) -> actionSendMsgText(actionId));
Adrien Béraud5477ce82020-02-24 11:13:54 -0500265 binding.msgInputTxt.setOnFocusChangeListener((view, hasFocus) -> {
266 if (hasFocus) {
267 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
268 if (fragment != null) {
269 ((LocationSharingFragment) fragment).hideControls();
270 }
271 }
272 });
Adrien Béraudb28c4912018-12-02 22:58:52 -0500273 binding.msgInputTxt.addTextChangedListener(new TextWatcher() {
Adrien Béraud3a875a02018-07-18 17:54:17 -0400274 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500275 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
276 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400277
278 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500279 public void onTextChanged(CharSequence s, int start, int before, int count) {
280 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400281
282 @Override
283 public void afterTextChanged(Editable s) {
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400284 String message = s.toString();
Adrien Béraude09dd012019-11-15 14:57:18 -0500285 boolean hasMessage = !TextUtils.isEmpty(message);
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500286 presenter.onComposingChanged(hasMessage);
Rayan Osseiran6f415662019-10-25 14:23:25 -0400287 if (hasMessage) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500288 binding.msgSend.setVisibility(View.VISIBLE);
289 binding.emojiSend.setVisibility(View.GONE);
Adrien Béraude09dd012019-11-15 14:57:18 -0500290 } else {
291 binding.msgSend.setVisibility(View.GONE);
292 binding.emojiSend.setVisibility(View.VISIBLE);
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400293 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400294 if (mPreferences != null) {
Rayan Osseiran6f415662019-10-25 14:23:25 -0400295 if (hasMessage)
296 mPreferences.edit().putString(KEY_PREFERENCE_PENDING_MESSAGE, message).apply();
297 else
298 mPreferences.edit().remove(KEY_PREFERENCE_PENDING_MESSAGE).apply();
Adrien Béraud3a875a02018-07-18 17:54:17 -0400299 }
300 }
301 });
Adrien Béraud9d4a81f2018-07-09 01:19:52 -0400302
Adrien Béraudfd083672019-10-31 13:52:38 -0400303 setHasOptionsMenu(true);
304 return binding.getRoot();
305 }
306
307 @Override
308 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
309 super.onViewCreated(view, savedInstanceState);
Adrien Béraudfd083672019-10-31 13:52:38 -0400310 if (mPreferences != null) {
311 String pendingMessage = mPreferences.getString(KEY_PREFERENCE_PENDING_MESSAGE, null);
312 if (!TextUtils.isEmpty(pendingMessage)) {
313 binding.msgInputTxt.setText(pendingMessage);
314 binding.msgSend.setVisibility(View.VISIBLE);
315 binding.emojiSend.setVisibility(View.GONE);
316 }
317 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500318
319 binding.msgInputTxt.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400320 if (oldBottom == 0 && oldTop == 0) {
321 updateListPadding();
322 } else {
323 if (animation.isStarted())
324 animation.cancel();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400325 animation.setIntValues(binding.histList.getPaddingBottom(), (currentBottomView == null ? 0 : currentBottomView.getHeight()) + marginPxTotal);
Adrien Béraud91f88742019-09-09 00:46:46 -0400326 animation.start();
327 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500328 });
329
Adrien Béraudb28c4912018-12-02 22:58:52 -0500330 DefaultItemAnimator animator = (DefaultItemAnimator) binding.histList.getItemAnimator();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500331 if (animator != null)
332 animator.setSupportsChangeAnimations(false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500333 binding.histList.setAdapter(mAdapter);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500334 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500335
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500336 @Override
337 public void setConversationColor(int color) {
Adrien Béraud171ba362018-12-14 21:35:40 -0500338 Colorable activity = (Colorable) getActivity();
339 if (activity != null)
340 activity.setColor(color);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500341 mAdapter.setPrimaryColor(color);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500342 }
343
Adrien Béraud7c505112018-03-20 16:03:28 -0400344 @Override
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500345 public void onDestroyView() {
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500346 if (mPreferences != null)
347 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
Adrien Béraud772e2162019-02-12 16:00:21 -0500348 animation.removeAllUpdateListeners();
Adrien Béraudb28c4912018-12-02 22:58:52 -0500349 binding.histList.setAdapter(null);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500350 mCompositeDisposable.clear();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500351 if (locationServiceConnection != null) {
352 try {
353 requireContext().unbindService(locationServiceConnection);
354 } catch (Exception e) {
355 Log.w(TAG, "Error unbinding service: " + e.getMessage());
356 }
357 }
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500358 mAdapter = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500359 super.onDestroyView();
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400360 binding = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500361 }
362
363 @Override
Adrien Béraudfd083672019-10-31 13:52:38 -0400364 public boolean onContextItemSelected(@NonNull MenuItem item) {
Adrien Béraud7c505112018-03-20 16:03:28 -0400365 if (mAdapter.onContextItemSelected(item))
366 return true;
367 return super.onContextItemSelected(item);
368 }
369
Rayan Osseirane634a562019-05-29 13:44:55 -0400370 public void updateAdapterItem() {
Adrien Béraud742d3202019-11-15 14:28:59 -0500371 if (mSelectedPosition != -1) {
372 mAdapter.notifyItemChanged(mSelectedPosition);
373 mSelectedPosition = -1;
Rayan Osseirane634a562019-05-29 13:44:55 -0400374 }
375 }
376
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500377 public void sendMessageText() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500378 String message = binding.msgInputTxt.getText().toString();
Adrien Béraudace37a22018-06-22 14:58:36 -0400379 clearMsgEdit();
380 presenter.sendTextMessage(message);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500381 }
382
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400383 public void sendEmoji() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500384 presenter.sendTextMessage(binding.emojiSend.getText().toString());
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400385 }
386
Adrien Béraud5477ce82020-02-24 11:13:54 -0500387 @SuppressLint("RestrictedApi")
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400388 public void expandMenu(View v) {
389 Context context = requireContext();
390 PopupMenu popup = new PopupMenu(context, v);
391 popup.inflate(R.menu.conversation_share_actions);
392 popup.setOnMenuItemClickListener(item -> {
393 switch(item.getItemId()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400394 case R.id.conv_send_audio:
395 sendAudioMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400396 break;
Adrien Béraudd5637f22020-05-14 12:41:50 -0400397 case R.id.conv_send_video:
398 sendVideoMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400399 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400400 case R.id.conv_send_file:
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400401 presenter.selectFile();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400402 break;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500403 case R.id.conv_share_location:
404 shareLocation();
405 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400406 }
407 return false;
408 });
409 MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), v);
410 menuHelper.setForceShowIcon(true);
411 menuHelper.show();
412 }
413
Adrien Béraud5477ce82020-02-24 11:13:54 -0500414 public void shareLocation() {
415 presenter.shareLocation();
416 }
417
418 public void closeLocationSharing(boolean isSharing) {
419 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
420 if (params.width != mapWidth) {
421 params.width = mapWidth;
422 params.height = mapHeight;
423 binding.mapCard.setLayoutParams(params);
424 }
425 if (!isSharing)
426 hideMap();
427 }
428
429 public void openLocationSharing() {
430 binding.conversationLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
431 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
432 if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
433 params.width = ViewGroup.LayoutParams.MATCH_PARENT;
434 params.height = ViewGroup.LayoutParams.MATCH_PARENT;
435 binding.mapCard.setLayoutParams(params);
436 }
437 }
438
439 @Override
440 public void startShareLocation(String accountId, String conversationId) {
441 showMap(accountId, conversationId, true);
442 }
443
Rayan Osseirane634a562019-05-29 13:44:55 -0400444 /**
445 * Used to update with the past adapter position when a long click was registered
Rayan Osseirane634a562019-05-29 13:44:55 -0400446 */
447 public void updatePosition(int position) {
Adrien Béraud742d3202019-11-15 14:28:59 -0500448 mSelectedPosition = position;
Rayan Osseirane634a562019-05-29 13:44:55 -0400449 }
450
Adrien Béraud5477ce82020-02-24 11:13:54 -0500451 @Override
452 public void showMap(String accountId, String contactId, boolean open) {
453 if (binding.mapCard.getVisibility() == View.GONE) {
454 Log.w(TAG, "showMap " + accountId + " " + contactId);
455
456 FragmentManager fragmentManager = getChildFragmentManager();
457 LocationSharingFragment fragment = LocationSharingFragment.newInstance(accountId, contactId, open);
458 fragmentManager.beginTransaction()
459 .add(R.id.mapLayout, fragment, "map")
460 .commit();
461 binding.mapCard.setVisibility(View.VISIBLE);
462 }
463 if (open) {
464 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
465 if (fragment != null) {
466 ((LocationSharingFragment) fragment).showControls();
467 }
468 }
469 }
470
471 @Override
472 public void hideMap() {
473 if (binding.mapCard.getVisibility() != View.GONE) {
474 binding.mapCard.setVisibility(View.GONE);
475
476 FragmentManager fragmentManager = getChildFragmentManager();
477 Fragment fragment = fragmentManager.findFragmentById(R.id.mapLayout);
478
479 if (fragment != null) {
480 fragmentManager.beginTransaction()
481 .remove(fragment)
482 .commit();
483 }
484 }
485 }
486
Adrien Béraudd5637f22020-05-14 12:41:50 -0400487 public void sendAudioMessage() {
488 if (!presenter.getDeviceRuntimeService().hasAudioPermission()) {
489 requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE_CAPTURE_AUDIO);
490 } else {
491 Context ctx = requireContext();
492 Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
493
494 if (intent.resolveActivity(ctx.getPackageManager()) != null) {
495 try {
496 mCurrentPhoto = AndroidFileUtils.createAudioFile(ctx);
497 } catch (IOException ex) {
498 Log.e(TAG, "takePicture: error creating temporary file", ex);
499 return;
500 }
501 startActivityForResult(intent, REQUEST_CODE_CAPTURE_AUDIO);
502 } else {
503 Toast.makeText(getActivity(), "Can't find audio recorder app", Toast.LENGTH_SHORT).show();
504 }
505 }
506 }
507
508 public void sendVideoMessage() {
509 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
510 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_CAPTURE_VIDEO);
511 } else {
512 Context context = requireContext();
513 Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
514 intent.putExtra("android.intent.extras.CAMERA_FACING", android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
515 intent.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
516 intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
517 if (intent.resolveActivity(context.getPackageManager()) != null) {
518 try {
519 mCurrentPhoto = AndroidFileUtils.createVideoFile(context);
520 } catch (IOException ex) {
521 Log.e(TAG, "takePicture: error creating temporary file", ex);
522 return;
523 }
524 intent.putExtra(MediaStore.EXTRA_OUTPUT, ContentUriHandler.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, mCurrentPhoto));
525 startActivityForResult(intent, REQUEST_CODE_CAPTURE_VIDEO);
526 } else {
527 Toast.makeText(getActivity(), "Can't find video recorder app", Toast.LENGTH_SHORT).show();
528 }
529 }
530 }
531
Adrien Béraud64538722018-03-15 17:34:00 -0400532 public void takePicture() {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500533 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400534 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_TAKE_PICTURE);
Adrien Béraud24027dd2020-10-19 18:21:31 -0400535 return;
536 }
537 Context c = getContext();
538 if (c == null)
539 return;
540 try {
541 File photoFile = AndroidFileUtils.createImageFile(c);
542 Log.i(TAG, "takePicture: trying to save to " + photoFile);
543 android.net.Uri photoURI = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, photoFile);
544 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
545 .putExtra("android.intent.extras.CAMERA_FACING", 1)
546 .putExtra("android.intent.extras.LENS_FACING_FRONT", 1)
547 .putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
548 mCurrentPhoto = photoFile;
549 startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE);
550 } catch (Exception e) {
551 Toast.makeText(c, "Error taking picture: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
Adrien Béraud64538722018-03-15 17:34:00 -0400552 }
553 }
554
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500555 @Override
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500556 public void askWriteExternalStoragePermission() {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400557 requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, JamiApplication.PERMISSIONS_REQUEST);
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500558 }
559
560 @Override
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500561 public void openFilePicker() {
562 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
563 intent.addCategory(Intent.CATEGORY_OPENABLE);
564 intent.setType("*/*");
565
566 startActivityForResult(intent, REQUEST_CODE_FILE_PICKER);
567 }
568
Adrien Béraud44939482019-02-13 21:42:08 -0500569 private Completable sendFile(File file) {
570 return Completable.fromAction(() -> presenter.sendFile(file));
571 }
572
Adrien Béraud44939482019-02-13 21:42:08 -0500573 private void startFileSend(Completable op) {
574 setLoading(true);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400575 op.observeOn(AndroidSchedulers.mainThread())
Adrien Béraud44939482019-02-13 21:42:08 -0500576 .doFinally(() -> setLoading(false))
577 .subscribe(() -> {}, e -> {
578 Log.e(TAG, "startFileSend: not able to create cache file", e);
Adrien Bérauda0226ff2019-11-21 15:24:42 -0500579 displayErrorToast(Error.INVALID_FILE);
Adrien Béraud44939482019-02-13 21:42:08 -0500580 });
581 }
582
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500583 @Override
Pierre Duchemin17542a72018-02-14 16:38:36 -0500584 public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
Adrien Béraud64538722018-03-15 17:34:00 -0400585 Log.w(TAG, "onActivityResult: " + requestCode + " " + resultCode + " " + resultData);
Pierre Duchemin17542a72018-02-14 16:38:36 -0500586 super.onActivityResult(requestCode, resultCode, resultData);
587
588 if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
Adrien Béraud64538722018-03-15 17:34:00 -0400589 if (resultData == null) {
590 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -0500591 }
Adrien Béraud64538722018-03-15 17:34:00 -0400592 android.net.Uri uri = resultData.getData();
593 if (uri == null) {
594 return;
595 }
Adrien Béraud1af6c012019-05-25 23:20:29 -0400596 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri)
597 .observeOn(AndroidSchedulers.mainThread())
598 .flatMapCompletable(this::sendFile));
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400599 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE
600 || requestCode == REQUEST_CODE_CAPTURE_AUDIO
601 || requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
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éraud898c2bf2019-09-26 14:49:33 -0400609 android.net.Uri createdUri = resultData.getData();
610 if (createdUri != null) {
611 file = AndroidFileUtils.getCacheFile(requireContext(), createdUri);
612 }
613 } else {
614 file = Single.just(mCurrentPhoto);
Adrien Béraud64538722018-03-15 17:34:00 -0400615 }
Adrien Béraud44939482019-02-13 21:42:08 -0500616 mCurrentPhoto = null;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400617 if (file == null) {
618 Toast.makeText(getActivity(), "Can't find picture", Toast.LENGTH_SHORT).show();
619 return;
620 }
621 startFileSend(file.flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500622 }
amine younes7c56f312019-06-10 11:34:25 -0400623 // File download trough SAF
624 else if(requestCode == ConversationFragment.REQUEST_CODE_SAVE_FILE
625 && resultCode == RESULT_OK){
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -0400626 if (resultData != null && resultData.getData() != null ) {
627 writeToFile(resultData.getData());
amine younes7c56f312019-06-10 11:34:25 -0400628 }
629 }
630
Pierre Duchemin17542a72018-02-14 16:38:36 -0500631 }
632
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -0400633 private void writeToFile(android.net.Uri data) {
634 File input = new File(mCurrentFileAbsolutePath);
635 if (requireContext().getContentResolver() != null)
636 mCompositeDisposable.add(AndroidFileUtils.copyFileToUri(requireContext().getContentResolver(), input, data).
637 observeOn(AndroidSchedulers.mainThread()).
638 subscribe(() -> Toast.makeText(getContext(), R.string.file_saved_successfully, Toast.LENGTH_SHORT).show(),
639 error -> Toast.makeText(getContext(), R.string.generic_error, Toast.LENGTH_SHORT).show()));
640 }
641
Pierre Duchemin17542a72018-02-14 16:38:36 -0500642 @Override
Adrien Béraud4f542f92019-01-03 12:17:53 -0500643 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500644 for (int i = 0, n = permissions.length; i < n; i++) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400645 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500646 switch (permissions[i]) {
647 case Manifest.permission.CAMERA:
Rayan Osseiran38206c62019-05-15 14:49:03 -0400648 presenter.cameraPermissionChanged(granted);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500649 if (granted) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400650 if (requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
651 sendVideoMessage();
652 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE) {
653 takePicture();
654 }
655 }
656 return;
657 case Manifest.permission.RECORD_AUDIO:
658 if (granted) {
659 if (requestCode == REQUEST_CODE_CAPTURE_AUDIO) {
660 sendAudioMessage();
661 }
Adrien Béraud4f542f92019-01-03 12:17:53 -0500662 }
663 return;
664 default:
665 break;
666 }
667 }
668 }
669
670 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400671 public void addElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400672 mAdapter.add(element);
673 scrollToEnd();
674 }
Adrien Béraud3cbc7fa2018-07-18 18:36:21 -0400675
Adrien Béraudace37a22018-06-22 14:58:36 -0400676 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400677 public void updateElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400678 mAdapter.update(element);
679 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500680
Adrien Béraudace37a22018-06-22 14:58:36 -0400681 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400682 public void removeElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400683 mAdapter.remove(element);
Adrien Béraud21533292018-03-22 14:11:35 -0400684 }
685
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400686 @Override
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500687 public void setComposingStatus(Account.ComposingStatus composingStatus) {
688 mAdapter.setComposingStatus(composingStatus);
689 if (composingStatus == Account.ComposingStatus.Active)
690 scrollToEnd();
691 }
692
693 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400694 public void setLastDisplayed(Interaction interaction) {
695 mAdapter.setLastDisplayed(interaction);
696 }
697
698 @Override
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400699 public void shareFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500700 Context c = getContext();
701 if (c == null)
702 return;
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400703 android.net.Uri fileUri = null;
704 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500705 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400706 } catch (IllegalArgumentException e) {
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500707 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400708 }
709 if (fileUri != null) {
710 Intent sendIntent = new Intent();
711 sendIntent.setAction(Intent.ACTION_SEND);
712 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500713 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400714 sendIntent.setDataAndType(fileUri, type);
715 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
716 startActivity(Intent.createChooser(sendIntent, null));
717 }
718 }
719
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500720 @Override
721 public void openFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500722 Context c = getContext();
723 if (c == null)
724 return;
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500725 android.net.Uri fileUri = null;
726 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500727 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500728 } catch (IllegalArgumentException e) {
729 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
730 }
731 if (fileUri != null) {
732 Intent sendIntent = new Intent();
733 sendIntent.setAction(Intent.ACTION_VIEW);
734 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500735 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500736 sendIntent.setDataAndType(fileUri, type);
737 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
738 //startActivity(Intent.createChooser(sendIntent, null));
Rayan Osseirane4450272019-06-03 14:17:19 -0400739 try {
740 startActivity(sendIntent);
741 } catch (ActivityNotFoundException e) {
742 Snackbar.make(getView(), R.string.conversation_open_file_error, Snackbar.LENGTH_LONG).show();
743 Log.e("File Loader", "File of unknown type, could not open: " + path.getName());
744 }
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500745 }
746 }
747
Adrien Béraud44939482019-02-13 21:42:08 -0500748 boolean actionSendMsgText(int actionId) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500749 switch (actionId) {
750 case EditorInfo.IME_ACTION_SEND:
Adrien Béraudace37a22018-06-22 14:58:36 -0400751 sendMessageText();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500752 return true;
753 }
754 return false;
755 }
756
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500757 public void onClick() {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400758 presenter.clickOnGoingPane();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500759 }
760
761 @Override
762 public void onPause() {
763 super.onPause();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400764 presenter.pause();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500765 }
766
767 @Override
768 public void onResume() {
769 super.onResume();
Amirhossein68916382020-07-19 11:23:59 -0400770 presenter.resume(mIsBubble);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500771 }
772
773 @Override
Andreas Traczykcee415a2019-12-03 15:45:04 -0500774 public void onDestroy() {
775 mCompositeDisposable.dispose();
776 super.onDestroy();
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400777 }
778
779 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400780 public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
781 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500782 return;
783 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400784 inflater.inflate(R.menu.conversation_actions, menu);
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400785 mAudioCallBtn = menu.findItem(R.id.conv_action_audiocall);
786 mVideoCallBtn = menu.findItem(R.id.conv_action_videocall);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500787 }
788
789 @Override
790 public boolean onOptionsItemSelected(MenuItem item) {
791 switch (item.getItemId()) {
792 case android.R.id.home:
793 startActivity(new Intent(getActivity(), HomeActivity.class));
794 return true;
795 case R.id.conv_action_audiocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500796 presenter.goToCall(true);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500797 return true;
798 case R.id.conv_action_videocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500799 presenter.goToCall(false);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500800 return true;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500801 case R.id.conv_contact_details:
802 presenter.openContact();
Aline Bonnet54cf69b2017-03-28 12:03:45 -0400803 return true;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500804 default:
805 return super.onOptionsItemSelected(item);
806 }
807 }
808
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500809 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400810 protected void initPresenter(ConversationPresenter presenter) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400811 ConversationPath path = ConversationPath.fromBundle(getArguments());
Amirhossein68916382020-07-19 11:23:59 -0400812 mIsBubble = getArguments().getBoolean(NotificationServiceImpl.EXTRA_BUBBLE);
Adrien Béraudbba76582020-05-15 19:18:23 -0400813 if (path == null)
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500814 return;
Adrien Béraud2d8a8a82020-10-15 11:05:38 -0400815
816 Uri contactUri = path.getConversationUri();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500817 mAdapter = new ConversationAdapter(this, presenter);
Adrien Béraudbba76582020-05-15 19:18:23 -0400818 presenter.init(contactUri, path.getAccountId());
Adrien Béraud56c34132018-11-29 13:32:00 -0500819 try {
Adrien Béraudbba76582020-05-15 19:18:23 -0400820 mPreferences = requireActivity().getSharedPreferences(path.getAccountId() + "_" + contactUri.getRawRingId(), Context.MODE_PRIVATE);
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500821 mPreferences.registerOnSharedPreferenceChangeListener(this);
822 presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
Adrien Béraud56c34132018-11-29 13:32:00 -0500823 } catch (Exception e) {
824 Log.e(TAG, "Can't load conversation preferences");
825 }
Adrien Béraud5477ce82020-02-24 11:13:54 -0500826
827 if (locationServiceConnection == null) {
828 locationServiceConnection = new ServiceConnection() {
829 @Override
830 public void onServiceConnected(ComponentName name, IBinder service) {
831 Log.w(TAG, "onServiceConnected");
832 LocationSharingService.LocalBinder binder = (LocationSharingService.LocalBinder) service;
833 LocationSharingService locationService = binder.getService();
834 ConversationPath path = new ConversationPath(presenter.getPath());
835 if (locationService.isSharing(path)) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400836 showMap(path.getAccountId(), contactUri.getUri(), false);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500837 }
838 try {
839 requireContext().unbindService(locationServiceConnection);
840 } catch (Exception e) {
841 Log.w(TAG, "Error unbinding service", e);
842 }
843 }
844
845 @Override
846 public void onServiceDisconnected(ComponentName name) {
847 Log.w(TAG, "onServiceDisconnected");
848 locationServiceConnection = null;
849 }
850 };
851
852 Log.w(TAG, "bindService");
853 requireContext().bindService(new Intent(requireContext(), LocationSharingService.class), locationServiceConnection, 0);
854 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500855 }
856
857 @Override
858 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
859 switch (key) {
860 case KEY_PREFERENCE_CONVERSATION_COLOR:
861 presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
862 break;
863 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400864 }
865
866 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400867 public void displayContact(final CallContact contact) {
Andreas Traczykcee415a2019-12-03 15:45:04 -0500868 mCompositeDisposable.clear();
869 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact)
870 .doOnSuccess(d -> {
871 mConversationAvatar = (AvatarDrawable) d;
872 mParticipantAvatars.put(contact.getPrimaryNumber(),
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500873 new AvatarDrawable((AvatarDrawable) d));
Andreas Traczykcee415a2019-12-03 15:45:04 -0500874 })
875 .flatMapObservable(d -> contact.getUpdatesSubject())
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400876 .observeOn(AndroidSchedulers.mainThread())
Andreas Traczykcee415a2019-12-03 15:45:04 -0500877 .subscribe(c -> {
878 mConversationAvatar.update(c);
879 String uri = contact.getPrimaryNumber();
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400880 AvatarDrawable ad = mParticipantAvatars.get(uri);
881 if (ad != null)
882 ad.update(c);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500883 setupActionbar(contact);
884 mAdapter.setPhoto();
885 }));
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400886 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact, false)
887 .doOnSuccess(d -> mSmallParticipantAvatars.put(contact.getPrimaryNumber(), new AvatarDrawable((AvatarDrawable) d)))
888 .flatMapObservable(d -> contact.getUpdatesSubject())
889 .subscribe(c -> {
890 synchronized (mSmallParticipantAvatars) {
891 String uri = contact.getPrimaryNumber();
892 AvatarDrawable ad = mSmallParticipantAvatars.get(uri);
893 if (ad != null)
894 ad.update(c);
895 }
896 }));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400897 }
898
899 @Override
900 public void displayOnGoingCallPane(final boolean display) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500901 binding.ongoingcallPane.setVisibility(display ? View.VISIBLE : View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400902 }
903
904 @Override
905 public void displayNumberSpinner(final Conversation conversation, final Uri number) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500906 binding.numberSelector.setVisibility(View.VISIBLE);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500907 binding.numberSelector.setAdapter(new NumberAdapter(getActivity(),
908 conversation.getContact(), false));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500909 binding.numberSelector.setSelection(getIndex(binding.numberSelector, number));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400910 }
911
912 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400913 public void hideNumberSpinner() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500914 binding.numberSelector.setVisibility(View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400915 }
916
917 @Override
918 public void clearMsgEdit() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500919 binding.msgInputTxt.setText("");
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400920 }
921
922 @Override
923 public void goToHome() {
924 if (getActivity() instanceof ConversationActivity) {
925 getActivity().finish();
Aline Bonneteb5f7ff2017-01-17 11:09:17 -0500926 }
927 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400928
929 @Override
930 public void goToAddContact(CallContact callContact) {
931 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact), REQ_ADD_CONTACT);
932 }
933
934 @Override
935 public void goToCallActivity(String conferenceId) {
936 startActivity(new Intent(Intent.ACTION_VIEW)
Adrien Béraud44939482019-02-13 21:42:08 -0500937 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400938 .putExtra(NotificationService.KEY_CALL_ID, conferenceId));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400939 }
940
941 @Override
Adrien Béraud770ef472020-10-19 16:47:14 -0400942 public void goToContactActivity(String accountId, String contactId) {
943 startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactId),
944 requireActivity().getApplicationContext(), ContactDetailsActivity.class));
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500945 }
946
947 @Override
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500948 public void goToCallActivityWithResult(String accountId, String contactRingId, boolean audioOnly) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400949 Intent intent = new Intent(CallActivity.ACTION_CALL)
Adrien Béraud44939482019-02-13 21:42:08 -0500950 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500951 .putExtra(KEY_ACCOUNT_ID, accountId)
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500952 .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500953 .putExtra(KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400954 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
955 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500956
Andreas Traczykcee415a2019-12-03 15:45:04 -0500957 private void setupActionbar(CallContact contact) {
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400958 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500959 return;
960 }
961
Andreas Traczykcee415a2019-12-03 15:45:04 -0500962 ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar();
963 if (actionBar == null) {
964 return;
965 }
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500966
Andreas Traczykcee415a2019-12-03 15:45:04 -0500967 Context context = actionBar.getThemedContext();
968 String displayName = contact.getDisplayName();
969 String identity = contact.getRingUsername();
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500970
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400971 Activity activity = getActivity();
972 if (activity instanceof HomeActivity) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500973 Toolbar toolbar = getActivity().findViewById(R.id.main_toolbar);
974 TextView title = toolbar.findViewById(R.id.contact_title);
975 TextView subtitle = toolbar.findViewById(R.id.contact_subtitle);
976 ImageView logo = toolbar.findViewById(R.id.contact_image);
977
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400978 if (!((HomeActivity) activity).isConversationSelected()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500979 title.setText("");
980 subtitle.setText("");
981 logo.setImageDrawable(null);
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500982 return;
983 }
984
985 logo.setVisibility(View.VISIBLE);
986 title.setText(displayName);
987 title.setTextSize(15);
988 title.setTypeface(null, Typeface.NORMAL);
989
990 if (identity != null && !identity.equals(displayName)) {
991 subtitle.setText(identity);
992
993 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
994 params.addRule(RelativeLayout.ALIGN_TOP, R.id.contact_image);
995 title.setLayoutParams(params);
996 } else {
997 subtitle.setText("");
998
999 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
1000 params.removeRule(RelativeLayout.ALIGN_TOP);
1001 params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
1002 title.setLayoutParams(params);
1003 }
1004
1005 logo.setImageDrawable(mConversationAvatar);
1006 } else {
1007 if (identity != null && !identity.equals(displayName)) {
1008 actionBar.setSubtitle(identity);
1009 }
1010 actionBar.setTitle(displayName);
1011 int targetSize = (int) (AvatarFactory.SIZE_AB * context.getResources().getDisplayMetrics().density);
1012 mConversationAvatar.setInSize(targetSize);
1013 actionBar.setLogo(null);
1014 actionBar.setLogo(mConversationAvatar);
Andreas Traczykcee415a2019-12-03 15:45:04 -05001015 }
Andreas Traczykcee415a2019-12-03 15:45:04 -05001016 }
1017
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001018 public void blockContactRequest() {
1019 presenter.onBlockIncomingContactRequest();
1020 }
1021
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001022 public void refuseContactRequest() {
1023 presenter.onRefuseIncomingContactRequest();
1024 }
1025
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001026 public void acceptContactRequest() {
1027 presenter.onAcceptIncomingContactRequest();
1028 }
1029
Adrien Béraudace37a22018-06-22 14:58:36 -04001030 public void addContact() {
1031 presenter.onAddContact();
1032 }
1033
1034 @Override
Adrien Béraud5477ce82020-02-24 11:13:54 -05001035 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001036 super.onPrepareOptionsMenu(menu);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001037 boolean visible = binding.cvMessageInput.getVisibility() == View.VISIBLE;
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001038 if (mAudioCallBtn != null)
1039 mAudioCallBtn.setVisible(visible);
1040 if (mVideoCallBtn != null)
1041 mVideoCallBtn.setVisible(visible);
1042 }
1043
1044 @Override
Adrien Béraudace37a22018-06-22 14:58:36 -04001045 public void switchToUnknownView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001046 binding.cvMessageInput.setVisibility(View.GONE);
1047 binding.unknownContactPrompt.setVisibility(View.VISIBLE);
1048 binding.trustRequestPrompt.setVisibility(View.GONE);
1049 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted), contactDisplayName));
1050 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001051 currentBottomView = binding.unknownContactPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001052 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001053 updateListPadding();
Adrien Béraudace37a22018-06-22 14:58:36 -04001054 }
1055
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001056 @Override
1057 public void switchToIncomingTrustRequestView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001058 binding.cvMessageInput.setVisibility(View.GONE);
1059 binding.unknownContactPrompt.setVisibility(View.GONE);
1060 binding.trustRequestPrompt.setVisibility(View.VISIBLE);
1061 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted_yet), contactDisplayName));
1062 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001063 currentBottomView = binding.trustRequestPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001064 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001065 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001066 }
1067
1068 @Override
1069 public void switchToConversationView() {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001070 binding.cvMessageInput.setVisibility(View.VISIBLE);
1071 binding.unknownContactPrompt.setVisibility(View.GONE);
1072 binding.trustRequestPrompt.setVisibility(View.GONE);
1073 binding.trustRequestMessageLayout.setVisibility(View.GONE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001074 currentBottomView = binding.cvMessageInput;
Adrien Béraud44939482019-02-13 21:42:08 -05001075 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001076 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001077 }
1078
1079 @Override
1080 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001081 presenter.clickOnGoingPane();
1082 }
1083
1084 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001085 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001086 presenter.clickOnGoingPane();
1087 }
1088
1089 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001090 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001091 presenter.clickOnGoingPane();
1092 }
Pierre Duchemin17542a72018-02-14 16:38:36 -05001093
1094 private void setLoading(boolean isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001095 if (binding == null)
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001096 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -05001097 if (isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001098 binding.btnTakePicture.setVisibility(View.GONE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001099 binding.pbDataTransfer.setVisibility(View.VISIBLE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001100 } else {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001101 binding.btnTakePicture.setVisibility(View.VISIBLE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001102 binding.pbDataTransfer.setVisibility(View.GONE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001103 }
1104 }
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -04001105
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001106 public void handleShareIntent(Intent intent) {
Adrien Béraud5477ce82020-02-24 11:13:54 -05001107 Log.w(TAG, "handleShareIntent " + intent);
1108
1109 String action = intent.getAction();
1110 if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
1111 String type = intent.getType();
1112 if (type == null) {
1113 Log.w(TAG, "Can't share with no type");
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001114 return;
Adrien Béraud5477ce82020-02-24 11:13:54 -05001115 }
1116 if (type.startsWith("text/plain")) {
1117 binding.msgInputTxt.setText(intent.getStringExtra(Intent.EXTRA_TEXT));
1118 } else {
1119 android.net.Uri uri = intent.getData();
1120 ClipData clip = intent.getClipData();
1121 if (uri == null && clip != null && clip.getItemCount() > 0)
1122 uri = clip.getItemAt(0).getUri();
1123 if (uri == null)
1124 return;
1125 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri).flatMapCompletable(this::sendFile));
1126 }
1127 } else if (Intent.ACTION_VIEW.equals(action)) {
1128 ConversationPath path = ConversationPath.fromIntent(intent);
1129 if (path != null && intent.getBooleanExtra(EXTRA_SHOW_MAP, false)) {
1130 shareLocation();
1131 }
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001132 }
1133 }
amine younes7c56f312019-06-10 11:34:25 -04001134
1135 /**
1136 * Creates an intent using Android Storage Access Framework
1137 * This intent is then received by applications that can handle it like
1138 * Downloads or Google drive
1139 * @param file DataTransfer of the file that is going to be stored
1140 * @param currentFileAbsolutePath absolute path of the file we want to save
1141 */
1142 public void startSaveFile(DataTransfer file, String currentFileAbsolutePath){
1143 //Get the current file absolute path and store it
1144 mCurrentFileAbsolutePath = currentFileAbsolutePath;
1145
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001146 try {
1147 //Use Android Storage File Access to download the file
1148 Intent downloadFileIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
1149 downloadFileIntent.setType(AndroidFileUtils.getMimeTypeFromExtension(file.getExtension()));
1150 downloadFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
1151 downloadFileIntent.putExtra(Intent.EXTRA_TITLE,file.getDisplayName());
amine younes7c56f312019-06-10 11:34:25 -04001152
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001153 startActivityForResult(downloadFileIntent, ConversationFragment.REQUEST_CODE_SAVE_FILE);
1154 } catch (Exception e) {
1155 Log.i(TAG, "No app detected for saving files.");
1156 File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
1157 if (!directory.exists()) {
1158 directory.mkdirs();
1159 }
1160 writeToFile(android.net.Uri.fromFile(new File(directory, file.getDisplayName())));
1161 }
amine younes7c56f312019-06-10 11:34:25 -04001162 }
1163
Amirhosseine0846c52020-03-12 15:34:35 -04001164 @Override
1165 public void displayNetworkErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001166 if (binding != null) {
1167 binding.errorMsgPane.setVisibility(View.VISIBLE);
Adrien Béraudc2790922020-04-28 17:34:03 -04001168 binding.errorMsgPane.setOnClickListener(null);
1169 binding.errorMsgPane.setText(R.string.error_no_network);
Amirhosseine0846c52020-03-12 15:34:35 -04001170 }
1171 }
1172
1173 @Override
1174 public void hideErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001175 if (binding != null) {
1176 binding.errorMsgPane.setVisibility(View.GONE);
Amirhosseine0846c52020-03-12 15:34:35 -04001177 }
Amirhosseine0846c52020-03-12 15:34:35 -04001178 }
1179
Adrien Béraude32ab742018-08-25 21:15:08 -04001180}