blob: de0b4cc08b6776279f7bb3d49119e018494dadd8 [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;
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
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400584 public void onActivityResult(int requestCode, int resultCode, @Nullable Intent resultData) {
Adrien Béraud64538722018-03-15 17:34:00 -0400585 Log.w(TAG, "onActivityResult: " + requestCode + " " + resultCode + " " + resultData);
Adrien Béraud70dd5aa2020-12-04 15:18:47 -0500586 android.net.Uri uri = resultData == null ? null : resultData.getData();
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400587 if (requestCode == REQUEST_CODE_FILE_PICKER) {
588 if (resultCode == RESULT_OK && uri != null) {
589 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri)
590 .observeOn(AndroidSchedulers.mainThread())
591 .flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500592 }
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400593 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE
594 || requestCode == REQUEST_CODE_CAPTURE_AUDIO
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400595 || requestCode == REQUEST_CODE_CAPTURE_VIDEO)
596 {
Adrien Béraud64538722018-03-15 17:34:00 -0400597 if (resultCode != RESULT_OK) {
598 mCurrentPhoto = null;
599 return;
600 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500601 Log.w(TAG, "onActivityResult: mCurrentPhoto " + mCurrentPhoto.getAbsolutePath() + " " + mCurrentPhoto.exists() + " " + mCurrentPhoto.length());
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400602 Single<File> file = null;
Adrien Béraud64538722018-03-15 17:34:00 -0400603 if (mCurrentPhoto == null || !mCurrentPhoto.exists() || mCurrentPhoto.length() == 0) {
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400604 if (uri != null) {
605 file = AndroidFileUtils.getCacheFile(requireContext(), uri);
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400606 }
607 } else {
608 file = Single.just(mCurrentPhoto);
Adrien Béraud64538722018-03-15 17:34:00 -0400609 }
Adrien Béraud44939482019-02-13 21:42:08 -0500610 mCurrentPhoto = null;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400611 if (file == null) {
612 Toast.makeText(getActivity(), "Can't find picture", Toast.LENGTH_SHORT).show();
613 return;
614 }
615 startFileSend(file.flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500616 }
amine younes7c56f312019-06-10 11:34:25 -0400617 // File download trough SAF
Adrien Béraud39ce17a2020-10-25 02:47:23 -0400618 else if (requestCode == ConversationFragment.REQUEST_CODE_SAVE_FILE) {
619 if (resultCode == RESULT_OK && uri != null) {
620 writeToFile(uri);
amine younes7c56f312019-06-10 11:34:25 -0400621 }
622 }
Pierre Duchemin17542a72018-02-14 16:38:36 -0500623 }
624
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -0400625 private void writeToFile(android.net.Uri data) {
626 File input = new File(mCurrentFileAbsolutePath);
627 if (requireContext().getContentResolver() != null)
628 mCompositeDisposable.add(AndroidFileUtils.copyFileToUri(requireContext().getContentResolver(), input, data).
629 observeOn(AndroidSchedulers.mainThread()).
630 subscribe(() -> Toast.makeText(getContext(), R.string.file_saved_successfully, Toast.LENGTH_SHORT).show(),
631 error -> Toast.makeText(getContext(), R.string.generic_error, Toast.LENGTH_SHORT).show()));
632 }
633
Pierre Duchemin17542a72018-02-14 16:38:36 -0500634 @Override
Adrien Béraud4f542f92019-01-03 12:17:53 -0500635 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500636 for (int i = 0, n = permissions.length; i < n; i++) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400637 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500638 switch (permissions[i]) {
639 case Manifest.permission.CAMERA:
Rayan Osseiran38206c62019-05-15 14:49:03 -0400640 presenter.cameraPermissionChanged(granted);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500641 if (granted) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400642 if (requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
643 sendVideoMessage();
644 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE) {
645 takePicture();
646 }
647 }
648 return;
649 case Manifest.permission.RECORD_AUDIO:
650 if (granted) {
651 if (requestCode == REQUEST_CODE_CAPTURE_AUDIO) {
652 sendAudioMessage();
653 }
Adrien Béraud4f542f92019-01-03 12:17:53 -0500654 }
655 return;
656 default:
657 break;
658 }
659 }
660 }
661
662 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400663 public void addElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400664 mAdapter.add(element);
665 scrollToEnd();
666 }
Adrien Béraud3cbc7fa2018-07-18 18:36:21 -0400667
Adrien Béraudace37a22018-06-22 14:58:36 -0400668 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400669 public void updateElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400670 mAdapter.update(element);
671 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500672
Adrien Béraudace37a22018-06-22 14:58:36 -0400673 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400674 public void removeElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400675 mAdapter.remove(element);
Adrien Béraud21533292018-03-22 14:11:35 -0400676 }
677
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400678 @Override
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500679 public void setComposingStatus(Account.ComposingStatus composingStatus) {
680 mAdapter.setComposingStatus(composingStatus);
681 if (composingStatus == Account.ComposingStatus.Active)
682 scrollToEnd();
683 }
684
685 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400686 public void setLastDisplayed(Interaction interaction) {
687 mAdapter.setLastDisplayed(interaction);
688 }
689
690 @Override
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400691 public void shareFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500692 Context c = getContext();
693 if (c == null)
694 return;
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400695 android.net.Uri fileUri = null;
696 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500697 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400698 } catch (IllegalArgumentException e) {
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500699 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400700 }
701 if (fileUri != null) {
702 Intent sendIntent = new Intent();
703 sendIntent.setAction(Intent.ACTION_SEND);
704 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500705 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400706 sendIntent.setDataAndType(fileUri, type);
707 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
708 startActivity(Intent.createChooser(sendIntent, null));
709 }
710 }
711
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500712 @Override
713 public void openFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500714 Context c = getContext();
715 if (c == null)
716 return;
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500717 android.net.Uri fileUri = null;
718 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500719 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500720 } catch (IllegalArgumentException e) {
721 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
722 }
723 if (fileUri != null) {
724 Intent sendIntent = new Intent();
725 sendIntent.setAction(Intent.ACTION_VIEW);
726 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500727 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500728 sendIntent.setDataAndType(fileUri, type);
729 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
730 //startActivity(Intent.createChooser(sendIntent, null));
Rayan Osseirane4450272019-06-03 14:17:19 -0400731 try {
732 startActivity(sendIntent);
733 } catch (ActivityNotFoundException e) {
734 Snackbar.make(getView(), R.string.conversation_open_file_error, Snackbar.LENGTH_LONG).show();
735 Log.e("File Loader", "File of unknown type, could not open: " + path.getName());
736 }
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500737 }
738 }
739
Adrien Béraud44939482019-02-13 21:42:08 -0500740 boolean actionSendMsgText(int actionId) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500741 switch (actionId) {
742 case EditorInfo.IME_ACTION_SEND:
Adrien Béraudace37a22018-06-22 14:58:36 -0400743 sendMessageText();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500744 return true;
745 }
746 return false;
747 }
748
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500749 public void onClick() {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400750 presenter.clickOnGoingPane();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500751 }
752
753 @Override
754 public void onPause() {
755 super.onPause();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400756 presenter.pause();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500757 }
758
759 @Override
760 public void onResume() {
761 super.onResume();
Amirhossein68916382020-07-19 11:23:59 -0400762 presenter.resume(mIsBubble);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500763 }
764
765 @Override
Andreas Traczykcee415a2019-12-03 15:45:04 -0500766 public void onDestroy() {
767 mCompositeDisposable.dispose();
768 super.onDestroy();
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400769 }
770
771 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400772 public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
773 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500774 return;
775 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400776 inflater.inflate(R.menu.conversation_actions, menu);
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400777 mAudioCallBtn = menu.findItem(R.id.conv_action_audiocall);
778 mVideoCallBtn = menu.findItem(R.id.conv_action_videocall);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500779 }
780
781 @Override
782 public boolean onOptionsItemSelected(MenuItem item) {
783 switch (item.getItemId()) {
784 case android.R.id.home:
785 startActivity(new Intent(getActivity(), HomeActivity.class));
786 return true;
787 case R.id.conv_action_audiocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500788 presenter.goToCall(true);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500789 return true;
790 case R.id.conv_action_videocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500791 presenter.goToCall(false);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500792 return true;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500793 case R.id.conv_contact_details:
794 presenter.openContact();
Aline Bonnet54cf69b2017-03-28 12:03:45 -0400795 return true;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500796 default:
797 return super.onOptionsItemSelected(item);
798 }
799 }
800
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500801 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400802 protected void initPresenter(ConversationPresenter presenter) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400803 ConversationPath path = ConversationPath.fromBundle(getArguments());
Amirhossein68916382020-07-19 11:23:59 -0400804 mIsBubble = getArguments().getBoolean(NotificationServiceImpl.EXTRA_BUBBLE);
Adrien Béraudbba76582020-05-15 19:18:23 -0400805 if (path == null)
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500806 return;
Adrien Béraud2d8a8a82020-10-15 11:05:38 -0400807
808 Uri contactUri = path.getConversationUri();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500809 mAdapter = new ConversationAdapter(this, presenter);
Adrien Béraudbba76582020-05-15 19:18:23 -0400810 presenter.init(contactUri, path.getAccountId());
Adrien Béraud56c34132018-11-29 13:32:00 -0500811 try {
Adrien Béraudbba76582020-05-15 19:18:23 -0400812 mPreferences = requireActivity().getSharedPreferences(path.getAccountId() + "_" + contactUri.getRawRingId(), Context.MODE_PRIVATE);
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500813 mPreferences.registerOnSharedPreferenceChangeListener(this);
814 presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
Adrien Béraud56c34132018-11-29 13:32:00 -0500815 } catch (Exception e) {
816 Log.e(TAG, "Can't load conversation preferences");
817 }
Adrien Béraud5477ce82020-02-24 11:13:54 -0500818
819 if (locationServiceConnection == null) {
820 locationServiceConnection = new ServiceConnection() {
821 @Override
822 public void onServiceConnected(ComponentName name, IBinder service) {
823 Log.w(TAG, "onServiceConnected");
824 LocationSharingService.LocalBinder binder = (LocationSharingService.LocalBinder) service;
825 LocationSharingService locationService = binder.getService();
826 ConversationPath path = new ConversationPath(presenter.getPath());
827 if (locationService.isSharing(path)) {
Adrien Béraudbba76582020-05-15 19:18:23 -0400828 showMap(path.getAccountId(), contactUri.getUri(), false);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500829 }
830 try {
831 requireContext().unbindService(locationServiceConnection);
832 } catch (Exception e) {
833 Log.w(TAG, "Error unbinding service", e);
834 }
835 }
836
837 @Override
838 public void onServiceDisconnected(ComponentName name) {
839 Log.w(TAG, "onServiceDisconnected");
840 locationServiceConnection = null;
841 }
842 };
843
844 Log.w(TAG, "bindService");
845 requireContext().bindService(new Intent(requireContext(), LocationSharingService.class), locationServiceConnection, 0);
846 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500847 }
848
849 @Override
850 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
851 switch (key) {
852 case KEY_PREFERENCE_CONVERSATION_COLOR:
853 presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
854 break;
855 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400856 }
857
858 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400859 public void displayContact(final CallContact contact) {
Andreas Traczykcee415a2019-12-03 15:45:04 -0500860 mCompositeDisposable.clear();
861 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact)
862 .doOnSuccess(d -> {
863 mConversationAvatar = (AvatarDrawable) d;
864 mParticipantAvatars.put(contact.getPrimaryNumber(),
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500865 new AvatarDrawable((AvatarDrawable) d));
Andreas Traczykcee415a2019-12-03 15:45:04 -0500866 })
867 .flatMapObservable(d -> contact.getUpdatesSubject())
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400868 .observeOn(AndroidSchedulers.mainThread())
Andreas Traczykcee415a2019-12-03 15:45:04 -0500869 .subscribe(c -> {
870 mConversationAvatar.update(c);
871 String uri = contact.getPrimaryNumber();
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400872 AvatarDrawable ad = mParticipantAvatars.get(uri);
873 if (ad != null)
874 ad.update(c);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500875 setupActionbar(contact);
876 mAdapter.setPhoto();
877 }));
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400878 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact, false)
879 .doOnSuccess(d -> mSmallParticipantAvatars.put(contact.getPrimaryNumber(), new AvatarDrawable((AvatarDrawable) d)))
880 .flatMapObservable(d -> contact.getUpdatesSubject())
881 .subscribe(c -> {
882 synchronized (mSmallParticipantAvatars) {
883 String uri = contact.getPrimaryNumber();
884 AvatarDrawable ad = mSmallParticipantAvatars.get(uri);
885 if (ad != null)
886 ad.update(c);
887 }
888 }));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400889 }
890
891 @Override
892 public void displayOnGoingCallPane(final boolean display) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500893 binding.ongoingcallPane.setVisibility(display ? View.VISIBLE : View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400894 }
895
896 @Override
897 public void displayNumberSpinner(final Conversation conversation, final Uri number) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500898 binding.numberSelector.setVisibility(View.VISIBLE);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500899 binding.numberSelector.setAdapter(new NumberAdapter(getActivity(),
900 conversation.getContact(), false));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500901 binding.numberSelector.setSelection(getIndex(binding.numberSelector, number));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400902 }
903
904 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400905 public void hideNumberSpinner() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500906 binding.numberSelector.setVisibility(View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400907 }
908
909 @Override
910 public void clearMsgEdit() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500911 binding.msgInputTxt.setText("");
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400912 }
913
914 @Override
915 public void goToHome() {
916 if (getActivity() instanceof ConversationActivity) {
917 getActivity().finish();
Aline Bonneteb5f7ff2017-01-17 11:09:17 -0500918 }
919 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400920
921 @Override
922 public void goToAddContact(CallContact callContact) {
923 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact), REQ_ADD_CONTACT);
924 }
925
926 @Override
927 public void goToCallActivity(String conferenceId) {
928 startActivity(new Intent(Intent.ACTION_VIEW)
Adrien Béraud44939482019-02-13 21:42:08 -0500929 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400930 .putExtra(NotificationService.KEY_CALL_ID, conferenceId));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400931 }
932
933 @Override
Adrien Béraud770ef472020-10-19 16:47:14 -0400934 public void goToContactActivity(String accountId, String contactId) {
935 startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactId),
936 requireActivity().getApplicationContext(), ContactDetailsActivity.class));
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500937 }
938
939 @Override
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500940 public void goToCallActivityWithResult(String accountId, String contactRingId, boolean audioOnly) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400941 Intent intent = new Intent(CallActivity.ACTION_CALL)
Adrien Béraud44939482019-02-13 21:42:08 -0500942 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500943 .putExtra(KEY_ACCOUNT_ID, accountId)
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500944 .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500945 .putExtra(KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400946 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
947 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500948
Andreas Traczykcee415a2019-12-03 15:45:04 -0500949 private void setupActionbar(CallContact contact) {
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400950 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500951 return;
952 }
953
Andreas Traczykcee415a2019-12-03 15:45:04 -0500954 ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar();
955 if (actionBar == null) {
956 return;
957 }
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500958
Andreas Traczykcee415a2019-12-03 15:45:04 -0500959 Context context = actionBar.getThemedContext();
960 String displayName = contact.getDisplayName();
961 String identity = contact.getRingUsername();
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500962
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400963 Activity activity = getActivity();
964 if (activity instanceof HomeActivity) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500965 Toolbar toolbar = getActivity().findViewById(R.id.main_toolbar);
966 TextView title = toolbar.findViewById(R.id.contact_title);
967 TextView subtitle = toolbar.findViewById(R.id.contact_subtitle);
968 ImageView logo = toolbar.findViewById(R.id.contact_image);
969
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400970 if (!((HomeActivity) activity).isConversationSelected()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500971 title.setText("");
972 subtitle.setText("");
973 logo.setImageDrawable(null);
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500974 return;
975 }
976
977 logo.setVisibility(View.VISIBLE);
978 title.setText(displayName);
979 title.setTextSize(15);
980 title.setTypeface(null, Typeface.NORMAL);
981
982 if (identity != null && !identity.equals(displayName)) {
983 subtitle.setText(identity);
984
985 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
986 params.addRule(RelativeLayout.ALIGN_TOP, R.id.contact_image);
987 title.setLayoutParams(params);
988 } else {
989 subtitle.setText("");
990
991 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
992 params.removeRule(RelativeLayout.ALIGN_TOP);
993 params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
994 title.setLayoutParams(params);
995 }
996
997 logo.setImageDrawable(mConversationAvatar);
998 } else {
999 if (identity != null && !identity.equals(displayName)) {
1000 actionBar.setSubtitle(identity);
1001 }
1002 actionBar.setTitle(displayName);
1003 int targetSize = (int) (AvatarFactory.SIZE_AB * context.getResources().getDisplayMetrics().density);
1004 mConversationAvatar.setInSize(targetSize);
1005 actionBar.setLogo(null);
1006 actionBar.setLogo(mConversationAvatar);
Andreas Traczykcee415a2019-12-03 15:45:04 -05001007 }
Andreas Traczykcee415a2019-12-03 15:45:04 -05001008 }
1009
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001010 public void blockContactRequest() {
1011 presenter.onBlockIncomingContactRequest();
1012 }
1013
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001014 public void refuseContactRequest() {
1015 presenter.onRefuseIncomingContactRequest();
1016 }
1017
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001018 public void acceptContactRequest() {
1019 presenter.onAcceptIncomingContactRequest();
1020 }
1021
Adrien Béraudace37a22018-06-22 14:58:36 -04001022 public void addContact() {
1023 presenter.onAddContact();
1024 }
1025
1026 @Override
Adrien Béraud5477ce82020-02-24 11:13:54 -05001027 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001028 super.onPrepareOptionsMenu(menu);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001029 boolean visible = binding.cvMessageInput.getVisibility() == View.VISIBLE;
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001030 if (mAudioCallBtn != null)
1031 mAudioCallBtn.setVisible(visible);
1032 if (mVideoCallBtn != null)
1033 mVideoCallBtn.setVisible(visible);
1034 }
1035
1036 @Override
Adrien Béraudace37a22018-06-22 14:58:36 -04001037 public void switchToUnknownView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001038 binding.cvMessageInput.setVisibility(View.GONE);
1039 binding.unknownContactPrompt.setVisibility(View.VISIBLE);
1040 binding.trustRequestPrompt.setVisibility(View.GONE);
1041 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted), contactDisplayName));
1042 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001043 currentBottomView = binding.unknownContactPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001044 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001045 updateListPadding();
Adrien Béraudace37a22018-06-22 14:58:36 -04001046 }
1047
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001048 @Override
1049 public void switchToIncomingTrustRequestView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001050 binding.cvMessageInput.setVisibility(View.GONE);
1051 binding.unknownContactPrompt.setVisibility(View.GONE);
1052 binding.trustRequestPrompt.setVisibility(View.VISIBLE);
1053 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted_yet), contactDisplayName));
1054 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001055 currentBottomView = binding.trustRequestPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001056 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001057 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001058 }
1059
1060 @Override
1061 public void switchToConversationView() {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001062 binding.cvMessageInput.setVisibility(View.VISIBLE);
1063 binding.unknownContactPrompt.setVisibility(View.GONE);
1064 binding.trustRequestPrompt.setVisibility(View.GONE);
1065 binding.trustRequestMessageLayout.setVisibility(View.GONE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001066 currentBottomView = binding.cvMessageInput;
Adrien Béraud44939482019-02-13 21:42:08 -05001067 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001068 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001069 }
1070
1071 @Override
1072 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001073 presenter.clickOnGoingPane();
1074 }
1075
1076 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001077 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001078 presenter.clickOnGoingPane();
1079 }
1080
1081 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001082 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001083 presenter.clickOnGoingPane();
1084 }
Pierre Duchemin17542a72018-02-14 16:38:36 -05001085
1086 private void setLoading(boolean isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001087 if (binding == null)
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001088 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -05001089 if (isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001090 binding.btnTakePicture.setVisibility(View.GONE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001091 binding.pbDataTransfer.setVisibility(View.VISIBLE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001092 } else {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001093 binding.btnTakePicture.setVisibility(View.VISIBLE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001094 binding.pbDataTransfer.setVisibility(View.GONE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001095 }
1096 }
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -04001097
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001098 public void handleShareIntent(Intent intent) {
Adrien Béraud5477ce82020-02-24 11:13:54 -05001099 Log.w(TAG, "handleShareIntent " + intent);
1100
1101 String action = intent.getAction();
1102 if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
1103 String type = intent.getType();
1104 if (type == null) {
1105 Log.w(TAG, "Can't share with no type");
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001106 return;
Adrien Béraud5477ce82020-02-24 11:13:54 -05001107 }
1108 if (type.startsWith("text/plain")) {
1109 binding.msgInputTxt.setText(intent.getStringExtra(Intent.EXTRA_TEXT));
1110 } else {
1111 android.net.Uri uri = intent.getData();
1112 ClipData clip = intent.getClipData();
1113 if (uri == null && clip != null && clip.getItemCount() > 0)
1114 uri = clip.getItemAt(0).getUri();
1115 if (uri == null)
1116 return;
1117 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri).flatMapCompletable(this::sendFile));
1118 }
1119 } else if (Intent.ACTION_VIEW.equals(action)) {
1120 ConversationPath path = ConversationPath.fromIntent(intent);
1121 if (path != null && intent.getBooleanExtra(EXTRA_SHOW_MAP, false)) {
1122 shareLocation();
1123 }
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001124 }
1125 }
amine younes7c56f312019-06-10 11:34:25 -04001126
1127 /**
1128 * Creates an intent using Android Storage Access Framework
1129 * This intent is then received by applications that can handle it like
1130 * Downloads or Google drive
1131 * @param file DataTransfer of the file that is going to be stored
1132 * @param currentFileAbsolutePath absolute path of the file we want to save
1133 */
1134 public void startSaveFile(DataTransfer file, String currentFileAbsolutePath){
1135 //Get the current file absolute path and store it
1136 mCurrentFileAbsolutePath = currentFileAbsolutePath;
1137
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001138 try {
1139 //Use Android Storage File Access to download the file
1140 Intent downloadFileIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
1141 downloadFileIntent.setType(AndroidFileUtils.getMimeTypeFromExtension(file.getExtension()));
1142 downloadFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
1143 downloadFileIntent.putExtra(Intent.EXTRA_TITLE,file.getDisplayName());
amine younes7c56f312019-06-10 11:34:25 -04001144
Adrien Béraudb9a1cfe2020-08-02 09:06:26 -04001145 startActivityForResult(downloadFileIntent, ConversationFragment.REQUEST_CODE_SAVE_FILE);
1146 } catch (Exception e) {
1147 Log.i(TAG, "No app detected for saving files.");
1148 File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
1149 if (!directory.exists()) {
1150 directory.mkdirs();
1151 }
1152 writeToFile(android.net.Uri.fromFile(new File(directory, file.getDisplayName())));
1153 }
amine younes7c56f312019-06-10 11:34:25 -04001154 }
1155
Amirhosseine0846c52020-03-12 15:34:35 -04001156 @Override
1157 public void displayNetworkErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001158 if (binding != null) {
1159 binding.errorMsgPane.setVisibility(View.VISIBLE);
Adrien Béraudc2790922020-04-28 17:34:03 -04001160 binding.errorMsgPane.setOnClickListener(null);
1161 binding.errorMsgPane.setText(R.string.error_no_network);
Amirhosseine0846c52020-03-12 15:34:35 -04001162 }
1163 }
1164
1165 @Override
1166 public void hideErrorPanel() {
Adrien Béraudc35f7f42020-04-15 15:29:29 -04001167 if (binding != null) {
1168 binding.errorMsgPane.setVisibility(View.GONE);
Amirhosseine0846c52020-03-12 15:34:35 -04001169 }
Amirhosseine0846c52020-03-12 15:34:35 -04001170 }
1171
Adrien Béraude32ab742018-08-25 21:15:08 -04001172}