blob: 07d756dbf0592fa25886096e900ea9ac3546af13 [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éraud5477ce82020-02-24 11:13:54 -050038import android.os.IBinder;
Adrien Béraud64538722018-03-15 17:34:00 -040039import android.provider.MediaStore;
Adrien Béraud3a875a02018-07-18 17:54:17 -040040import android.text.Editable;
Adrien Béraud58bd92b2018-08-23 10:54:25 -040041import android.text.TextUtils;
Adrien Béraud3a875a02018-07-18 17:54:17 -040042import android.text.TextWatcher;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050043import android.util.Log;
Adrien Béraudb28c4912018-12-02 22:58:52 -050044import android.view.LayoutInflater;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050045import android.view.Menu;
46import android.view.MenuInflater;
47import android.view.MenuItem;
48import android.view.View;
49import android.view.ViewGroup;
50import android.view.inputmethod.EditorInfo;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050051import android.widget.ImageView;
52import android.widget.RelativeLayout;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050053import android.widget.Spinner;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050054import android.widget.TextView;
Pierre Duchemine0c3a492018-02-01 16:22:45 -050055import android.widget.Toast;
56
Rayan Osseirane4450272019-06-03 14:17:19 -040057import com.google.android.material.snackbar.Snackbar;
58
amine younes7c56f312019-06-10 11:34:25 -040059import androidx.annotation.NonNull;
60import androidx.annotation.Nullable;
61import androidx.appcompat.app.ActionBar;
62import androidx.appcompat.app.AppCompatActivity;
Adrien Béraud898c2bf2019-09-26 14:49:33 -040063import androidx.appcompat.view.menu.MenuBuilder;
64import androidx.appcompat.view.menu.MenuPopupHelper;
65import androidx.appcompat.widget.PopupMenu;
Adrien Béraudb96a7d92020-02-24 11:55:05 -050066import androidx.appcompat.widget.Toolbar;
Adrien Béraud91f88742019-09-09 00:46:46 -040067import androidx.core.view.ViewCompat;
Adrien Béraud5477ce82020-02-24 11:13:54 -050068import androidx.fragment.app.Fragment;
69import androidx.fragment.app.FragmentManager;
amine younes7c56f312019-06-10 11:34:25 -040070import androidx.recyclerview.widget.DefaultItemAnimator;
71
Pierre Duchemine0c3a492018-02-01 16:22:45 -050072import java.io.File;
73import java.io.IOException;
Andreas Traczykcee415a2019-12-03 15:45:04 -050074import java.util.HashMap;
Adrien Béraudace37a22018-06-22 14:58:36 -040075import java.util.List;
Andreas Traczykcee415a2019-12-03 15:45:04 -050076import java.util.Map;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050077
Adrien Béraud5b47cb52018-07-06 16:24:14 -040078import cx.ring.BuildConfig;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050079import cx.ring.R;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050080import cx.ring.adapters.ConversationAdapter;
81import cx.ring.adapters.NumberAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040082import cx.ring.application.JamiApplication;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050083import cx.ring.client.CallActivity;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -050084import cx.ring.client.ContactDetailsActivity;
Aline Bonnet830c4c62016-12-27 14:02:02 -050085import cx.ring.client.ConversationActivity;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050086import cx.ring.client.HomeActivity;
Adrien Béraud78ae7b92018-08-25 19:04:17 -040087import cx.ring.contacts.AvatarFactory;
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -040088import cx.ring.conversation.ConversationPresenter;
89import cx.ring.conversation.ConversationView;
Adrien Béraudb28c4912018-12-02 22:58:52 -050090import cx.ring.databinding.FragConversationBinding;
Adrien Béraud171ba362018-12-14 21:35:40 -050091import cx.ring.interfaces.Colorable;
Adrien Béraudfd458ea2020-02-28 13:40:18 -050092import cx.ring.model.Account;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050093import cx.ring.model.CallContact;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050094import cx.ring.model.Conversation;
Rayan Osseiran6f415662019-10-25 14:23:25 -040095import cx.ring.model.Interaction;
Adrien Béraud21533292018-03-22 14:11:35 -040096import cx.ring.model.DataTransfer;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050097import cx.ring.model.Phone;
Adrien Bérauda0226ff2019-11-21 15:24:42 -050098import cx.ring.model.Error;
Aline Bonnet9c6defe2016-12-21 13:21:02 -050099import cx.ring.model.Uri;
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500100import cx.ring.mvp.BaseSupportFragment;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500101import cx.ring.services.LocationSharingService;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400102import cx.ring.services.NotificationService;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500103import cx.ring.utils.ActionHelper;
Adrien Béraud64538722018-03-15 17:34:00 -0400104import cx.ring.utils.AndroidFileUtils;
Adrien Béraud64538722018-03-15 17:34:00 -0400105import cx.ring.utils.ContentUriHandler;
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500106import cx.ring.utils.DeviceUtils;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500107import cx.ring.utils.ConversationPath;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500108import cx.ring.utils.MediaButtonsHelper;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500109import cx.ring.views.AvatarDrawable;
Adrien Béraud44939482019-02-13 21:42:08 -0500110import io.reactivex.Completable;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400111import io.reactivex.Single;
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400112import io.reactivex.android.schedulers.AndroidSchedulers;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500113import io.reactivex.disposables.CompositeDisposable;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500114
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500115import static android.app.Activity.RESULT_OK;
116
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500117public class ConversationFragment extends BaseSupportFragment<ConversationPresenter> implements
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500118 MediaButtonsHelper.MediaButtonsHelperCallback,
Rayan Osseirane634a562019-05-29 13:44:55 -0400119 ConversationView, SharedPreferences.OnSharedPreferenceChangeListener {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500120 private static final String TAG = ConversationFragment.class.getSimpleName();
Adrien Béraud64538722018-03-15 17:34:00 -0400121
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400122 public static final int REQ_ADD_CONTACT = 42;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400123
Adrien Béraud6ac63632018-12-09 00:11:21 -0500124 public static final String KEY_CONTACT_RING_ID = BuildConfig.APPLICATION_ID + ".CONTACT_RING_ID";
125 public static final String KEY_ACCOUNT_ID = BuildConfig.APPLICATION_ID + ".ACCOUNT_ID";
Adrien Béraud3a875a02018-07-18 17:54:17 -0400126 public static final String KEY_PREFERENCE_PENDING_MESSAGE = "pendingMessage";
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500127 public static final String KEY_PREFERENCE_CONVERSATION_COLOR = "color";
Adrien Béraud5477ce82020-02-24 11:13:54 -0500128 public static final String EXTRA_SHOW_MAP = "showMap";
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500129
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500130 private static final int REQUEST_CODE_FILE_PICKER = 1000;
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500131 private static final int REQUEST_PERMISSION_CAMERA = 1001;
Adrien Béraud64538722018-03-15 17:34:00 -0400132 private static final int REQUEST_CODE_TAKE_PICTURE = 1002;
amine younes7c56f312019-06-10 11:34:25 -0400133 private static final int REQUEST_CODE_SAVE_FILE = 1003;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400134 private static final int REQUEST_CODE_CAPTURE_AUDIO = 1004;
135 private static final int REQUEST_CODE_CAPTURE_VIDEO = 1005;
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500136
Adrien Béraud5477ce82020-02-24 11:13:54 -0500137 private ServiceConnection locationServiceConnection = null;
138
Adrien Béraudb28c4912018-12-02 22:58:52 -0500139 private FragConversationBinding binding;
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400140 private MenuItem mAudioCallBtn = null;
141 private MenuItem mVideoCallBtn = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500142
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400143 private View currentBottomView = null;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500144 private ConversationAdapter mAdapter = null;
Adrien Béraud772e2162019-02-12 16:00:21 -0500145 private int marginPx;
Adrien Béraud91f88742019-09-09 00:46:46 -0400146 private int marginPxTotal;
Adrien Béraud772e2162019-02-12 16:00:21 -0500147 private final ValueAnimator animation = new ValueAnimator();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500148
Adrien Béraud3a875a02018-07-18 17:54:17 -0400149 private SharedPreferences mPreferences;
150
Adrien Béraud64538722018-03-15 17:34:00 -0400151 private File mCurrentPhoto = null;
amine younes7c56f312019-06-10 11:34:25 -0400152 private String mCurrentFileAbsolutePath = null;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500153 private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
Adrien Béraud742d3202019-11-15 14:28:59 -0500154 private int mSelectedPosition;
Adrien Béraud64538722018-03-15 17:34:00 -0400155
Andreas Traczykcee415a2019-12-03 15:45:04 -0500156 private AvatarDrawable mConversationAvatar;
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400157 private final Map<String, AvatarDrawable> mParticipantAvatars = new HashMap<>();
158 private final Map<String, AvatarDrawable> mSmallParticipantAvatars = new HashMap<>();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500159 private int mapWidth, mapHeight;
Andreas Traczykcee415a2019-12-03 15:45:04 -0500160
161 public AvatarDrawable getConversationAvatar(String uri) {
162 return mParticipantAvatars.get(uri);
163 }
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400164 public AvatarDrawable getSmallConversationAvatar(String uri) {
165 synchronized (mSmallParticipantAvatars) {
166 return mSmallParticipantAvatars.get(uri);
167 }
168 }
Andreas Traczykcee415a2019-12-03 15:45:04 -0500169
Pierre Duchemin1fa61922018-01-18 10:09:02 -0500170 private static int getIndex(Spinner spinner, Uri myString) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500171 for (int i = 0, n = spinner.getCount(); i < n; i++)
172 if (((Phone) spinner.getItemAtPosition(i)).getNumber().equals(myString)) {
173 return i;
174 }
175 return 0;
176 }
177
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400178 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400179 public void refreshView(final List<Interaction> conversation) {
Adrien Béraud20d42212018-03-02 14:40:38 -0500180 if (conversation == null) {
181 return;
182 }
Adrien Béraudb28c4912018-12-02 22:58:52 -0500183 if (binding != null)
184 binding.pbLoading.setVisibility(View.GONE);
Adrien Béraudace37a22018-06-22 14:58:36 -0400185 if (mAdapter != null) {
186 mAdapter.updateDataset(conversation);
187 }
Rayan Osseiran6f415662019-10-25 14:23:25 -0400188 requireActivity().invalidateOptionsMenu();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500189 }
190
Aline Bonnete8e87f62016-12-26 10:54:37 -0500191 @Override
Adrien Béraud64538722018-03-15 17:34:00 -0400192 public void scrollToEnd() {
Adrien Béraudace37a22018-06-22 14:58:36 -0400193 if (mAdapter.getItemCount() > 0) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500194 binding.histList.scrollToPosition(mAdapter.getItemCount() - 1);
Adrien Béraudace37a22018-06-22 14:58:36 -0400195 }
Adrien Béraud64538722018-03-15 17:34:00 -0400196 }
197
Adrien Béraud91f88742019-09-09 00:46:46 -0400198 private static void setBottomPadding(@NonNull View view, int padding) {
199 view.setPadding(
200 view.getPaddingLeft(),
201 view.getPaddingTop(),
202 view.getPaddingRight(),
203 padding);
204 }
205
206 private void updateListPadding() {
Adrien Béraud5477ce82020-02-24 11:13:54 -0500207 if (currentBottomView != null && currentBottomView.getHeight() != 0) {
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400208 setBottomPadding(binding.histList, currentBottomView.getHeight() + marginPxTotal);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500209 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
210 params.bottomMargin = currentBottomView.getHeight() + marginPxTotal;
211 binding.mapCard.setLayoutParams(params);
212 }
Adrien Béraud91f88742019-09-09 00:46:46 -0400213 }
214
Adrien Béraudb28c4912018-12-02 22:58:52 -0500215 @Nullable
216 @Override
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500217 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Adrien Béraud7307cd52020-04-13 23:29:11 -0400218 ((JamiApplication) getActivity().getApplication()).getInjectionComponent().inject(this);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500219 Resources res = getResources();
220 marginPx = res.getDimensionPixelSize(R.dimen.conversation_message_input_margin);
221 mapWidth = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_width);
222 mapHeight = res.getDimensionPixelSize(R.dimen.location_sharing_minmap_height);
Adrien Béraud91f88742019-09-09 00:46:46 -0400223 marginPxTotal = marginPx;
Adrien Béraudfd083672019-10-31 13:52:38 -0400224
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500225 binding = FragConversationBinding.inflate(inflater, container, false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500226 binding.setPresenter(this);
Adrien Béraud91f88742019-09-09 00:46:46 -0400227
Adrien Béraudfd083672019-10-31 13:52:38 -0400228 animation.setDuration(150);
229 animation.addUpdateListener(valueAnimator -> setBottomPadding(binding.histList, (Integer)valueAnimator.getAnimatedValue()));
230
Adrien Béraud91f88742019-09-09 00:46:46 -0400231 ViewCompat.setOnApplyWindowInsetsListener(binding.histList, (v, insets) -> {
232 marginPxTotal = marginPx + insets.getSystemWindowInsetBottom();
233 updateListPadding();
234 insets.consumeSystemWindowInsets();
235 return insets;
236 });
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500237 View layout = binding.conversationLayout;
238
239 // remove action bar height for tablet layout
240 if (DeviceUtils.isTablet(getContext())) {
241 layout.setPadding(layout.getPaddingLeft(), 0, layout.getPaddingRight(), layout.getPaddingBottom());
242 }
243
244 int paddingTop = layout.getPaddingTop();
245 ViewCompat.setOnApplyWindowInsetsListener(layout, (v, insets) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400246 v.setPadding(
247 v.getPaddingLeft(),
248 paddingTop + insets.getSystemWindowInsetTop(),
249 v.getPaddingRight(),
250 v.getPaddingBottom());
251 insets.consumeSystemWindowInsets();
252 return insets;
253 });
254
Adrien Béraudfd083672019-10-31 13:52:38 -0400255 binding.ongoingcallPane.setVisibility(View.GONE);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400256 binding.msgInputTxt.setMediaListener(contentInfo -> startFileSend(AndroidFileUtils
Adrien Béraudfd083672019-10-31 13:52:38 -0400257 .getCacheFile(requireContext(), contentInfo.getContentUri())
258 .flatMapCompletable(this::sendFile)
259 .doFinally(contentInfo::releasePermission)));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500260 binding.msgInputTxt.setOnEditorActionListener((v, actionId, event) -> actionSendMsgText(actionId));
Adrien Béraud5477ce82020-02-24 11:13:54 -0500261 binding.msgInputTxt.setOnFocusChangeListener((view, hasFocus) -> {
262 if (hasFocus) {
263 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
264 if (fragment != null) {
265 ((LocationSharingFragment) fragment).hideControls();
266 }
267 }
268 });
Adrien Béraudb28c4912018-12-02 22:58:52 -0500269 binding.msgInputTxt.addTextChangedListener(new TextWatcher() {
Adrien Béraud3a875a02018-07-18 17:54:17 -0400270 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500271 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
272 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400273
274 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500275 public void onTextChanged(CharSequence s, int start, int before, int count) {
276 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400277
278 @Override
279 public void afterTextChanged(Editable s) {
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400280 String message = s.toString();
Adrien Béraude09dd012019-11-15 14:57:18 -0500281 boolean hasMessage = !TextUtils.isEmpty(message);
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500282 presenter.onComposingChanged(hasMessage);
Rayan Osseiran6f415662019-10-25 14:23:25 -0400283 if (hasMessage) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500284 binding.msgSend.setVisibility(View.VISIBLE);
285 binding.emojiSend.setVisibility(View.GONE);
Adrien Béraude09dd012019-11-15 14:57:18 -0500286 } else {
287 binding.msgSend.setVisibility(View.GONE);
288 binding.emojiSend.setVisibility(View.VISIBLE);
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400289 }
Adrien Béraud3a875a02018-07-18 17:54:17 -0400290 if (mPreferences != null) {
Rayan Osseiran6f415662019-10-25 14:23:25 -0400291 if (hasMessage)
292 mPreferences.edit().putString(KEY_PREFERENCE_PENDING_MESSAGE, message).apply();
293 else
294 mPreferences.edit().remove(KEY_PREFERENCE_PENDING_MESSAGE).apply();
Adrien Béraud3a875a02018-07-18 17:54:17 -0400295 }
296 }
297 });
Adrien Béraud9d4a81f2018-07-09 01:19:52 -0400298
Adrien Béraudfd083672019-10-31 13:52:38 -0400299 setHasOptionsMenu(true);
300 return binding.getRoot();
301 }
302
303 @Override
304 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
305 super.onViewCreated(view, savedInstanceState);
306
307 if (mPreferences != null) {
308 String pendingMessage = mPreferences.getString(KEY_PREFERENCE_PENDING_MESSAGE, null);
309 if (!TextUtils.isEmpty(pendingMessage)) {
310 binding.msgInputTxt.setText(pendingMessage);
311 binding.msgSend.setVisibility(View.VISIBLE);
312 binding.emojiSend.setVisibility(View.GONE);
313 }
314 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500315
316 binding.msgInputTxt.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
Adrien Béraud91f88742019-09-09 00:46:46 -0400317 if (oldBottom == 0 && oldTop == 0) {
318 updateListPadding();
319 } else {
320 if (animation.isStarted())
321 animation.cancel();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -0400322 animation.setIntValues(binding.histList.getPaddingBottom(), (currentBottomView == null ? 0 : currentBottomView.getHeight()) + marginPxTotal);
Adrien Béraud91f88742019-09-09 00:46:46 -0400323 animation.start();
324 }
Adrien Béraud772e2162019-02-12 16:00:21 -0500325 });
326
Adrien Béraudb28c4912018-12-02 22:58:52 -0500327 DefaultItemAnimator animator = (DefaultItemAnimator) binding.histList.getItemAnimator();
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500328 if (animator != null)
329 animator.setSupportsChangeAnimations(false);
Adrien Béraudb28c4912018-12-02 22:58:52 -0500330 binding.histList.setAdapter(mAdapter);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500331 }
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500332
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500333 @Override
334 public void setConversationColor(int color) {
Adrien Béraud171ba362018-12-14 21:35:40 -0500335 Colorable activity = (Colorable) getActivity();
336 if (activity != null)
337 activity.setColor(color);
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500338 mAdapter.setPrimaryColor(color);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500339 }
340
Adrien Béraud7c505112018-03-20 16:03:28 -0400341 @Override
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500342 public void onDestroyView() {
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500343 if (mPreferences != null)
344 mPreferences.unregisterOnSharedPreferenceChangeListener(this);
Adrien Béraud772e2162019-02-12 16:00:21 -0500345 animation.removeAllUpdateListeners();
Adrien Béraudb28c4912018-12-02 22:58:52 -0500346 binding.histList.setAdapter(null);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500347 mCompositeDisposable.clear();
Adrien Béraud5477ce82020-02-24 11:13:54 -0500348 if (locationServiceConnection != null) {
349 try {
350 requireContext().unbindService(locationServiceConnection);
351 } catch (Exception e) {
352 Log.w(TAG, "Error unbinding service: " + e.getMessage());
353 }
354 }
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500355 mAdapter = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500356 super.onDestroyView();
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400357 binding = null;
Adrien Béraud4030d2e2018-12-02 23:08:03 -0500358 }
359
360 @Override
Adrien Béraudfd083672019-10-31 13:52:38 -0400361 public boolean onContextItemSelected(@NonNull MenuItem item) {
Adrien Béraud7c505112018-03-20 16:03:28 -0400362 if (mAdapter.onContextItemSelected(item))
363 return true;
364 return super.onContextItemSelected(item);
365 }
366
Rayan Osseirane634a562019-05-29 13:44:55 -0400367 public void updateAdapterItem() {
Adrien Béraud742d3202019-11-15 14:28:59 -0500368 if (mSelectedPosition != -1) {
369 mAdapter.notifyItemChanged(mSelectedPosition);
370 mSelectedPosition = -1;
Rayan Osseirane634a562019-05-29 13:44:55 -0400371 }
372 }
373
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500374 public void sendMessageText() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500375 String message = binding.msgInputTxt.getText().toString();
Adrien Béraudace37a22018-06-22 14:58:36 -0400376 clearMsgEdit();
377 presenter.sendTextMessage(message);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500378 }
379
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400380 public void sendEmoji() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500381 presenter.sendTextMessage(binding.emojiSend.getText().toString());
Adrien Béraud58bd92b2018-08-23 10:54:25 -0400382 }
383
Adrien Béraud5477ce82020-02-24 11:13:54 -0500384 @SuppressLint("RestrictedApi")
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400385 public void expandMenu(View v) {
386 Context context = requireContext();
387 PopupMenu popup = new PopupMenu(context, v);
388 popup.inflate(R.menu.conversation_share_actions);
389 popup.setOnMenuItemClickListener(item -> {
390 switch(item.getItemId()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400391 case R.id.conv_send_audio:
392 sendAudioMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400393 break;
Adrien Béraudd5637f22020-05-14 12:41:50 -0400394 case R.id.conv_send_video:
395 sendVideoMessage();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400396 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400397 case R.id.conv_send_file:
Adrien Béraudc35f7f42020-04-15 15:29:29 -0400398 presenter.selectFile();
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400399 break;
Adrien Béraud5477ce82020-02-24 11:13:54 -0500400 case R.id.conv_share_location:
401 shareLocation();
402 break;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400403 }
404 return false;
405 });
406 MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), v);
407 menuHelper.setForceShowIcon(true);
408 menuHelper.show();
409 }
410
Adrien Béraud5477ce82020-02-24 11:13:54 -0500411 public void shareLocation() {
412 presenter.shareLocation();
413 }
414
415 public void closeLocationSharing(boolean isSharing) {
416 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
417 if (params.width != mapWidth) {
418 params.width = mapWidth;
419 params.height = mapHeight;
420 binding.mapCard.setLayoutParams(params);
421 }
422 if (!isSharing)
423 hideMap();
424 }
425
426 public void openLocationSharing() {
427 binding.conversationLayout.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
428 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.mapCard.getLayoutParams();
429 if (params.width != ViewGroup.LayoutParams.MATCH_PARENT) {
430 params.width = ViewGroup.LayoutParams.MATCH_PARENT;
431 params.height = ViewGroup.LayoutParams.MATCH_PARENT;
432 binding.mapCard.setLayoutParams(params);
433 }
434 }
435
436 @Override
437 public void startShareLocation(String accountId, String conversationId) {
438 showMap(accountId, conversationId, true);
439 }
440
Rayan Osseirane634a562019-05-29 13:44:55 -0400441 /**
442 * Used to update with the past adapter position when a long click was registered
Rayan Osseirane634a562019-05-29 13:44:55 -0400443 */
444 public void updatePosition(int position) {
Adrien Béraud742d3202019-11-15 14:28:59 -0500445 mSelectedPosition = position;
Rayan Osseirane634a562019-05-29 13:44:55 -0400446 }
447
Adrien Béraud5477ce82020-02-24 11:13:54 -0500448 @Override
449 public void showMap(String accountId, String contactId, boolean open) {
450 if (binding.mapCard.getVisibility() == View.GONE) {
451 Log.w(TAG, "showMap " + accountId + " " + contactId);
452
453 FragmentManager fragmentManager = getChildFragmentManager();
454 LocationSharingFragment fragment = LocationSharingFragment.newInstance(accountId, contactId, open);
455 fragmentManager.beginTransaction()
456 .add(R.id.mapLayout, fragment, "map")
457 .commit();
458 binding.mapCard.setVisibility(View.VISIBLE);
459 }
460 if (open) {
461 Fragment fragment = getChildFragmentManager().findFragmentById(R.id.mapLayout);
462 if (fragment != null) {
463 ((LocationSharingFragment) fragment).showControls();
464 }
465 }
466 }
467
468 @Override
469 public void hideMap() {
470 if (binding.mapCard.getVisibility() != View.GONE) {
471 binding.mapCard.setVisibility(View.GONE);
472
473 FragmentManager fragmentManager = getChildFragmentManager();
474 Fragment fragment = fragmentManager.findFragmentById(R.id.mapLayout);
475
476 if (fragment != null) {
477 fragmentManager.beginTransaction()
478 .remove(fragment)
479 .commit();
480 }
481 }
482 }
483
Adrien Béraudd5637f22020-05-14 12:41:50 -0400484 public void sendAudioMessage() {
485 if (!presenter.getDeviceRuntimeService().hasAudioPermission()) {
486 requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_CODE_CAPTURE_AUDIO);
487 } else {
488 Context ctx = requireContext();
489 Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
490
491 if (intent.resolveActivity(ctx.getPackageManager()) != null) {
492 try {
493 mCurrentPhoto = AndroidFileUtils.createAudioFile(ctx);
494 } catch (IOException ex) {
495 Log.e(TAG, "takePicture: error creating temporary file", ex);
496 return;
497 }
498 startActivityForResult(intent, REQUEST_CODE_CAPTURE_AUDIO);
499 } else {
500 Toast.makeText(getActivity(), "Can't find audio recorder app", Toast.LENGTH_SHORT).show();
501 }
502 }
503 }
504
505 public void sendVideoMessage() {
506 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
507 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_CAPTURE_VIDEO);
508 } else {
509 Context context = requireContext();
510 Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
511 intent.putExtra("android.intent.extras.CAMERA_FACING", android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
512 intent.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
513 intent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
514 if (intent.resolveActivity(context.getPackageManager()) != null) {
515 try {
516 mCurrentPhoto = AndroidFileUtils.createVideoFile(context);
517 } catch (IOException ex) {
518 Log.e(TAG, "takePicture: error creating temporary file", ex);
519 return;
520 }
521 intent.putExtra(MediaStore.EXTRA_OUTPUT, ContentUriHandler.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, mCurrentPhoto));
522 startActivityForResult(intent, REQUEST_CODE_CAPTURE_VIDEO);
523 } else {
524 Toast.makeText(getActivity(), "Can't find video recorder app", Toast.LENGTH_SHORT).show();
525 }
526 }
527 }
528
Adrien Béraud64538722018-03-15 17:34:00 -0400529 public void takePicture() {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500530 if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400531 requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CODE_TAKE_PICTURE);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500532 } else {
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500533 Context c = getContext();
534 if (c == null)
535 return;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500536 Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Adrien Béraudf5c32f92019-01-03 23:40:00 -0500537 if (takePictureIntent.resolveActivity(c.getPackageManager()) != null) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500538 // Create the File where the photo should go
Adrien Béraud4f542f92019-01-03 12:17:53 -0500539 try {
Adrien Béraud20df00c2020-05-01 19:35:10 -0400540 File photoFile = AndroidFileUtils.createImageFile(c);
541 Log.i(TAG, "takePicture: trying to save to " + photoFile);
542 android.net.Uri photoURI = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, photoFile);
543 takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
544 .putExtra("android.intent.extras.CAMERA_FACING", 1)
545 .putExtra("android.intent.extras.LENS_FACING_FRONT", 1)
546 .putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
547 mCurrentPhoto = photoFile;
548 startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE);
549 } catch (Exception e) {
550 Toast.makeText(c, "Error taking picture: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
Adrien Béraud4f542f92019-01-03 12:17:53 -0500551 }
Adrien Béraud64538722018-03-15 17:34:00 -0400552 }
Adrien Béraud64538722018-03-15 17:34:00 -0400553 }
554 }
555
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500556 @Override
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500557 public void askWriteExternalStoragePermission() {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400558 requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, JamiApplication.PERMISSIONS_REQUEST);
Pierre Duchemin4af6b392018-02-02 11:23:56 -0500559 }
560
561 @Override
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500562 public void openFilePicker() {
563 Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
564 intent.addCategory(Intent.CATEGORY_OPENABLE);
565 intent.setType("*/*");
566
567 startActivityForResult(intent, REQUEST_CODE_FILE_PICKER);
568 }
569
Adrien Béraud44939482019-02-13 21:42:08 -0500570 private Completable sendFile(File file) {
571 return Completable.fromAction(() -> presenter.sendFile(file));
572 }
573
Adrien Béraud44939482019-02-13 21:42:08 -0500574 private void startFileSend(Completable op) {
575 setLoading(true);
Adrien Béraud1af6c012019-05-25 23:20:29 -0400576 op.observeOn(AndroidSchedulers.mainThread())
Adrien Béraud44939482019-02-13 21:42:08 -0500577 .doFinally(() -> setLoading(false))
578 .subscribe(() -> {}, e -> {
579 Log.e(TAG, "startFileSend: not able to create cache file", e);
Adrien Bérauda0226ff2019-11-21 15:24:42 -0500580 displayErrorToast(Error.INVALID_FILE);
Adrien Béraud44939482019-02-13 21:42:08 -0500581 });
582 }
583
Pierre Duchemine0c3a492018-02-01 16:22:45 -0500584 @Override
Pierre Duchemin17542a72018-02-14 16:38:36 -0500585 public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
Adrien Béraud64538722018-03-15 17:34:00 -0400586 Log.w(TAG, "onActivityResult: " + requestCode + " " + resultCode + " " + resultData);
Pierre Duchemin17542a72018-02-14 16:38:36 -0500587 super.onActivityResult(requestCode, resultCode, resultData);
588
589 if (requestCode == REQUEST_CODE_FILE_PICKER && resultCode == RESULT_OK) {
Adrien Béraud64538722018-03-15 17:34:00 -0400590 if (resultData == null) {
591 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -0500592 }
Adrien Béraud64538722018-03-15 17:34:00 -0400593 android.net.Uri uri = resultData.getData();
594 if (uri == null) {
595 return;
596 }
Adrien Béraud1af6c012019-05-25 23:20:29 -0400597 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri)
598 .observeOn(AndroidSchedulers.mainThread())
599 .flatMapCompletable(this::sendFile));
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400600 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE
601 || requestCode == REQUEST_CODE_CAPTURE_AUDIO
602 || requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
Adrien Béraud64538722018-03-15 17:34:00 -0400603 if (resultCode != RESULT_OK) {
604 mCurrentPhoto = null;
605 return;
606 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500607 Log.w(TAG, "onActivityResult: mCurrentPhoto " + mCurrentPhoto.getAbsolutePath() + " " + mCurrentPhoto.exists() + " " + mCurrentPhoto.length());
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400608 Single<File> file = null;
Adrien Béraud64538722018-03-15 17:34:00 -0400609 if (mCurrentPhoto == null || !mCurrentPhoto.exists() || mCurrentPhoto.length() == 0) {
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400610 android.net.Uri createdUri = resultData.getData();
611 if (createdUri != null) {
612 file = AndroidFileUtils.getCacheFile(requireContext(), createdUri);
613 }
614 } else {
615 file = Single.just(mCurrentPhoto);
Adrien Béraud64538722018-03-15 17:34:00 -0400616 }
Adrien Béraud44939482019-02-13 21:42:08 -0500617 mCurrentPhoto = null;
Adrien Béraud898c2bf2019-09-26 14:49:33 -0400618 if (file == null) {
619 Toast.makeText(getActivity(), "Can't find picture", Toast.LENGTH_SHORT).show();
620 return;
621 }
622 startFileSend(file.flatMapCompletable(this::sendFile));
Pierre Duchemin17542a72018-02-14 16:38:36 -0500623 }
amine younes7c56f312019-06-10 11:34:25 -0400624 // File download trough SAF
625 else if(requestCode == ConversationFragment.REQUEST_CODE_SAVE_FILE
626 && resultCode == RESULT_OK){
627 if(resultData != null && resultData.getData() != null ) {
628 //Get the Uri of the file that was created by the app that received our intent
629 android.net.Uri createdUri = resultData.getData();
630
631 //Try to copy the data of the current file into the newly created one
632 File input = new File(mCurrentFileAbsolutePath);
633 if(requireContext().getContentResolver() != null)
Adrien Béraudd5637f22020-05-14 12:41:50 -0400634 mCompositeDisposable.add(AndroidFileUtils.copyFileToUri(requireContext().getContentResolver(), input, createdUri).
amine younes7c56f312019-06-10 11:34:25 -0400635 observeOn(AndroidSchedulers.mainThread()).
Adrien Béraudd5637f22020-05-14 12:41:50 -0400636 subscribe(()-> Toast.makeText(getContext(), R.string.file_saved_successfully, Toast.LENGTH_SHORT).show(),
637 error-> Toast.makeText(getContext(), R.string.generic_error, Toast.LENGTH_SHORT).show()));
amine younes7c56f312019-06-10 11:34:25 -0400638
639 }
640 }
641
Pierre Duchemin17542a72018-02-14 16:38:36 -0500642 }
643
644 @Override
Adrien Béraud4f542f92019-01-03 12:17:53 -0500645 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Adrien Béraud4f542f92019-01-03 12:17:53 -0500646 for (int i = 0, n = permissions.length; i < n; i++) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400647 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Adrien Béraud4f542f92019-01-03 12:17:53 -0500648 switch (permissions[i]) {
649 case Manifest.permission.CAMERA:
Rayan Osseiran38206c62019-05-15 14:49:03 -0400650 presenter.cameraPermissionChanged(granted);
Adrien Béraud4f542f92019-01-03 12:17:53 -0500651 if (granted) {
Adrien Béraudd5637f22020-05-14 12:41:50 -0400652 if (requestCode == REQUEST_CODE_CAPTURE_VIDEO) {
653 sendVideoMessage();
654 } else if (requestCode == REQUEST_CODE_TAKE_PICTURE) {
655 takePicture();
656 }
657 }
658 return;
659 case Manifest.permission.RECORD_AUDIO:
660 if (granted) {
661 if (requestCode == REQUEST_CODE_CAPTURE_AUDIO) {
662 sendAudioMessage();
663 }
Adrien Béraud4f542f92019-01-03 12:17:53 -0500664 }
665 return;
666 default:
667 break;
668 }
669 }
670 }
671
672 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400673 public void addElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400674 mAdapter.add(element);
675 scrollToEnd();
676 }
Adrien Béraud3cbc7fa2018-07-18 18:36:21 -0400677
Adrien Béraudace37a22018-06-22 14:58:36 -0400678 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400679 public void updateElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400680 mAdapter.update(element);
681 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500682
Adrien Béraudace37a22018-06-22 14:58:36 -0400683 @Override
Rayan Osseiran6f415662019-10-25 14:23:25 -0400684 public void removeElement(Interaction element) {
Adrien Béraudace37a22018-06-22 14:58:36 -0400685 mAdapter.remove(element);
Adrien Béraud21533292018-03-22 14:11:35 -0400686 }
687
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400688 @Override
Adrien Béraudfd458ea2020-02-28 13:40:18 -0500689 public void setComposingStatus(Account.ComposingStatus composingStatus) {
690 mAdapter.setComposingStatus(composingStatus);
691 if (composingStatus == Account.ComposingStatus.Active)
692 scrollToEnd();
693 }
694
695 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400696 public void setLastDisplayed(Interaction interaction) {
697 mAdapter.setLastDisplayed(interaction);
698 }
699
700 @Override
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400701 public void shareFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500702 Context c = getContext();
703 if (c == null)
704 return;
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400705 android.net.Uri fileUri = null;
706 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500707 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400708 } catch (IllegalArgumentException e) {
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500709 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400710 }
711 if (fileUri != null) {
712 Intent sendIntent = new Intent();
713 sendIntent.setAction(Intent.ACTION_SEND);
714 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500715 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudfcf457f2018-04-03 17:46:34 -0400716 sendIntent.setDataAndType(fileUri, type);
717 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
718 startActivity(Intent.createChooser(sendIntent, null));
719 }
720 }
721
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500722 @Override
723 public void openFile(File path) {
Adrien Béraud50549532019-01-03 12:22:16 -0500724 Context c = getContext();
725 if (c == null)
726 return;
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500727 android.net.Uri fileUri = null;
728 try {
Andreas Traczykbc5d2352020-01-23 14:27:59 -0500729 fileUri = ContentUriHandler.getUriForFile(c, ContentUriHandler.AUTHORITY_FILES, path);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500730 } catch (IllegalArgumentException e) {
731 Log.e("File Selector", "The selected file can't be shared: " + path.getName());
732 }
733 if (fileUri != null) {
734 Intent sendIntent = new Intent();
735 sendIntent.setAction(Intent.ACTION_VIEW);
736 sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Adrien Béraud50549532019-01-03 12:22:16 -0500737 String type = c.getContentResolver().getType(fileUri);
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500738 sendIntent.setDataAndType(fileUri, type);
739 sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
740 //startActivity(Intent.createChooser(sendIntent, null));
Rayan Osseirane4450272019-06-03 14:17:19 -0400741 try {
742 startActivity(sendIntent);
743 } catch (ActivityNotFoundException e) {
744 Snackbar.make(getView(), R.string.conversation_open_file_error, Snackbar.LENGTH_LONG).show();
745 Log.e("File Loader", "File of unknown type, could not open: " + path.getName());
746 }
Adrien Béraudb2b3f442018-12-01 17:42:38 -0500747 }
748 }
749
Adrien Béraud44939482019-02-13 21:42:08 -0500750 boolean actionSendMsgText(int actionId) {
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500751 switch (actionId) {
752 case EditorInfo.IME_ACTION_SEND:
Adrien Béraudace37a22018-06-22 14:58:36 -0400753 sendMessageText();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500754 return true;
755 }
756 return false;
757 }
758
Alexandre Lision66a9f9a2017-02-26 20:28:27 -0500759 public void onClick() {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400760 presenter.clickOnGoingPane();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500761 }
762
763 @Override
764 public void onPause() {
765 super.onPause();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400766 presenter.pause();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500767 }
768
769 @Override
770 public void onResume() {
771 super.onResume();
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400772 presenter.resume();
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500773 }
774
775 @Override
Andreas Traczykcee415a2019-12-03 15:45:04 -0500776 public void onDestroy() {
777 mCompositeDisposable.dispose();
778 super.onDestroy();
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400779 }
780
781 @Override
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400782 public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
783 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500784 return;
785 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400786 inflater.inflate(R.menu.conversation_actions, menu);
Adrien Béraud5b47cb52018-07-06 16:24:14 -0400787 mAudioCallBtn = menu.findItem(R.id.conv_action_audiocall);
788 mVideoCallBtn = menu.findItem(R.id.conv_action_videocall);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500789 }
790
791 @Override
792 public boolean onOptionsItemSelected(MenuItem item) {
793 switch (item.getItemId()) {
794 case android.R.id.home:
795 startActivity(new Intent(getActivity(), HomeActivity.class));
796 return true;
797 case R.id.conv_action_audiocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500798 presenter.goToCall(true);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500799 return true;
800 case R.id.conv_action_videocall:
Adrien Béraud4a643052019-11-18 12:41:23 -0500801 presenter.goToCall(false);
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500802 return true;
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500803 case R.id.conv_contact_details:
804 presenter.openContact();
Aline Bonnet54cf69b2017-03-28 12:03:45 -0400805 return true;
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500806 default:
807 return super.onOptionsItemSelected(item);
808 }
809 }
810
Aline Bonnet9c6defe2016-12-21 13:21:02 -0500811 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400812 protected void initPresenter(ConversationPresenter presenter) {
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500813 Bundle args = getArguments();
814 if (args == null)
815 return;
816 Uri contactUri = new Uri(args.getString(KEY_CONTACT_RING_ID));
817 String accountId = args.getString(KEY_ACCOUNT_ID);
818 mAdapter = new ConversationAdapter(this, presenter);
819 presenter.init(contactUri, accountId);
Adrien Béraud56c34132018-11-29 13:32:00 -0500820 try {
Adrien Béraud44939482019-02-13 21:42:08 -0500821 mPreferences = requireActivity().getSharedPreferences(accountId + "_" + contactUri.getRawRingId(), Context.MODE_PRIVATE);
Adrien Béraud3c483ce2019-01-02 17:33:49 -0500822 mPreferences.registerOnSharedPreferenceChangeListener(this);
823 presenter.setConversationColor(mPreferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
Adrien Béraud56c34132018-11-29 13:32:00 -0500824 } catch (Exception e) {
825 Log.e(TAG, "Can't load conversation preferences");
826 }
Adrien Béraud5477ce82020-02-24 11:13:54 -0500827
828 if (locationServiceConnection == null) {
829 locationServiceConnection = new ServiceConnection() {
830 @Override
831 public void onServiceConnected(ComponentName name, IBinder service) {
832 Log.w(TAG, "onServiceConnected");
833 LocationSharingService.LocalBinder binder = (LocationSharingService.LocalBinder) service;
834 LocationSharingService locationService = binder.getService();
835 ConversationPath path = new ConversationPath(presenter.getPath());
836 if (locationService.isSharing(path)) {
837 showMap(accountId, contactUri.getUri(), false);
838 }
839 try {
840 requireContext().unbindService(locationServiceConnection);
841 } catch (Exception e) {
842 Log.w(TAG, "Error unbinding service", e);
843 }
844 }
845
846 @Override
847 public void onServiceDisconnected(ComponentName name) {
848 Log.w(TAG, "onServiceDisconnected");
849 locationServiceConnection = null;
850 }
851 };
852
853 Log.w(TAG, "bindService");
854 requireContext().bindService(new Intent(requireContext(), LocationSharingService.class), locationServiceConnection, 0);
855 }
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500856 }
857
858 @Override
859 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
860 switch (key) {
861 case KEY_PREFERENCE_CONVERSATION_COLOR:
862 presenter.setConversationColor(prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, getResources().getColor(R.color.color_primary_light)));
863 break;
864 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400865 }
866
867 @Override
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400868 public void displayContact(final CallContact contact) {
Andreas Traczykcee415a2019-12-03 15:45:04 -0500869 mCompositeDisposable.clear();
870 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact)
871 .doOnSuccess(d -> {
872 mConversationAvatar = (AvatarDrawable) d;
873 mParticipantAvatars.put(contact.getPrimaryNumber(),
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500874 new AvatarDrawable((AvatarDrawable) d));
Andreas Traczykcee415a2019-12-03 15:45:04 -0500875 })
876 .flatMapObservable(d -> contact.getUpdatesSubject())
Adrien Béraud78ae7b92018-08-25 19:04:17 -0400877 .observeOn(AndroidSchedulers.mainThread())
Andreas Traczykcee415a2019-12-03 15:45:04 -0500878 .subscribe(c -> {
879 mConversationAvatar.update(c);
880 String uri = contact.getPrimaryNumber();
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400881 AvatarDrawable ad = mParticipantAvatars.get(uri);
882 if (ad != null)
883 ad.update(c);
Andreas Traczykcee415a2019-12-03 15:45:04 -0500884 setupActionbar(contact);
885 mAdapter.setPhoto();
886 }));
Adrien Béraud263cd5c2020-03-13 13:36:57 -0400887 mCompositeDisposable.add(AvatarFactory.getAvatar(requireContext(), contact, false)
888 .doOnSuccess(d -> mSmallParticipantAvatars.put(contact.getPrimaryNumber(), new AvatarDrawable((AvatarDrawable) d)))
889 .flatMapObservable(d -> contact.getUpdatesSubject())
890 .subscribe(c -> {
891 synchronized (mSmallParticipantAvatars) {
892 String uri = contact.getPrimaryNumber();
893 AvatarDrawable ad = mSmallParticipantAvatars.get(uri);
894 if (ad != null)
895 ad.update(c);
896 }
897 }));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400898 }
899
900 @Override
901 public void displayOnGoingCallPane(final boolean display) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500902 binding.ongoingcallPane.setVisibility(display ? View.VISIBLE : View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400903 }
904
905 @Override
906 public void displayNumberSpinner(final Conversation conversation, final Uri number) {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500907 binding.numberSelector.setVisibility(View.VISIBLE);
Adrien Béraud5477ce82020-02-24 11:13:54 -0500908 binding.numberSelector.setAdapter(new NumberAdapter(getActivity(),
909 conversation.getContact(), false));
Adrien Béraudb28c4912018-12-02 22:58:52 -0500910 binding.numberSelector.setSelection(getIndex(binding.numberSelector, number));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400911 }
912
913 @Override
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400914 public void hideNumberSpinner() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500915 binding.numberSelector.setVisibility(View.GONE);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400916 }
917
918 @Override
919 public void clearMsgEdit() {
Adrien Béraudb28c4912018-12-02 22:58:52 -0500920 binding.msgInputTxt.setText("");
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400921 }
922
923 @Override
924 public void goToHome() {
925 if (getActivity() instanceof ConversationActivity) {
926 getActivity().finish();
Aline Bonneteb5f7ff2017-01-17 11:09:17 -0500927 }
928 }
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400929
930 @Override
931 public void goToAddContact(CallContact callContact) {
932 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact), REQ_ADD_CONTACT);
933 }
934
935 @Override
936 public void goToCallActivity(String conferenceId) {
937 startActivity(new Intent(Intent.ACTION_VIEW)
Adrien Béraud44939482019-02-13 21:42:08 -0500938 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400939 .putExtra(NotificationService.KEY_CALL_ID, conferenceId));
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400940 }
941
942 @Override
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500943 public void goToContactActivity(String accountId, String contactRingId) {
944 startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contactRingId))
Adrien Béraud44939482019-02-13 21:42:08 -0500945 .setClass(requireActivity().getApplicationContext(), ContactDetailsActivity.class));
Adrien Béraud0f3ee3d2018-12-08 22:03:54 -0500946 }
947
948 @Override
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500949 public void goToCallActivityWithResult(String accountId, String contactRingId, boolean audioOnly) {
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400950 Intent intent = new Intent(CallActivity.ACTION_CALL)
Adrien Béraud44939482019-02-13 21:42:08 -0500951 .setClass(requireActivity().getApplicationContext(), CallActivity.class)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500952 .putExtra(KEY_ACCOUNT_ID, accountId)
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500953 .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500954 .putExtra(KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousaec95e5e2017-03-21 15:28:23 -0400955 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL);
956 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500957
Andreas Traczykcee415a2019-12-03 15:45:04 -0500958 private void setupActionbar(CallContact contact) {
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400959 if (!isVisible()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500960 return;
961 }
962
Andreas Traczykcee415a2019-12-03 15:45:04 -0500963 ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar();
964 if (actionBar == null) {
965 return;
966 }
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500967
Andreas Traczykcee415a2019-12-03 15:45:04 -0500968 Context context = actionBar.getThemedContext();
969 String displayName = contact.getDisplayName();
970 String identity = contact.getRingUsername();
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500971
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400972 Activity activity = getActivity();
973 if (activity instanceof HomeActivity) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500974 Toolbar toolbar = getActivity().findViewById(R.id.main_toolbar);
975 TextView title = toolbar.findViewById(R.id.contact_title);
976 TextView subtitle = toolbar.findViewById(R.id.contact_subtitle);
977 ImageView logo = toolbar.findViewById(R.id.contact_image);
978
Adrien Béraud21a3ea22020-04-01 16:06:09 -0400979 if (!((HomeActivity) activity).isConversationSelected()) {
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500980 title.setText("");
981 subtitle.setText("");
982 logo.setImageDrawable(null);
Adrien Béraudb96a7d92020-02-24 11:55:05 -0500983 return;
984 }
985
986 logo.setVisibility(View.VISIBLE);
987 title.setText(displayName);
988 title.setTextSize(15);
989 title.setTypeface(null, Typeface.NORMAL);
990
991 if (identity != null && !identity.equals(displayName)) {
992 subtitle.setText(identity);
993
994 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
995 params.addRule(RelativeLayout.ALIGN_TOP, R.id.contact_image);
996 title.setLayoutParams(params);
997 } else {
998 subtitle.setText("");
999
1000 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) title.getLayoutParams();
1001 params.removeRule(RelativeLayout.ALIGN_TOP);
1002 params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
1003 title.setLayoutParams(params);
1004 }
1005
1006 logo.setImageDrawable(mConversationAvatar);
1007 } else {
1008 if (identity != null && !identity.equals(displayName)) {
1009 actionBar.setSubtitle(identity);
1010 }
1011 actionBar.setTitle(displayName);
1012 int targetSize = (int) (AvatarFactory.SIZE_AB * context.getResources().getDisplayMetrics().density);
1013 mConversationAvatar.setInSize(targetSize);
1014 actionBar.setLogo(null);
1015 actionBar.setLogo(mConversationAvatar);
Andreas Traczykcee415a2019-12-03 15:45:04 -05001016 }
Andreas Traczykcee415a2019-12-03 15:45:04 -05001017 }
1018
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001019 public void blockContactRequest() {
1020 presenter.onBlockIncomingContactRequest();
1021 }
1022
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001023 public void refuseContactRequest() {
1024 presenter.onRefuseIncomingContactRequest();
1025 }
1026
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001027 public void acceptContactRequest() {
1028 presenter.onAcceptIncomingContactRequest();
1029 }
1030
Adrien Béraudace37a22018-06-22 14:58:36 -04001031 public void addContact() {
1032 presenter.onAddContact();
1033 }
1034
1035 @Override
Adrien Béraud5477ce82020-02-24 11:13:54 -05001036 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001037 super.onPrepareOptionsMenu(menu);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001038 boolean visible = binding.cvMessageInput.getVisibility() == View.VISIBLE;
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001039 if (mAudioCallBtn != null)
1040 mAudioCallBtn.setVisible(visible);
1041 if (mVideoCallBtn != null)
1042 mVideoCallBtn.setVisible(visible);
1043 }
1044
1045 @Override
Adrien Béraudace37a22018-06-22 14:58:36 -04001046 public void switchToUnknownView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001047 binding.cvMessageInput.setVisibility(View.GONE);
1048 binding.unknownContactPrompt.setVisibility(View.VISIBLE);
1049 binding.trustRequestPrompt.setVisibility(View.GONE);
1050 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted), contactDisplayName));
1051 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001052 currentBottomView = binding.unknownContactPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001053 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001054 updateListPadding();
Adrien Béraudace37a22018-06-22 14:58:36 -04001055 }
1056
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001057 @Override
1058 public void switchToIncomingTrustRequestView(String contactDisplayName) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001059 binding.cvMessageInput.setVisibility(View.GONE);
1060 binding.unknownContactPrompt.setVisibility(View.GONE);
1061 binding.trustRequestPrompt.setVisibility(View.VISIBLE);
1062 binding.tvTrustRequestMessage.setText(String.format(getString(R.string.message_contact_not_trusted_yet), contactDisplayName));
1063 binding.trustRequestMessageLayout.setVisibility(View.VISIBLE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001064 currentBottomView = binding.trustRequestPrompt;
Adrien Béraud44939482019-02-13 21:42:08 -05001065 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001066 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001067 }
1068
1069 @Override
1070 public void switchToConversationView() {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001071 binding.cvMessageInput.setVisibility(View.VISIBLE);
1072 binding.unknownContactPrompt.setVisibility(View.GONE);
1073 binding.trustRequestPrompt.setVisibility(View.GONE);
1074 binding.trustRequestMessageLayout.setVisibility(View.GONE);
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001075 currentBottomView = binding.cvMessageInput;
Adrien Béraud44939482019-02-13 21:42:08 -05001076 requireActivity().invalidateOptionsMenu();
Adrien Béraud0dcc71b2019-09-25 13:23:44 -04001077 updateListPadding();
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001078 }
1079
1080 @Override
1081 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001082 presenter.clickOnGoingPane();
1083 }
1084
1085 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001086 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001087 presenter.clickOnGoingPane();
1088 }
1089
1090 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001091 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001092 presenter.clickOnGoingPane();
1093 }
Pierre Duchemin17542a72018-02-14 16:38:36 -05001094
1095 private void setLoading(boolean isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001096 if (binding == null)
Adrien Béraud5b47cb52018-07-06 16:24:14 -04001097 return;
Pierre Duchemin17542a72018-02-14 16:38:36 -05001098 if (isLoading) {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001099 binding.btnTakePicture.setVisibility(View.GONE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001100 binding.pbDataTransfer.setVisibility(View.VISIBLE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001101 } else {
Adrien Béraudb28c4912018-12-02 22:58:52 -05001102 binding.btnTakePicture.setVisibility(View.VISIBLE);
Adrien Béraudb28c4912018-12-02 22:58:52 -05001103 binding.pbDataTransfer.setVisibility(View.GONE);
Pierre Duchemin17542a72018-02-14 16:38:36 -05001104 }
1105 }
Adrien Béraud1b8ac9f2018-05-31 14:34:23 -04001106
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001107 public void handleShareIntent(Intent intent) {
Adrien Béraud5477ce82020-02-24 11:13:54 -05001108 Log.w(TAG, "handleShareIntent " + intent);
1109
1110 String action = intent.getAction();
1111 if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
1112 String type = intent.getType();
1113 if (type == null) {
1114 Log.w(TAG, "Can't share with no type");
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001115 return;
Adrien Béraud5477ce82020-02-24 11:13:54 -05001116 }
1117 if (type.startsWith("text/plain")) {
1118 binding.msgInputTxt.setText(intent.getStringExtra(Intent.EXTRA_TEXT));
1119 } else {
1120 android.net.Uri uri = intent.getData();
1121 ClipData clip = intent.getClipData();
1122 if (uri == null && clip != null && clip.getItemCount() > 0)
1123 uri = clip.getItemAt(0).getUri();
1124 if (uri == null)
1125 return;
1126 startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri).flatMapCompletable(this::sendFile));
1127 }
1128 } else if (Intent.ACTION_VIEW.equals(action)) {
1129 ConversationPath path = ConversationPath.fromIntent(intent);
1130 if (path != null && intent.getBooleanExtra(EXTRA_SHOW_MAP, false)) {
1131 shareLocation();
1132 }
Adrien Béraudae45ffa2018-07-06 16:21:29 -04001133 }
1134 }
amine younes7c56f312019-06-10 11:34:25 -04001135
1136 /**
1137 * Creates an intent using Android Storage Access Framework
1138 * This intent is then received by applications that can handle it like
1139 * Downloads or Google drive
1140 * @param file DataTransfer of the file that is going to be stored
1141 * @param currentFileAbsolutePath absolute path of the file we want to save
1142 */
1143 public void startSaveFile(DataTransfer file, String currentFileAbsolutePath){
1144 //Get the current file absolute path and store it
1145 mCurrentFileAbsolutePath = currentFileAbsolutePath;
1146
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()));
amine younes7c56f312019-06-10 11:34:25 -04001150 downloadFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
1151 downloadFileIntent.putExtra(Intent.EXTRA_TITLE,file.getDisplayName());
1152
1153 startActivityForResult(downloadFileIntent, ConversationFragment.REQUEST_CODE_SAVE_FILE);
1154 }
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}