blob: 9827fb69c79169427fa529969dad381d099b968b [file] [log] [blame]
Adrien Béraud04d822c2015-04-02 17:44:36 -04001/*
Adrien Béraude552f692020-11-03 14:30:52 -05002 * Copyright (C) 2004-2020 Savoir-faire Linux Inc.
Adrien Béraud04d822c2015-04-02 17:44:36 -04003 *
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04004 * Author: Hadrien De Sousa <hadrien.desousa@savoirfairelinux.com>
Adrien Béraudbc0898e2018-08-23 14:31:11 -04005 * Adrien Béraud <adrien.beraud@savoirfairelinux.com>
Adrien Béraud04d822c2015-04-02 17:44:36 -04006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
Adrien Béraudda712a42015-11-22 23:45:26 -050019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Adrien Béraud04d822c2015-04-02 17:44:36 -040020 */
Adrien Béraud04d822c2015-04-02 17:44:36 -040021package cx.ring.fragments;
22
Rayan Osseiran38206c62019-05-15 14:49:03 -040023import android.Manifest;
Adrien Béraud2d50acb2020-03-23 22:02:15 -040024import android.animation.ValueAnimator;
Adrien Béraude4f901a2019-10-25 17:26:30 -040025import android.annotation.SuppressLint;
Adrien Béraudde0d4522018-12-12 12:11:02 -050026import android.app.Activity;
Adrien Béraud79808d02018-02-20 00:16:28 +010027import android.app.PendingIntent;
28import android.app.PictureInPictureParams;
29import android.app.RemoteAction;
Rayan Osseiranf7dfe232019-06-06 10:26:10 -040030import android.content.ComponentName;
Adrien Béraud162427f2016-04-12 18:04:08 -040031import android.content.Context;
32import android.content.Intent;
Rayan Osseiran38206c62019-05-15 14:49:03 -040033import android.content.pm.PackageManager;
ayounes47e93992019-10-28 12:09:53 -040034import android.content.res.Configuration;
Adrien Béraudde0d4522018-12-12 12:11:02 -050035import android.graphics.Matrix;
Adrien Béraudfb6341f2016-03-07 16:18:54 -050036import android.graphics.PixelFormat;
Adrien Béraud2d50acb2020-03-23 22:02:15 -040037import android.graphics.PointF;
Adrien Béraud79808d02018-02-20 00:16:28 +010038import android.graphics.Rect;
Adrien Béraudde0d4522018-12-12 12:11:02 -050039import android.graphics.RectF;
40import android.graphics.SurfaceTexture;
ayounes47e93992019-10-28 12:09:53 -040041import android.graphics.drawable.Drawable;
Adrien Béraud79808d02018-02-20 00:16:28 +010042import android.graphics.drawable.Icon;
Adrien Béraudade9bee2019-12-02 17:13:26 -050043import android.media.projection.MediaProjection;
44import android.media.projection.MediaProjectionManager;
Adrien Béraud8d6a4832016-04-12 18:06:11 -040045import android.os.Build;
Adrien Béraud04d822c2015-04-02 17:44:36 -040046import android.os.Bundle;
47import android.os.PowerManager;
Adrien Béraudbcbb4d42018-12-08 16:06:39 -050048import android.text.Editable;
Adrien Béraud34915fb2020-08-24 17:12:03 -040049import android.text.TextUtils;
Adrien Béraudbcbb4d42018-12-08 16:06:39 -050050import android.text.TextWatcher;
Adrien Béraud34915fb2020-08-24 17:12:03 -040051import android.util.Log;
Adrien Béraud79808d02018-02-20 00:16:28 +010052import android.util.Rational;
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -040053import android.view.Gravity;
Adrien Béraud86a1e372018-11-23 23:24:30 -050054import android.view.LayoutInflater;
Adrien Béraud162427f2016-04-12 18:04:08 -040055import android.view.Menu;
56import android.view.MenuInflater;
57import android.view.MenuItem;
Adrien Béraud2d50acb2020-03-23 22:02:15 -040058import android.view.MotionEvent;
Adrien Béraudeb4bb002019-03-14 15:52:48 -040059import android.view.OrientationEventListener;
Adrien Béraudde0d4522018-12-12 12:11:02 -050060import android.view.Surface;
Adrien Béraud162427f2016-04-12 18:04:08 -040061import android.view.SurfaceHolder;
Adrien Béraudde0d4522018-12-12 12:11:02 -050062import android.view.TextureView;
Adrien Béraud162427f2016-04-12 18:04:08 -040063import android.view.View;
Adrien Béraud162427f2016-04-12 18:04:08 -040064import android.view.ViewGroup;
Adrien Béraudeb4bb002019-03-14 15:52:48 -040065import android.view.WindowManager;
Adrien Béraud2d50acb2020-03-23 22:02:15 -040066import android.view.animation.DecelerateInterpolator;
Romain Bertozziad8fd842016-05-11 14:30:35 -040067import android.view.inputmethod.InputMethodManager;
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -040068import android.widget.FrameLayout;
ayounes47e93992019-10-28 12:09:53 -040069import android.widget.LinearLayout;
Adrien Béraud162427f2016-04-12 18:04:08 -040070import android.widget.RelativeLayout;
Adrien Béraud20bd7232020-03-16 11:33:23 -040071import android.widget.Toast;
Adrien Béraud04d822c2015-04-02 17:44:36 -040072
Rayan Osseiran3dd04662019-06-28 16:47:48 -040073import androidx.annotation.NonNull;
74import androidx.annotation.Nullable;
75import androidx.appcompat.app.ActionBar;
76import androidx.appcompat.app.AppCompatActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -040077import androidx.appcompat.view.menu.MenuBuilder;
78import androidx.appcompat.view.menu.MenuPopupHelper;
79import androidx.appcompat.widget.PopupMenu;
Rayan Osseiran3dd04662019-06-28 16:47:48 -040080import androidx.databinding.DataBindingUtil;
Adrien Béraude4f901a2019-10-25 17:26:30 -040081import androidx.fragment.app.FragmentActivity;
Adrien Béraud34915fb2020-08-24 17:12:03 -040082import androidx.percentlayout.widget.PercentFrameLayout;
Rayan Osseiran3dd04662019-06-28 16:47:48 -040083
Pierre Ducheminbb833672018-03-09 16:18:33 -050084import com.rodolfonavalon.shaperipplelibrary.model.Circle;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040085
Adrien Béraud79808d02018-02-20 00:16:28 +010086import java.util.ArrayList;
Adrien Béraude4f901a2019-10-25 17:26:30 -040087import java.util.List;
Romain Bertozzi64a66782016-08-02 12:10:38 -040088import java.util.Locale;
ayounes81087472019-11-08 15:26:05 -050089import java.util.Map;
Adrien Béraud79808d02018-02-20 00:16:28 +010090import java.util.Random;
Adrien Béraud04d822c2015-04-02 17:44:36 -040091
Rayan Osseiran38206c62019-05-15 14:49:03 -040092import javax.inject.Inject;
93
Adrien Béraud162427f2016-04-12 18:04:08 -040094import cx.ring.R;
Adrien Bérauda0226ff2019-11-21 15:24:42 -050095import cx.ring.adapters.ConfParticipantAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040096import cx.ring.application.JamiApplication;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -040097import cx.ring.call.CallPresenter;
98import cx.ring.call.CallView;
Rayan Osseiran3dd04662019-06-28 16:47:48 -040099import cx.ring.client.CallActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400100import cx.ring.client.ContactDetailsActivity;
Adrien Béraud162427f2016-04-12 18:04:08 -0400101import cx.ring.client.ConversationActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400102import cx.ring.client.ConversationSelectionActivity;
Thibault Wittemberg4f33d072016-10-06 17:11:41 -0400103import cx.ring.client.HomeActivity;
ayounes019267f2020-01-13 15:14:08 -0500104import cx.ring.daemon.Ringservice;
Adrien Béraud86a1e372018-11-23 23:24:30 -0500105import cx.ring.databinding.FragCallBinding;
Adrien Béraud34915fb2020-08-24 17:12:03 -0400106import cx.ring.databinding.ItemParticipantLabelBinding;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400107import cx.ring.model.CallContact;
Adrien Béraud34915fb2020-08-24 17:12:03 -0400108import cx.ring.model.Conference;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400109import cx.ring.model.SipCall;
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500110import cx.ring.mvp.BaseSupportFragment;
ayounesc6c2c012019-11-11 11:09:51 -0500111import cx.ring.plugins.RecyclerPicker.RecyclerPicker;
112import cx.ring.plugins.RecyclerPicker.RecyclerPickerLayoutManager;
Alexandre Lision5da46fa2017-08-09 10:25:50 -0400113import cx.ring.service.DRingService;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400114import cx.ring.services.DeviceRuntimeService;
Adrien Béraud34a6fa22019-07-28 16:02:59 -0400115import cx.ring.services.HardwareService;
Adrien Béraud79808d02018-02-20 00:16:28 +0100116import cx.ring.services.NotificationService;
Alexandre Lision4865f7d2016-11-16 18:03:35 -0500117import cx.ring.utils.ActionHelper;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400118import cx.ring.utils.ContentUriHandler;
119import cx.ring.utils.ConversationPath;
Pierre Duchemin42788c32018-03-08 16:21:15 -0500120import cx.ring.utils.DeviceUtils;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400121import cx.ring.utils.KeyboardVisibilityManager;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500122import cx.ring.utils.MediaButtonsHelper;
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -0400123import cx.ring.utils.StringUtils;
Adrien Béraud8f9d2702018-09-16 18:24:01 -0400124import cx.ring.views.AvatarDrawable;
Adrien Béraud2c378b32018-07-11 15:24:02 -0400125import io.reactivex.disposables.CompositeDisposable;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400126
agsantos00e3a9d2020-07-06 15:08:43 -0400127import static cx.ring.daemon.Ringservice.getPluginsEnabled;
agsantos00e3a9d2020-07-06 15:08:43 -0400128
ayounes47e93992019-10-28 12:09:53 -0400129public class CallFragment extends BaseSupportFragment<CallPresenter> implements CallView, MediaButtonsHelper.MediaButtonsHelperCallback, RecyclerPickerLayoutManager.ItemSelectedListener {
Adrien Béraud04d822c2015-04-02 17:44:36 -0400130
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400131 public static final String TAG = CallFragment.class.getSimpleName();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400132
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400133 public static final String ACTION_PLACE_CALL = "PLACE_CALL";
134 public static final String ACTION_GET_CALL = "GET_CALL";
Adrien Béraud04d822c2015-04-02 17:44:36 -0400135
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400136 public static final String KEY_ACTION = "action";
137 public static final String KEY_ACCOUNT_ID = "accountId";
138 public static final String KEY_CONF_ID = "confId";
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500139 public static final String KEY_AUDIO_ONLY = "AUDIO_ONLY";
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400140
Adrien Béraude4f901a2019-10-25 17:26:30 -0400141 private static final int REQUEST_CODE_ADD_PARTICIPANT = 6;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400142 private static final int REQUEST_PERMISSION_INCOMING = 1003;
143 private static final int REQUEST_PERMISSION_OUTGOING = 1004;
Adrien Béraudade9bee2019-12-02 17:13:26 -0500144 private static final int REQUEST_CODE_SCREEN_SHARE = 7;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400145
Adrien Béraud86a1e372018-11-23 23:24:30 -0500146 private FragCallBinding binding;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400147 private OrientationEventListener mOrientationListener;
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400148
Romain Bertozziad8fd842016-05-11 14:30:35 -0400149 private MenuItem dialPadBtn = null;
ayounes47e93992019-10-28 12:09:53 -0400150 private MenuItem pluginsMenuBtn = null;
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400151 private boolean restartVideo = false;
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400152 private boolean restartPreview = false;
Rayan Osseirande9ac142019-07-02 13:01:32 -0400153 private PowerManager.WakeLock mScreenWakeLock = null;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400154 private int mCurrentOrientation = 0;
155
156 private int mVideoWidth = -1;
157 private int mVideoHeight = -1;
Adrien Béraudde0d4522018-12-12 12:11:02 -0500158 private int mPreviewWidth = 720, mPreviewHeight = 1280;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400159 private int mPreviewSurfaceWidth = 0, mPreviewSurfaceHeight = 0;
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400160
Adrien Béraudade9bee2019-12-02 17:13:26 -0500161 private MediaProjectionManager mProjectionManager;
162
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400163 private boolean mBackstackLost = false;
164
Adrien Béraude4f901a2019-10-25 17:26:30 -0400165 private ConfParticipantAdapter confAdapter = null;
166 private boolean mConferenceMode = false;
agsantosa6d68a82020-07-09 11:33:30 -0400167 private boolean choosePluginMode = false;
168 public boolean isChoosePluginMode() {
169 return choosePluginMode;
170 }
ayounes81087472019-11-08 15:26:05 -0500171 private boolean pluginsModeFirst = true;
ayounes019267f2020-01-13 15:14:08 -0500172 private List<String> callMediaHandlers;
ayounes47e93992019-10-28 12:09:53 -0400173 private int previousPluginPosition = -1;
174 private RecyclerPicker rp;
ayounesc6c2c012019-11-11 11:09:51 -0500175 private final ValueAnimator animation = new ValueAnimator();
176
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400177 private PointF previewDrag = null;
178 private final ValueAnimator previewSnapAnimation = new ValueAnimator();
179 private final int[] previewMargins = new int[4];
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400180 private float previewHiddenState = 0;
181 private enum PreviewPosition {LEFT, RIGHT}
182 private PreviewPosition previewPosition = PreviewPosition.RIGHT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400183
Rayan Osseiran38206c62019-05-15 14:49:03 -0400184 @Inject
185 DeviceRuntimeService mDeviceRuntimeService;
186
Adrien Béraud2c378b32018-07-11 15:24:02 -0400187 private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
188
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500189 public static CallFragment newInstance(@NonNull String action, @Nullable String accountID, @Nullable String contactRingId, boolean audioOnly) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400190 Bundle bundle = new Bundle();
191 bundle.putString(KEY_ACTION, action);
192 bundle.putString(KEY_ACCOUNT_ID, accountID);
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500193 bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500194 bundle.putBoolean(KEY_AUDIO_ONLY, audioOnly);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400195 CallFragment countDownFragment = new CallFragment();
196 countDownFragment.setArguments(bundle);
197 return countDownFragment;
198 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500199
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400200 public static CallFragment newInstance(@NonNull String action, @Nullable String confId) {
201 Bundle bundle = new Bundle();
202 bundle.putString(KEY_ACTION, action);
203 bundle.putString(KEY_CONF_ID, confId);
204 CallFragment countDownFragment = new CallFragment();
205 countDownFragment.setArguments(bundle);
206 return countDownFragment;
207 }
208
Rayan Osseiran6f415662019-10-25 14:23:25 -0400209 public static int callStateToHumanState(final SipCall.CallStatus state) {
Loïc Siret0202fbf2017-09-28 16:34:28 -0400210 switch (state) {
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400211 case SEARCHING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400212 return R.string.call_human_state_searching;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400213 case CONNECTING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400214 return R.string.call_human_state_connecting;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400215 case RINGING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400216 return R.string.call_human_state_ringing;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400217 case CURRENT:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400218 return R.string.call_human_state_current;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400219 case HUNGUP:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400220 return R.string.call_human_state_hungup;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400221 case BUSY:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400222 return R.string.call_human_state_busy;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400223 case FAILURE:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400224 return R.string.call_human_state_failure;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400225 case HOLD:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400226 return R.string.call_human_state_hold;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400227 case UNHOLD:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400228 return R.string.call_human_state_unhold;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400229 case OVER:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400230 return R.string.call_human_state_over;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400231 case NONE:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400232 default:
Adrien Béraude4f901a2019-10-25 17:26:30 -0400233 return R.string.call_human_state_none;
Loïc Siret0202fbf2017-09-28 16:34:28 -0400234 }
235 }
236
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400237 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400238 protected void initPresenter(CallPresenter presenter) {
239 super.initPresenter(presenter);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400240 Bundle args = getArguments();
241 if (args != null) {
242 String action = args.getString(KEY_ACTION);
243 if (action != null) {
244 if (action.equals(ACTION_PLACE_CALL)) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -0400245 prepareCall(false);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400246 } else if (action.equals(ACTION_GET_CALL) || action.equals(CallActivity.ACTION_CALL_ACCEPT)) {
Rayan Osseiraned9feeb2019-07-05 16:04:30 -0400247 presenter.initIncomingCall(getArguments().getString(KEY_CONF_ID), action.equals(ACTION_GET_CALL));
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400248 }
Pierre Duchemin45707ca2018-01-15 15:05:23 -0500249 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500250 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500251 }
252
Adrien Béraud79808d02018-02-20 00:16:28 +0100253 public void onUserLeave() {
254 presenter.requestPipMode();
255 }
256
257 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400258 public void enterPipMode(String callId) {
Adrien Béraud79808d02018-02-20 00:16:28 +0100259 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
260 return;
261 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400262 Context context = requireContext();
Adrien Béraud79808d02018-02-20 00:16:28 +0100263 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
264 PictureInPictureParams.Builder paramBuilder = new PictureInPictureParams.Builder();
Adrien Béraud86a1e372018-11-23 23:24:30 -0500265 if (binding.videoSurface.getVisibility() == View.VISIBLE) {
Adrien Béraud79808d02018-02-20 00:16:28 +0100266 int[] l = new int[2];
Adrien Béraud86a1e372018-11-23 23:24:30 -0500267 binding.videoSurface.getLocationInWindow(l);
Adrien Béraud79808d02018-02-20 00:16:28 +0100268 int x = l[0];
269 int y = l[1];
Adrien Béraud86a1e372018-11-23 23:24:30 -0500270 int w = binding.videoSurface.getWidth();
271 int h = binding.videoSurface.getHeight();
Adrien Béraud79808d02018-02-20 00:16:28 +0100272 Rect videoBounds = new Rect(x, y, x + w, y + h);
273 paramBuilder.setAspectRatio(new Rational(w, h));
274 paramBuilder.setSourceRectHint(videoBounds);
275 }
276 ArrayList<RemoteAction> actions = new ArrayList<>(1);
277 actions.add(new RemoteAction(
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400278 Icon.createWithResource(context, R.drawable.baseline_call_end_24),
Adrien Béraud79808d02018-02-20 00:16:28 +0100279 getString(R.string.action_call_hangup),
280 getString(R.string.action_call_hangup),
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400281 PendingIntent.getService(context, new Random().nextInt(),
Adrien Béraud79808d02018-02-20 00:16:28 +0100282 new Intent(DRingService.ACTION_CALL_END)
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400283 .setClass(context, DRingService.class)
Adrien Béraude4f901a2019-10-25 17:26:30 -0400284 .putExtra(NotificationService.KEY_CALL_ID, callId), PendingIntent.FLAG_ONE_SHOT)));
Adrien Béraud79808d02018-02-20 00:16:28 +0100285 paramBuilder.setActions(actions);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400286 requireActivity().enterPictureInPictureMode(paramBuilder.build());
287 } else if (DeviceUtils.isTv(context)) {
288 requireActivity().enterPictureInPictureMode();
Adrien Béraud79808d02018-02-20 00:16:28 +0100289 }
290 }
291
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500292 @Override
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400293 public void onStart() {
294 super.onStart();
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400295 if (restartVideo && restartPreview) {
296 displayVideoSurface(true, !presenter.isPipMode());
297 restartVideo = false;
298 restartPreview = false;
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400299 } else if (restartVideo) {
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400300 displayVideoSurface(true, false);
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400301 restartVideo = false;
302 }
303 }
304
305 @Override
306 public void onStop() {
307 super.onStop();
Adrien Béraud7b7e2ca2020-12-10 11:18:19 -0500308 previewSnapAnimation.cancel();
Adrien Béraud86a1e372018-11-23 23:24:30 -0500309 if (binding.videoSurface.getVisibility() == View.VISIBLE) {
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400310 restartVideo = true;
311 }
agsantosa6d68a82020-07-09 11:33:30 -0400312 if (!choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -0400313 if (binding.previewContainer.getVisibility() == View.VISIBLE) {
314 restartPreview = true;
315 }
316 }else {
317 if (binding.pluginPreviewContainer.getVisibility() == View.VISIBLE) {
318 restartPreview = true;
agsantos4f7b5a12020-07-08 16:18:07 -0400319 presenter.stopPlugin();
AGS5ef482ce2020-06-12 13:28:51 -0400320 }
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400321 }
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400322 }
323
Adrien Béraud86a1e372018-11-23 23:24:30 -0500324 @Nullable
325 @Override
Adrien Béraudc14d55d2019-01-02 16:33:40 -0500326 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
Adrien Béraud7307cd52020-04-13 23:29:11 -0400327 ((JamiApplication) requireActivity().getApplication()).getInjectionComponent().inject(this);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500328 binding = DataBindingUtil.inflate(inflater, R.layout.frag_call, container, false);
329 binding.setPresenter(this);
Adrien Béraud496e49a2020-08-13 22:31:05 -0400330 rp = new RecyclerPicker(binding.recyclerPicker,
ayounesc6c2c012019-11-11 11:09:51 -0500331 R.layout.item_picker,
ayounes47e93992019-10-28 12:09:53 -0400332 LinearLayout.HORIZONTAL, this);
ayounesc6c2c012019-11-11 11:09:51 -0500333 rp.setFirstLastElementsWidths(112, 112);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500334 return binding.getRoot();
335 }
336
Adrien Béraudde0d4522018-12-12 12:11:02 -0500337 private TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
338 @Override
339 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400340 mPreviewSurfaceWidth = width;
341 mPreviewSurfaceHeight = height;
Adrien Béraudde0d4522018-12-12 12:11:02 -0500342 presenter.previewVideoSurfaceCreated(binding.previewSurface);
343 }
344
345 @Override
346 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400347 mPreviewSurfaceWidth = width;
348 mPreviewSurfaceHeight = height;
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400349 configurePreview(width, 1);
Adrien Béraudde0d4522018-12-12 12:11:02 -0500350 }
351
352 @Override
353 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
354 presenter.previewVideoSurfaceDestroyed();
355 return true;
356 }
357
358 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400359 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
360 }
Adrien Béraudde0d4522018-12-12 12:11:02 -0500361 };
362
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400363 /**
364 * @param hiddenState 0.f if fully shown, 1.f if fully hidden.
365 */
366 private void setPreviewDragHiddenState(float hiddenState) {
367 binding.previewSurface.setAlpha(1.f - (3 * hiddenState / 4));
AGS5ef482ce2020-06-12 13:28:51 -0400368 binding.pluginPreviewSurface.setAlpha(1.f - (3 * hiddenState / 4));
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400369 binding.previewHandle.setAlpha(hiddenState);
AGS5ef482ce2020-06-12 13:28:51 -0400370 binding.pluginPreviewHandle.setAlpha(hiddenState);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400371 }
372
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400373 @SuppressLint("ClickableViewAccessibility")
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400374 @Override
Adrien Béraudc14d55d2019-01-02 16:33:40 -0500375 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400376 setHasOptionsMenu(true);
Hadrien De Sousa73d6dd72017-09-07 10:54:51 -0400377 super.onViewCreated(view, savedInstanceState);
Adrien Béraud79808d02018-02-20 00:16:28 +0100378 mCurrentOrientation = getResources().getConfiguration().orientation;
ayounesc6c2c012019-11-11 11:09:51 -0500379 float dpRatio = requireActivity().getResources().getDisplayMetrics().density;
380
381 animation.setDuration(150);
382 animation.addUpdateListener(valueAnimator -> {
Adrien Béraudb46fd322020-09-02 17:18:28 -0400383 if (binding == null)
384 return;
ayounesc6c2c012019-11-11 11:09:51 -0500385 int upBy = (int) valueAnimator.getAnimatedValue();
386 RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) binding.previewContainer.getLayoutParams();
387 layoutParams.setMargins(0, 0, 0, (int) (upBy * dpRatio));
388 binding.previewContainer.setLayoutParams(layoutParams);
389 });
Adrien Béraud04d822c2015-04-02 17:44:36 -0400390
Adrien Béraude4f901a2019-10-25 17:26:30 -0400391 FragmentActivity activity = getActivity();
392 if (activity != null) {
393 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
394 if (activity instanceof AppCompatActivity) {
395 AppCompatActivity ac_activity = (AppCompatActivity) activity;
396 ActionBar ab = ac_activity.getSupportActionBar();
397 if (ab != null) {
398 ab.setHomeAsUpIndicator(R.drawable.baseline_chat_24);
399 ab.setDisplayHomeAsUpEnabled(true);
400 }
401 }
402 }
403
Adrien Béraudade9bee2019-12-02 17:13:26 -0500404 mProjectionManager = (MediaProjectionManager) requireContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
405
Adrien Béraude4f901a2019-10-25 17:26:30 -0400406 PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
407 if (powerManager != null) {
408 mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
409 mScreenWakeLock.setReferenceCounted(false);
410 if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
411 mScreenWakeLock.acquire();
412 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400413 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500414
Amirhossein7bb77aa2020-12-18 16:30:44 -0500415 if (presenter.setBlockRecordStatus()) {
416 binding.videoSurface.setSecure(true);
417 getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
418 }
419
Adrien Béraud86a1e372018-11-23 23:24:30 -0500420 binding.videoSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
421 binding.videoSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400422 @Override
423 public void surfaceCreated(SurfaceHolder holder) {
424 presenter.videoSurfaceCreated(holder);
425 }
426
427 @Override
428 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
429
430 }
431
432 @Override
433 public void surfaceDestroyed(SurfaceHolder holder) {
434 presenter.videoSurfaceDestroyed();
435 }
436 });
AGS5ef482ce2020-06-12 13:28:51 -0400437
438 binding.pluginPreviewSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
439 binding.pluginPreviewSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
440 @Override
441 public void surfaceCreated(SurfaceHolder holder) {
442 presenter.pluginSurfaceCreated(holder);
443 }
444
445 @Override
446 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
447
448 }
449
450 @Override
451 public void surfaceDestroyed(SurfaceHolder holder) {
452 presenter.pluginSurfaceDestroyed();
453 }
454 });
455
Pierre Duchemin45707ca2018-01-15 15:05:23 -0500456 view.setOnSystemUiVisibilityChangeListener(visibility -> {
457 boolean ui = (visibility & (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN)) == 0;
458 presenter.uiVisibilityChanged(ui);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400459 });
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400460 view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
461 resetVideoSize(mVideoWidth, mVideoHeight));
462
463 WindowManager windowManager = (WindowManager) requireContext().getSystemService(Context.WINDOW_SERVICE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400464 if (windowManager != null) {
465 mOrientationListener = new OrientationEventListener(getContext()) {
466 @Override
467 public void onOrientationChanged(int orientation) {
468 int rot = windowManager.getDefaultDisplay().getRotation();
469 if (mCurrentOrientation != rot) {
470 mCurrentOrientation = rot;
471 presenter.configurationChanged(rot);
472 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400473 }
Adrien Béraude4f901a2019-10-25 17:26:30 -0400474 };
475 if (mOrientationListener.canDetectOrientation()) {
476 mOrientationListener.enable();
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400477 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400478 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400479
Adrien Béraud86a1e372018-11-23 23:24:30 -0500480 binding.shapeRipple.setRippleShape(new Circle());
481 binding.callSpeakerBtn.setChecked(presenter.isSpeakerphoneOn());
Adrien Béraudec19fad2018-12-30 16:51:05 -0500482 binding.callMicBtn.setChecked(presenter.isMicrophoneMuted());
AGS5ef482ce2020-06-12 13:28:51 -0400483 binding.pluginPreviewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
484 configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
Adrien Béraudde0d4522018-12-12 12:11:02 -0500485 binding.previewSurface.setSurfaceTextureListener(listener);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400486 binding.previewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
487 configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500488
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400489 previewSnapAnimation.setDuration(250);
490 previewSnapAnimation.setFloatValues(0.f, 1.f);
491 previewSnapAnimation.setInterpolator(new DecelerateInterpolator());
492 previewSnapAnimation.addUpdateListener(animation -> {
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400493 float animatedFraction = animation == null ? 1 : animation.getAnimatedFraction();
494 configurePreview(mPreviewSurfaceWidth, animatedFraction);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400495 });
496
497 binding.previewContainer.setOnTouchListener((v, event) -> {
498 int action = event.getActionMasked();
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400499 RelativeLayout parent = (RelativeLayout) v.getParent();
500 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
501
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400502 if (action == MotionEvent.ACTION_DOWN) {
503 previewSnapAnimation.cancel();
504 previewDrag = new PointF(event.getX(), event.getY());
505 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400506 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
507 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
508 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
509 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400510 params.setMargins((int) v.getX(), (int) v.getY(), parent.getWidth() - ((int) v.getX() + v.getWidth()), parent.getHeight() - ((int) v.getY() + v.getHeight()));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400511 v.setLayoutParams(params);
512 return true;
513 } else if (action == MotionEvent.ACTION_MOVE) {
514 if (previewDrag != null) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400515 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
516 int currentYPosition = params.topMargin + (int) (event.getY() - previewDrag.y);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400517 params.setMargins(
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400518 currentXPosition,
519 currentYPosition,
520 -((currentXPosition + v.getWidth()) - (int) event.getX()),
521 -((currentYPosition + v.getHeight()) - (int) event.getY()));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400522 v.setLayoutParams(params);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400523
524 float outPosition = binding.previewContainer.getWidth() * 0.85f;
525 float drapOut = 0.f;
526 if (currentXPosition < 0) {
527 drapOut = Math.min(1.f, -currentXPosition / outPosition);
528 } else if (currentXPosition + v.getWidth() > parent.getWidth()) {
529 drapOut = Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition);
530 }
531 setPreviewDragHiddenState(drapOut);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400532 return true;
533 }
534 return false;
535 } else if (action == MotionEvent.ACTION_UP) {
536 if (previewDrag != null) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400537 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
538
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400539 previewSnapAnimation.cancel();
540 previewDrag = null;
541 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400542 int ml = 0, mr = 0, mt = 0, mb = 0;
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400543
544 FrameLayout.LayoutParams hp = (FrameLayout.LayoutParams) binding.previewHandle.getLayoutParams();
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400545 if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) {
546 params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
547 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
548 mr = (int) (parent.getWidth() - v.getWidth() - v.getX());
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400549 previewPosition = PreviewPosition.RIGHT;
550 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400551 } else {
552 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
553 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
554 ml = (int) v.getX();
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400555 previewPosition = PreviewPosition.LEFT;
556 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400557 }
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400558 binding.previewHandle.setLayoutParams(hp);
559
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400560 if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) {
561 params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
562 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
563 mb = (int) (parent.getHeight() - v.getHeight() - v.getY());
564 } else {
565 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
566 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
567 mt = (int) v.getY();
568 }
569 previewMargins[0] = ml;
570 previewMargins[1] = mt;
571 previewMargins[2] = mr;
572 previewMargins[3] = mb;
573 params.setMargins(ml, mt, mr, mb);
574 v.setLayoutParams(params);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400575
576 float outPosition = binding.previewContainer.getWidth() * 0.85f;
577 previewHiddenState = currentXPosition < 0
578 ? Math.min(1.f, -currentXPosition / outPosition)
579 : ((currentXPosition + v.getWidth() > parent.getWidth())
580 ? Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition)
581 : 0.f);
582 setPreviewDragHiddenState(previewHiddenState);
583
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400584 previewSnapAnimation.start();
585 return true;
586 }
587 return false;
588 } else {
589 return false;
590 }
591 });
592
AGS5ef482ce2020-06-12 13:28:51 -0400593 binding.pluginPreviewContainer.setOnTouchListener((v, event) -> {
594 int action = event.getActionMasked();
595 RelativeLayout parent = (RelativeLayout) v.getParent();
596 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
597
598 if (action == MotionEvent.ACTION_DOWN) {
599 previewSnapAnimation.cancel();
600 previewDrag = new PointF(event.getX(), event.getY());
601 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged));
602 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
603 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
604 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
605 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
606 params.setMargins((int) v.getX(), (int) v.getY(), parent.getWidth() - ((int) v.getX() + v.getWidth()), parent.getHeight() - ((int) v.getY() + v.getHeight()));
607 v.setLayoutParams(params);
608 return true;
609 } else if (action == MotionEvent.ACTION_MOVE) {
610 if (previewDrag != null) {
611 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
612 int currentYPosition = params.topMargin + (int) (event.getY() - previewDrag.y);
613 params.setMargins(
614 currentXPosition,
615 currentYPosition,
616 -((currentXPosition + v.getWidth()) - (int) event.getX()),
617 -((currentYPosition + v.getHeight()) - (int) event.getY()));
618 v.setLayoutParams(params);
619
620 float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
621 float drapOut = 0.f;
622 if (currentXPosition < 0) {
623 drapOut = Math.min(1.f, -currentXPosition / outPosition);
624 } else if (currentXPosition + v.getWidth() > parent.getWidth()) {
625 drapOut = Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition);
626 }
627 setPreviewDragHiddenState(drapOut);
628 return true;
629 }
630 return false;
631 } else if (action == MotionEvent.ACTION_UP) {
632 if (previewDrag != null) {
633 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
634
635 previewSnapAnimation.cancel();
636 previewDrag = null;
637 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation));
638 int ml = 0, mr = 0, mt = 0, mb = 0;
639
640 FrameLayout.LayoutParams hp = (FrameLayout.LayoutParams) binding.pluginPreviewHandle.getLayoutParams();
641 if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) {
642 params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
643 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
644 mr = (int) (parent.getWidth() - v.getWidth() - v.getX());
645 previewPosition = PreviewPosition.RIGHT;
646 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
647 } else {
648 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
649 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
650 ml = (int) v.getX();
651 previewPosition = PreviewPosition.LEFT;
652 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
653 }
654 binding.pluginPreviewHandle.setLayoutParams(hp);
655
656 if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) {
657 params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
658 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
659 mb = (int) (parent.getHeight() - v.getHeight() - v.getY());
660 } else {
661 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
662 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
663 mt = (int) v.getY();
664 }
665 previewMargins[0] = ml;
666 previewMargins[1] = mt;
667 previewMargins[2] = mr;
668 previewMargins[3] = mb;
669 params.setMargins(ml, mt, mr, mb);
670 v.setLayoutParams(params);
671
672 float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
673 previewHiddenState = currentXPosition < 0
674 ? Math.min(1.f, -currentXPosition / outPosition)
675 : ((currentXPosition + v.getWidth() > parent.getWidth())
676 ? Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition)
677 : 0.f);
678 setPreviewDragHiddenState(previewHiddenState);
679
680 previewSnapAnimation.start();
681 return true;
682 }
683 return false;
684 } else {
685 return false;
686 }
687 });
688
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500689 binding.dialpadEditText.addTextChangedListener(new TextWatcher() {
690 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400691 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
692 }
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500693
694 @Override
695 public void onTextChanged(CharSequence s, int start, int before, int count) {
696 presenter.sendDtmf(s.subSequence(start, start + count));
697 }
698
699 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400700 public void afterTextChanged(Editable s) {
701 }
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500702 });
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500703 }
704
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400705 private void configurePreview(int width, float animatedFraction) {
Adrien Béraud7b7e2ca2020-12-10 11:18:19 -0500706 Context context = getContext();
707 if (context == null || binding == null)
708 return;
709 float margin = context.getResources().getDimension(R.dimen.call_preview_margin);
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400710 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.previewContainer.getLayoutParams();
711 float r = 1.f - animatedFraction;
712 float hideMargin = 0.f;
713 float targetHiddenState = 0.f;
714 if (previewHiddenState > 0.f) {
715 targetHiddenState = 1.f;
716 float v = width * 0.85f * animatedFraction;
717 hideMargin = previewPosition == PreviewPosition.RIGHT ? v : -v;
718 }
719 setPreviewDragHiddenState(previewHiddenState * r + targetHiddenState * animatedFraction);
720
721 float f = margin * animatedFraction;
722 params.setMargins(
723 (int) (previewMargins[0] * r + f + hideMargin),
724 (int) (previewMargins[1] * r + f),
725 (int) (previewMargins[2] * r + f - hideMargin),
726 (int) (previewMargins[3] * r + f));
727 binding.previewContainer.setLayoutParams(params);
AGS5ef482ce2020-06-12 13:28:51 -0400728 binding.pluginPreviewContainer.setLayoutParams(params);
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400729 }
730
Rayan Osseirande9ac142019-07-02 13:01:32 -0400731 /**
732 * Releases current wakelock and acquires a new proximity wakelock if current call is audio only.
ayounesc6c2c012019-11-11 11:09:51 -0500733 *
Rayan Osseirande9ac142019-07-02 13:01:32 -0400734 * @param isAudioOnly true if it is an audio call
735 */
736 @Override
737 public void handleCallWakelock(boolean isAudioOnly) {
738 if (isAudioOnly) {
739 if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) {
740 mScreenWakeLock.release();
741 }
742 PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400743 if (powerManager != null) {
744 mScreenWakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
745 mScreenWakeLock.setReferenceCounted(false);
Rayan Osseirande9ac142019-07-02 13:01:32 -0400746
Adrien Béraude4f901a2019-10-25 17:26:30 -0400747 if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
748 mScreenWakeLock.acquire();
749 }
Rayan Osseirande9ac142019-07-02 13:01:32 -0400750 }
751 }
752 }
753
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500754 @Override
Adrien Béraud2c378b32018-07-11 15:24:02 -0400755 public void onDestroyView() {
756 super.onDestroyView();
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400757 if (mOrientationListener != null) {
758 mOrientationListener.disable();
759 mOrientationListener = null;
760 }
Adrien Béraud2c378b32018-07-11 15:24:02 -0400761 mCompositeDisposable.clear();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500762 if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) {
763 mScreenWakeLock.release();
764 }
Adrien Béraud7307cd52020-04-13 23:29:11 -0400765 binding = null;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400766 }
767
Adrien Béraud7307cd52020-04-13 23:29:11 -0400768 @Override
769 public void onDestroy() {
770 super.onDestroy();
771 mCompositeDisposable.dispose();
772 }
Rayan Osseiran38206c62019-05-15 14:49:03 -0400773
774 @Override
775 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
776 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Adrien Béraud63de6042019-05-31 09:38:31 -0400777 if (requestCode != REQUEST_PERMISSION_INCOMING && requestCode != REQUEST_PERMISSION_OUTGOING)
778 return;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400779 for (int i = 0, n = permissions.length; i < n; i++) {
780 boolean audioGranted = mDeviceRuntimeService.hasAudioPermission();
Adrien Béraud63de6042019-05-31 09:38:31 -0400781 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400782 switch (permissions[i]) {
783 case Manifest.permission.CAMERA:
Adrien Béraud63de6042019-05-31 09:38:31 -0400784 presenter.cameraPermissionChanged(granted);
785 if (audioGranted) {
786 initializeCall(requestCode == REQUEST_PERMISSION_INCOMING);
Rayan Osseiran38206c62019-05-15 14:49:03 -0400787 }
788 break;
789 case Manifest.permission.RECORD_AUDIO:
Adrien Béraud63de6042019-05-31 09:38:31 -0400790 presenter.audioPermissionChanged(granted);
791 initializeCall(requestCode == REQUEST_PERMISSION_INCOMING);
Rayan Osseiran38206c62019-05-15 14:49:03 -0400792 break;
793 }
794 }
795 }
796
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400797 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400798 public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
799 if (requestCode == REQUEST_CODE_ADD_PARTICIPANT) {
800 if (resultCode == Activity.RESULT_OK && data != null) {
801 ConversationPath path = ConversationPath.fromUri(data.getData());
802 if (path != null) {
Adrien Béraud2d8a8a82020-10-15 11:05:38 -0400803 presenter.addConferenceParticipant(path.getAccountId(), path.getConversationId());
Adrien Béraude4f901a2019-10-25 17:26:30 -0400804 }
805 }
Adrien Béraudade9bee2019-12-02 17:13:26 -0500806 } else if (requestCode == REQUEST_CODE_SCREEN_SHARE) {
807 if (resultCode == Activity.RESULT_OK && data != null) {
Adrien Béraudd0bd4ce2020-11-09 12:07:18 -0500808 try {
809 startScreenShare(mProjectionManager.getMediaProjection(resultCode, data));
810 } catch (Exception e) {
811 Log.w(TAG, "Error starting screen sharing", e);
812 }
Adrien Béraudade9bee2019-12-02 17:13:26 -0500813 } else {
814 binding.callScreenshareBtn.setChecked(false);
815 }
Adrien Béraude4f901a2019-10-25 17:26:30 -0400816 }
817 }
818
819 @Override
820 public void onCreateOptionsMenu(@NonNull Menu m, @NonNull MenuInflater inf) {
Adrien Béraudda712a42015-11-22 23:45:26 -0500821 super.onCreateOptionsMenu(m, inf);
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500822 inf.inflate(R.menu.ac_call, m);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400823 dialPadBtn = m.findItem(R.id.menuitem_dialpad);
ayounes47e93992019-10-28 12:09:53 -0400824 pluginsMenuBtn = m.findItem(R.id.menuitem_video_plugins);
Adrien Béraudda712a42015-11-22 23:45:26 -0500825 }
826
827 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400828 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraudda712a42015-11-22 23:45:26 -0500829 super.onPrepareOptionsMenu(menu);
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400830 presenter.prepareOptionMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400831 }
832
833 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400834 public boolean onOptionsItemSelected(@NonNull MenuItem item) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400835 super.onOptionsItemSelected(item);
836 switch (item.getItemId()) {
837 case android.R.id.home:
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400838 presenter.chatClick();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400839 break;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400840 case R.id.menuitem_dialpad:
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400841 presenter.dialpadClick();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400842 break;
ayounes47e93992019-10-28 12:09:53 -0400843 case R.id.menuitem_video_plugins:
844 displayVideoPluginsCarousel();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400845 }
846 return true;
847 }
848
Adrien Béraud79808d02018-02-20 00:16:28 +0100849 @Override
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500850 public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400851 AppCompatActivity activity = (AppCompatActivity) getActivity();
852 ActionBar actionBar = activity == null ? null : activity.getSupportActionBar();
853 if (actionBar != null) {
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400854 if (isInPictureInPictureMode) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400855 actionBar.hide();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400856 } else {
857 mBackstackLost = true;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400858 actionBar.show();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400859 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400860 }
Adrien Béraud79808d02018-02-20 00:16:28 +0100861 presenter.pipModeChanged(isInPictureInPictureMode);
862 }
863
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400864 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400865 public void displayContactBubble(final boolean display) {
Adrien Béraudd0bd4ce2020-11-09 12:07:18 -0500866 if (binding != null)
867 binding.contactBubbleLayout.getHandler().post(() -> {
868 if (binding != null) binding.contactBubbleLayout.setVisibility(display ? View.VISIBLE : View.GONE);
869 });
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400870 }
871
872 @Override
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400873 public void displayVideoSurface(final boolean displayVideoSurface, final boolean displayPreviewContainer) {
874 binding.videoSurface.setVisibility(displayVideoSurface ? View.VISIBLE : View.GONE);
agsantosa6d68a82020-07-09 11:33:30 -0400875 if (choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -0400876 binding.pluginPreviewSurface.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
877 binding.pluginPreviewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
878 binding.previewContainer.setVisibility(View.GONE);
879 } else {
880 binding.pluginPreviewSurface.setVisibility(View.GONE);
881 binding.pluginPreviewContainer.setVisibility(View.GONE);
882 binding.previewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
883 }
Adrien Béraudace37a22018-06-22 14:58:36 -0400884 updateMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400885 }
886
887 @Override
Adrien Béraud79808d02018-02-20 00:16:28 +0100888 public void displayPreviewSurface(final boolean display) {
889 if (display) {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500890 binding.videoSurface.setZOrderOnTop(false);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500891 binding.videoSurface.setZOrderMediaOverlay(false);
Adrien Béraud79808d02018-02-20 00:16:28 +0100892 } else {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500893 binding.videoSurface.setZOrderMediaOverlay(true);
894 binding.videoSurface.setZOrderOnTop(true);
Adrien Béraud79808d02018-02-20 00:16:28 +0100895 }
896 }
897
898 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400899 public void displayHangupButton(boolean display) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400900 Log.w(TAG, "displayHangupButton " + display);
agsantosa6d68a82020-07-09 11:33:30 -0400901 display &= !choosePluginMode;
Adrien Béraud86a1e372018-11-23 23:24:30 -0500902 binding.callControlGroup.setVisibility(display ? View.VISIBLE : View.GONE);
903 binding.callHangupBtn.setVisibility(display ? View.VISIBLE : View.GONE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400904 binding.confControlGroup.setVisibility((mConferenceMode && display) ? View.VISIBLE : View.GONE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400905 }
906
907 @Override
908 public void displayDialPadKeyboard() {
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500909 KeyboardVisibilityManager.showKeyboard(getActivity(), binding.dialpadEditText, InputMethodManager.SHOW_FORCED);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400910 }
911
912 @Override
913 public void switchCameraIcon(boolean isFront) {
Adrien Béraud91f88742019-09-09 00:46:46 -0400914 binding.callCameraFlipBtn.setImageResource(isFront ? R.drawable.baseline_camera_front_24 : R.drawable.baseline_camera_rear_24);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400915 }
916
917 @Override
Adrien Béraud34a6fa22019-07-28 16:02:59 -0400918 public void updateAudioState(HardwareService.AudioState state) {
919 binding.callSpeakerBtn.setChecked(state.getOutputType() == HardwareService.AudioOutput.SPEAKERS);
920 }
921
922 @Override
Adrien Béraudd3bf4e42018-02-14 14:44:41 +0100923 public void updateMenu() {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400924 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400925 }
926
927 @Override
928 public void updateTime(final long duration) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400929 if (binding != null) {
Adrien Béraud78c547f2020-09-08 16:01:17 -0400930 if (duration <= 0)
Adrien Béraude4f901a2019-10-25 17:26:30 -0400931 binding.callStatusTxt.setText(null);
932 else
933 binding.callStatusTxt.setText(String.format(Locale.getDefault(), "%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
934 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400935 }
936
937 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400938 @SuppressLint("RestrictedApi")
939 public void updateContactBubble(@NonNull final List<SipCall> contacts) {
940 Log.w(TAG, "updateContactBubble " + contacts.size());
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400941
Adrien Béraude4f901a2019-10-25 17:26:30 -0400942 mConferenceMode = contacts.size() > 1;
943 String username = mConferenceMode ? "Conference with " + contacts.size() + " people" : contacts.get(0).getContact().getRingUsername();
944 String displayName = mConferenceMode ? null : contacts.get(0).getContact().getDisplayName();
Adrien Béraud5f8c3f72018-03-09 14:49:39 -0500945
Adrien Béraudafcdd962018-07-06 21:38:41 -0400946 boolean hasProfileName = displayName != null && !displayName.contentEquals(username);
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400947
948 AppCompatActivity activity = (AppCompatActivity) getActivity();
949 if (activity != null) {
950 ActionBar ab = activity.getSupportActionBar();
951 if (ab != null) {
952 if (hasProfileName) {
953 ab.setTitle(displayName);
954 ab.setSubtitle(username);
955 } else {
956 ab.setTitle(username);
957 ab.setSubtitle(null);
958 }
959 ab.setDisplayShowTitleEnabled(true);
960 }
961 }
962
Adrien Béraudafcdd962018-07-06 21:38:41 -0400963 if (hasProfileName) {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500964 binding.contactBubbleNumTxt.setVisibility(View.VISIBLE);
965 binding.contactBubbleTxt.setText(displayName);
966 binding.contactBubbleNumTxt.setText(username);
Adrien Béraudafcdd962018-07-06 21:38:41 -0400967 } else {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500968 binding.contactBubbleNumTxt.setVisibility(View.GONE);
969 binding.contactBubbleTxt.setText(username);
Adrien Béraudafcdd962018-07-06 21:38:41 -0400970 }
Adrien Béraud5f8c3f72018-03-09 14:49:39 -0500971
Andreas Traczykcee415a2019-12-03 15:45:04 -0500972 binding.contactBubble.setImageDrawable(
973 new AvatarDrawable.Builder()
974 .withContact(contacts.get(0).getContact())
975 .withCircleCrop(true)
976 .withPresence(false)
977 .build(getActivity())
978 );
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400979
Adrien Béraude4f901a2019-10-25 17:26:30 -0400980 if (!mConferenceMode) {
981 binding.confControlGroup.setVisibility(View.GONE);
982 } else {
983 binding.confControlGroup.setVisibility(View.VISIBLE);
ayounesc6c2c012019-11-11 11:09:51 -0500984 if (confAdapter == null) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400985 confAdapter = new ConfParticipantAdapter((view, call) -> {
Adrien Béraud78c547f2020-09-08 16:01:17 -0400986 if (presenter == null)
987 return;
988 boolean maximized = presenter.isMaximized(call);
Adrien Bérauda165bee2020-06-08 10:30:26 -0400989 PopupMenu popup = new PopupMenu(view.getContext(), view);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400990 popup.inflate(R.menu.conference_participant_actions);
Adrien Béraud78c547f2020-09-08 16:01:17 -0400991 MenuBuilder menu = (MenuBuilder) popup.getMenu();
992 MenuItem maxItem = menu.findItem(R.id.conv_contact_maximize);
993 if (maximized) {
994 maxItem.setTitle(R.string.action_call_minimize);
995 maxItem.setIcon(R.drawable.baseline_close_fullscreen_24);
996 } else {
997 maxItem.setTitle(R.string.action_call_maximize);
998 maxItem.setIcon(R.drawable.baseline_open_in_full_24);
999 }
Adrien Béraude4f901a2019-10-25 17:26:30 -04001000 popup.setOnMenuItemClickListener(item -> {
Adrien Béraud78c547f2020-09-08 16:01:17 -04001001 if (presenter == null)
1002 return false;
1003 switch (item.getItemId()) {
1004 case R.id.conv_contact_details:
1005 presenter.openParticipantContact(call);
1006 break;
1007 case R.id.conv_contact_hangup:
1008 presenter.hangupParticipant(call);
1009 break;
1010 case R.id.conv_contact_maximize:
1011 presenter.maximizeParticipant(call);
1012 break;
1013 default:
1014 return false;
1015 }
Adrien Béraude4f901a2019-10-25 17:26:30 -04001016 return true;
1017 });
Adrien Béraud78c547f2020-09-08 16:01:17 -04001018 MenuPopupHelper menuHelper = new MenuPopupHelper(view.getContext(), menu, view);
Adrien Béraude4f901a2019-10-25 17:26:30 -04001019 menuHelper.setForceShowIcon(true);
1020 menuHelper.show();
1021 });
1022 }
1023 confAdapter.updateFromCalls(contacts);
1024 if (binding.confControlGroup.getAdapter() == null)
1025 binding.confControlGroup.setAdapter(confAdapter);
Adrien Béraud3f9f6cd2018-12-12 15:05:28 -05001026 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001027 }
1028
1029 @Override
Adrien Béraud34915fb2020-08-24 17:12:03 -04001030 public void updateConfInfo(List<Conference.ParticipantInfo> info) {
1031 binding.participantLabelContainer.removeAllViews();
1032 if (!info.isEmpty()) {
1033 LayoutInflater inflater = LayoutInflater.from(binding.participantLabelContainer.getContext());
1034 for (Conference.ParticipantInfo i : info) {
1035 String displayName = i.contact.getDisplayName();
1036 if (!TextUtils.isEmpty(displayName)) {
1037 ItemParticipantLabelBinding label = ItemParticipantLabelBinding.inflate(inflater);
1038 PercentFrameLayout.LayoutParams params = new PercentFrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
1039 params.getPercentLayoutInfo().leftMarginPercent = i.x / (float) mVideoWidth;
1040 params.getPercentLayoutInfo().topMarginPercent = i.y / (float) mVideoHeight;
1041 label.participantName.setText(displayName);
1042 binding.participantLabelContainer.addView(label.getRoot(), params);
1043 }
1044 }
1045 }
1046 binding.participantLabelContainer.setVisibility(info.isEmpty() ? View.GONE : View.VISIBLE);
1047 }
1048
1049 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -04001050 public void updateCallStatus(final SipCall.CallStatus callStatus) {
1051 binding.callStatusTxt.setText(callStateToHumanState(callStatus));
1052 }
1053
1054 @Override
ayounes47e93992019-10-28 12:09:53 -04001055 public void initMenu(boolean isSpeakerOn, boolean displayFlip, boolean canDial,
1056 boolean showPluginBtn, boolean onGoingCall) {
Adrien Béraud93e887f2020-08-13 15:50:32 -04001057 if (binding != null) {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001058 binding.callCameraFlipBtn.setVisibility(displayFlip ? View.VISIBLE : View.GONE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001059 }
Romain Bertozziad8fd842016-05-11 14:30:35 -04001060 if (dialPadBtn != null) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001061 dialPadBtn.setVisible(canDial);
Romain Bertozziad8fd842016-05-11 14:30:35 -04001062 }
ayounes47e93992019-10-28 12:09:53 -04001063
ayounesc6c2c012019-11-11 11:09:51 -05001064 if (pluginsMenuBtn != null) {
ayounes47e93992019-10-28 12:09:53 -04001065 pluginsMenuBtn.setVisible(showPluginBtn);
1066 }
1067 updateMenu();
Adrien Béraud04d822c2015-04-02 17:44:36 -04001068 }
1069
1070 @Override
Adrien Béraud34a6fa22019-07-28 16:02:59 -04001071 public void initNormalStateDisplay(final boolean audioOnly, boolean isMuted) {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001072 Log.w(TAG, "initNormalStateDisplay");
Adrien Béraud86a1e372018-11-23 23:24:30 -05001073 binding.shapeRipple.stopRipple();
Pierre Ducheminbb833672018-03-09 16:18:33 -05001074
Adrien Béraud86a1e372018-11-23 23:24:30 -05001075 binding.callAcceptBtn.setVisibility(View.GONE);
1076 binding.callRefuseBtn.setVisibility(View.GONE);
1077 binding.callControlGroup.setVisibility(View.VISIBLE);
1078 binding.callHangupBtn.setVisibility(View.VISIBLE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001079
Adrien Béraud86a1e372018-11-23 23:24:30 -05001080 binding.contactBubbleLayout.setVisibility(audioOnly ? View.VISIBLE : View.GONE);
Adrien Béraudec19fad2018-12-30 16:51:05 -05001081 binding.callMicBtn.setChecked(isMuted);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001082
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001083 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001084 }
1085
1086 @Override
1087 public void initIncomingCallDisplay() {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001088 Log.w(TAG, "initIncomingCallDisplay");
1089
Adrien Béraud86a1e372018-11-23 23:24:30 -05001090 binding.callAcceptBtn.setVisibility(View.VISIBLE);
1091 binding.callRefuseBtn.setVisibility(View.VISIBLE);
1092 binding.callControlGroup.setVisibility(View.GONE);
1093 binding.callHangupBtn.setVisibility(View.GONE);
Hadrien De Sousa841d15a2017-06-02 11:52:10 -04001094
Adrien Béraud86a1e372018-11-23 23:24:30 -05001095 binding.contactBubbleLayout.setVisibility(View.VISIBLE);
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001096 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001097 }
1098
1099 @Override
1100 public void initOutGoingCallDisplay() {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001101 Log.w(TAG, "initOutGoingCallDisplay");
1102
Adrien Béraud86a1e372018-11-23 23:24:30 -05001103 binding.callAcceptBtn.setVisibility(View.GONE);
1104 binding.callRefuseBtn.setVisibility(View.VISIBLE);
1105 binding.callControlGroup.setVisibility(View.GONE);
1106 binding.callHangupBtn.setVisibility(View.GONE);
Hadrien De Sousa841d15a2017-06-02 11:52:10 -04001107
Adrien Béraud86a1e372018-11-23 23:24:30 -05001108 binding.contactBubbleLayout.setVisibility(View.VISIBLE);
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001109 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001110 }
1111
1112 @Override
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001113 public void resetPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
1114 if (previewWidth == -1 && previewHeight == -1)
1115 return;
1116 mPreviewWidth = previewWidth;
1117 mPreviewHeight = previewHeight;
1118 boolean flip = (rot % 180) != 0;
1119 binding.previewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
1120 }
1121
1122 @Override
AGS5ef482ce2020-06-12 13:28:51 -04001123 public void resetPluginPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
1124 if (previewWidth == -1 && previewHeight == -1)
1125 return;
1126 mPreviewWidth = previewWidth;
1127 mPreviewHeight = previewHeight;
1128 boolean flip = (rot % 180) != 0;
1129 binding.pluginPreviewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
1130 }
1131
1132 @Override
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001133 public void resetVideoSize(int videoWidth, int videoHeight) {
Adrien Béraudace37a22018-06-22 14:58:36 -04001134 ViewGroup rootView = (ViewGroup) getView();
1135 if (rootView == null)
1136 return;
Adrien Béraudace37a22018-06-22 14:58:36 -04001137 double videoRatio = videoWidth / (double) videoHeight;
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001138 double screenRatio = rootView.getWidth() / (double) rootView.getHeight();
Adrien Béraud86a1e372018-11-23 23:24:30 -05001139 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.videoSurface.getLayoutParams();
Adrien Béraudace37a22018-06-22 14:58:36 -04001140 int oldW = params.width;
1141 int oldH = params.height;
1142 if (videoRatio >= screenRatio) {
1143 params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
1144 params.height = (int) (videoHeight * (double) rootView.getWidth() / (double) videoWidth);
1145 } else {
1146 params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
1147 params.width = (int) (videoWidth * (double) rootView.getHeight() / (double) videoHeight);
1148 }
Thibault Wittembergb3280502016-12-16 17:34:53 -05001149
Adrien Béraudace37a22018-06-22 14:58:36 -04001150 if (oldW != params.width || oldH != params.height) {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001151 binding.videoSurface.setLayoutParams(params);
Adrien Béraudace37a22018-06-22 14:58:36 -04001152 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001153 mVideoWidth = videoWidth;
1154 mVideoHeight = videoHeight;
Adrien Béraudde0d4522018-12-12 12:11:02 -05001155 }
Adrien Béraud30532a52018-09-11 15:10:05 -04001156
Adrien Béraudde0d4522018-12-12 12:11:02 -05001157 private void configureTransform(int viewWidth, int viewHeight) {
1158 Activity activity = getActivity();
Adrien Béraud93e887f2020-08-13 15:50:32 -04001159 if (null == binding || null == activity) {
Adrien Béraudde0d4522018-12-12 12:11:02 -05001160 return;
Adrien Béraud30532a52018-09-11 15:10:05 -04001161 }
Adrien Béraudde0d4522018-12-12 12:11:02 -05001162 int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
1163 boolean rot = Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation;
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001164 // Log.w(TAG, "configureTransform " + viewWidth + "x" + viewHeight + " rot=" + rot + " mPreviewWidth=" + mPreviewWidth + " mPreviewHeight=" + mPreviewHeight);
Adrien Béraudde0d4522018-12-12 12:11:02 -05001165 Matrix matrix = new Matrix();
1166 RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
1167 float centerX = viewRect.centerX();
1168 float centerY = viewRect.centerY();
1169 if (rot) {
1170 RectF bufferRect = new RectF(0, 0, mPreviewHeight, mPreviewWidth);
1171 bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
1172 matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
1173 float scale = Math.max(
1174 (float) viewHeight / mPreviewHeight,
1175 (float) viewWidth / mPreviewWidth);
1176 matrix.postScale(scale, scale, centerX, centerY);
1177 matrix.postRotate(90 * (rotation - 2), centerX, centerY);
1178 } else if (Surface.ROTATION_180 == rotation) {
1179 matrix.postRotate(180, centerX, centerY);
Adrien Béraudace37a22018-06-22 14:58:36 -04001180 }
agsantosa6d68a82020-07-09 11:33:30 -04001181 if(!choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -04001182// binding.pluginPreviewSurface.setTransform(matrix);
1183// }
1184// else {
1185 binding.previewSurface.setTransform(matrix);
1186 }
Adrien Béraud04d822c2015-04-02 17:44:36 -04001187 }
1188
1189 @Override
Hadrien De Sousa0dc83162017-11-10 16:15:18 -05001190 public void goToConversation(String accountId, String conversationId) {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001191 Context context = requireContext();
1192 if (DeviceUtils.isTablet(context)) {
Adrien Béraud52d46a42020-05-15 14:41:08 -04001193 startActivity(new Intent(DRingService.ACTION_CONV_ACCEPT, ConversationPath.toUri(accountId, conversationId), context, HomeActivity.class));
Adrien Béraudda712a42015-11-22 23:45:26 -05001194 } else {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001195 startActivityForResult(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), context, ConversationActivity.class)
1196 .setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT), HomeActivity.REQUEST_CODE_CONVERSATION);
Adrien Béraudda712a42015-11-22 23:45:26 -05001197 }
Adrien Béraud04d822c2015-04-02 17:44:36 -04001198 }
1199
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001200 @Override
1201 public void goToAddContact(CallContact callContact) {
1202 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact),
1203 ConversationFragment.REQ_ADD_CONTACT);
1204 }
1205
Adrien Béraude4f901a2019-10-25 17:26:30 -04001206 @Override
1207 public void goToContact(String accountId, CallContact contact) {
1208 startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contact.getPrimaryNumber()))
1209 .setClass(requireContext(), ContactDetailsActivity.class));
1210 }
1211
Rayan Osseiran38206c62019-05-15 14:49:03 -04001212 /**
1213 * Checks if permissions are accepted for camera and microphone. Takes into account whether call is incoming and outgoing, and requests permissions if not available.
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001214 * Initializes the call if permissions are accepted.
Rayan Osseiran38206c62019-05-15 14:49:03 -04001215 *
1216 * @param isIncoming true if call is incoming, false for outgoing
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001217 * @see #initializeCall(boolean) initializeCall
Rayan Osseiran38206c62019-05-15 14:49:03 -04001218 */
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001219 @Override
1220 public void prepareCall(boolean isIncoming) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001221 boolean audioGranted = mDeviceRuntimeService.hasAudioPermission();
1222 boolean audioOnly;
1223 int permissionType;
1224
1225 if (isIncoming) {
1226 audioOnly = presenter.isAudioOnly();
1227 permissionType = REQUEST_PERMISSION_INCOMING;
Rayan Osseiran38206c62019-05-15 14:49:03 -04001228 } else {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001229 Bundle args = getArguments();
1230 audioOnly = args != null && args.getBoolean(KEY_AUDIO_ONLY);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001231 permissionType = REQUEST_PERMISSION_OUTGOING;
1232 }
1233 if (!audioOnly) {
1234 boolean videoGranted = mDeviceRuntimeService.hasVideoPermission();
1235
Adrien Bérauda0226ff2019-11-21 15:24:42 -05001236 if ((!audioGranted || !videoGranted) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001237 ArrayList<String> perms = new ArrayList<>();
1238 if (!videoGranted) {
1239 perms.add(Manifest.permission.CAMERA);
1240 }
1241 if (!audioGranted) {
1242 perms.add(Manifest.permission.RECORD_AUDIO);
1243 }
1244 requestPermissions(perms.toArray(new String[perms.size()]), permissionType);
1245 } else if (audioGranted && videoGranted) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001246 initializeCall(isIncoming);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001247 }
1248 } else {
Adrien Bérauda0226ff2019-11-21 15:24:42 -05001249 if (!audioGranted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001250 requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, permissionType);
1251 } else if (audioGranted) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001252 initializeCall(isIncoming);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001253 }
1254 }
Rayan Osseiran38206c62019-05-15 14:49:03 -04001255 }
1256
1257 /**
1258 * Starts a call. Takes into account whether call is incoming or outgoing.
1259 *
1260 * @param isIncoming true if call is incoming, false for outgoing
1261 */
Adrien Béraude4f901a2019-10-25 17:26:30 -04001262 private void initializeCall(boolean isIncoming) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001263 if (isIncoming) {
1264 presenter.acceptCall();
1265 } else {
1266 Bundle args;
1267 args = getArguments();
1268 if (args != null) {
1269 presenter.initOutGoing(getArguments().getString(KEY_ACCOUNT_ID),
1270 getArguments().getString(ConversationFragment.KEY_CONTACT_RING_ID),
1271 getArguments().getBoolean(KEY_AUDIO_ONLY));
1272 }
1273 }
1274 }
1275
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001276 @Override
1277 public void finish() {
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001278 Activity activity = getActivity();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -04001279 if (activity != null) {
Adrien Béraudb46fd322020-09-02 17:18:28 -04001280 activity.finishAndRemoveTask();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -04001281 if (mBackstackLost) {
Adrien Béraudb46fd322020-09-02 17:18:28 -04001282 startActivity(Intent.makeMainActivity(new ComponentName(activity, HomeActivity.class)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
Rayan Osseiranf7dfe232019-06-06 10:26:10 -04001283 }
1284 }
Alexandre Lision1532d952016-11-17 09:41:00 -05001285 }
1286
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001287 public void speakerClicked() {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001288 presenter.speakerClick(binding.callSpeakerBtn.isChecked());
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001289 }
1290
Adrien Béraudade9bee2019-12-02 17:13:26 -05001291 private void startScreenShare(MediaProjection mediaProjection) {
Adrien Béraud20bd7232020-03-16 11:33:23 -04001292 if (presenter.startScreenShare(mediaProjection)) {
agsantosa6d68a82020-07-09 11:33:30 -04001293 if(choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -04001294 binding.pluginPreviewSurface.setVisibility(View.GONE);
1295 } else {
1296 binding.previewSurface.setVisibility(View.GONE);
1297 }
Adrien Béraud20bd7232020-03-16 11:33:23 -04001298 } else {
1299 Toast.makeText(requireContext(), "Can't start screen sharing", Toast.LENGTH_SHORT).show();
1300 }
Adrien Béraudade9bee2019-12-02 17:13:26 -05001301 }
1302
1303 private void stopShareScreen() {
Adrien Béraud496e49a2020-08-13 22:31:05 -04001304 binding.previewSurface.setVisibility(View.VISIBLE);
Adrien Béraudade9bee2019-12-02 17:13:26 -05001305 presenter.stopScreenShare();
1306 }
1307
1308 public void shareScreenClicked(boolean checked) {
1309 if (!checked) {
1310 stopShareScreen();
1311 } else {
1312 startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_SHARE);
1313 }
1314 }
1315
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001316 public void micClicked() {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001317 presenter.muteMicrophoneToggled(binding.callMicBtn.isChecked());
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001318 }
1319
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001320 public void hangUpClicked() {
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -04001321 presenter.hangupCall();
Alexandre Lision1532d952016-11-17 09:41:00 -05001322 }
1323
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001324 public void refuseClicked() {
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -04001325 presenter.refuseCall();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001326 }
1327
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001328 public void acceptClicked() {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001329 prepareCall(true);
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001330 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001331
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001332 public void cameraFlip() {
1333 presenter.switchVideoInputClick();
1334 }
1335
Adrien Béraude4f901a2019-10-25 17:26:30 -04001336 public void addParticipant() {
1337 presenter.startAddParticipant();
1338 }
1339
1340 @Override
1341 public void startAddParticipant(String conferenceId) {
1342 startActivityForResult(
1343 new Intent(Intent.ACTION_PICK)
1344 .setClass(requireActivity(), ConversationSelectionActivity.class)
1345 .putExtra(KEY_CONF_ID, conferenceId),
1346 CallFragment.REQUEST_CODE_ADD_PARTICIPANT);
1347 }
agsantos4f7b5a12020-07-08 16:18:07 -04001348
1349 @Override
agsantos5f68e512020-10-26 11:48:52 -04001350 public void toggleCallMediaHandler(String id, String callId, boolean toggle) {
1351 Ringservice.toggleCallMediaHandler(id, callId, toggle);
ayounes47e93992019-10-28 12:09:53 -04001352 }
1353
ayounes019267f2020-01-13 15:14:08 -05001354 public Map<String, String> getCallMediaHandlerDetails(String id) {
1355 return Ringservice.getCallMediaHandlerDetails(id).toNative();
ayounesc6c2c012019-11-11 11:09:51 -05001356 }
ayounes81087472019-11-08 15:26:05 -05001357
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001358 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001359 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001360 presenter.positiveButtonClicked();
1361 }
1362
1363 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001364 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001365 presenter.negativeButtonClicked();
1366 }
1367
1368 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001369 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001370 presenter.toggleButtonClicked();
1371 }
Rayan Osseiran38206c62019-05-15 14:49:03 -04001372
ayounesc6c2c012019-11-11 11:09:51 -05001373 public boolean displayPluginsButton() {
agsantosa6d68a82020-07-09 11:33:30 -04001374 return getPluginsEnabled();
ayounesc6c2c012019-11-11 11:09:51 -05001375 }
1376
ayounes47e93992019-10-28 12:09:53 -04001377 @Override
1378 public void onConfigurationChanged(@NonNull Configuration newConfig) {
1379 super.onConfigurationChanged(newConfig);
agsantos00e3a9d2020-07-06 15:08:43 -04001380 // Reset the padding of the RecyclerPicker on each
ayounesc6c2c012019-11-11 11:09:51 -05001381 rp.setFirstLastElementsWidths(112, 112);
ayounes47e93992019-10-28 12:09:53 -04001382 binding.recyclerPicker.setVisibility(View.GONE);
agsantosa6d68a82020-07-09 11:33:30 -04001383 if (choosePluginMode) {
ayounes47e93992019-10-28 12:09:53 -04001384 displayHangupButton(false);
1385 binding.recyclerPicker.setVisibility(View.VISIBLE);
ayounesc6c2c012019-11-11 11:09:51 -05001386 movePreview(true);
1387 if (previousPluginPosition != -1) {
ayounes47e93992019-10-28 12:09:53 -04001388 rp.scrollToPosition(previousPluginPosition);
1389 }
1390 } else {
ayounesc6c2c012019-11-11 11:09:51 -05001391 movePreview(false);
ayounes47e93992019-10-28 12:09:53 -04001392 displayHangupButton(true);
1393 }
1394 }
1395
ayounesc6c2c012019-11-11 11:09:51 -05001396 public void toggleVideoPluginsCarousel(boolean toggle) {
agsantosa6d68a82020-07-09 11:33:30 -04001397 if (choosePluginMode) {
Adrien Béraud93e887f2020-08-13 15:50:32 -04001398 if (toggle) {
ayounesc6c2c012019-11-11 11:09:51 -05001399 binding.recyclerPicker.setVisibility(View.VISIBLE);
1400 movePreview(true);
1401 } else {
1402 binding.recyclerPicker.setVisibility(View.INVISIBLE);
1403 movePreview(false);
1404 }
1405 }
ayounesc6c2c012019-11-11 11:09:51 -05001406 }
1407
1408 public void movePreview(boolean up) {
1409 // Move the preview container (cardview) by a certain margin
1410 if(up) {
1411 animation.setIntValues(12, 128);
1412 } else {
1413 animation.setIntValues(128, 12);
1414 }
1415 animation.start();
1416 }
1417
1418 /**
1419 * Function that is called to show/hide the plugins recycler viewer and update UI
1420 */
ayounes47e93992019-10-28 12:09:53 -04001421 public void displayVideoPluginsCarousel() {
agsantosa6d68a82020-07-09 11:33:30 -04001422 choosePluginMode = !choosePluginMode;
AGS5ef482ce2020-06-12 13:28:51 -04001423
ayounes81087472019-11-08 15:26:05 -05001424 Context context = requireActivity();
1425
ayounes019267f2020-01-13 15:14:08 -05001426 // Create callMediaHandlers and videoPluginsItems in a lazy manner
ayounesc6c2c012019-11-11 11:09:51 -05001427 if (pluginsModeFirst) {
1428 // Init
ayounes019267f2020-01-13 15:14:08 -05001429 callMediaHandlers = Ringservice.listCallMediaHandlers();
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001430 List<Drawable> videoPluginsItems = new ArrayList<>(callMediaHandlers.size() + 1);
ayounes47e93992019-10-28 12:09:53 -04001431
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001432 videoPluginsItems.add(context.getDrawable(R.drawable.baseline_cancel_24));
ayounes019267f2020-01-13 15:14:08 -05001433 // Search for plugin call media handlers icons
1434 // If a call media handler doesn't have an icon use a standard android icon
1435 for (String callMediaHandler : callMediaHandlers) {
1436 Map<String, String> details = getCallMediaHandlerDetails(callMediaHandler);
agsantos4d495c92020-07-10 12:01:36 -04001437 String drawablePath = details.get("iconPath");
1438 Drawable handlerIcon = StringUtils.isEmpty(drawablePath) ? null : Drawable.createFromPath(details.get("iconPath"));
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001439 if (handlerIcon == null) {
1440 handlerIcon = context.getDrawable(R.drawable.ic_jami);
ayounes47e93992019-10-28 12:09:53 -04001441 }
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001442 videoPluginsItems.add(handlerIcon);
ayounes47e93992019-10-28 12:09:53 -04001443 }
1444
1445 rp.updateData(videoPluginsItems);
1446
ayounesc6c2c012019-11-11 11:09:51 -05001447 pluginsModeFirst = false;
1448 }
1449
agsantosa6d68a82020-07-09 11:33:30 -04001450 if (choosePluginMode) {
ayounesc6c2c012019-11-11 11:09:51 -05001451 // hide hang up button and other call buttons
1452 displayHangupButton(false);
1453 // Display the plugins recyclerpicker
1454 binding.recyclerPicker.setVisibility(View.VISIBLE);
1455 movePreview(true);
1456
1457 // Start loading the first or previous plugin if one was active
ayounes019267f2020-01-13 15:14:08 -05001458 if(callMediaHandlers.size() > 0) {
ayounesc6c2c012019-11-11 11:09:51 -05001459 // If no previous plugin was active, take the first, else previous
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001460 int position;
1461 if(previousPluginPosition < 1) {
1462 rp.scrollToPosition(1);
1463 position = 1;
1464 previousPluginPosition = 1;
1465 } else {
1466 position = previousPluginPosition;
1467 }
1468 if (position > 0) {
1469 String callMediaId = callMediaHandlers.get(position-1);
agsantos4d495c92020-07-10 12:01:36 -04001470 presenter.startPlugin(callMediaId);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001471 }
ayounesc6c2c012019-11-11 11:09:51 -05001472 }
1473
ayounes47e93992019-10-28 12:09:53 -04001474 } else {
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001475 if (previousPluginPosition > 0) {
ayounes019267f2020-01-13 15:14:08 -05001476 String callMediaId = callMediaHandlers.
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001477 get(previousPluginPosition-1);
ayounes81087472019-11-08 15:26:05 -05001478
agsantos4f7b5a12020-07-08 16:18:07 -04001479 presenter.toggleCallMediaHandler(callMediaId, false);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001480 rp.scrollToPosition(previousPluginPosition);
ayounes47e93992019-10-28 12:09:53 -04001481 }
agsantos4d495c92020-07-10 12:01:36 -04001482 presenter.stopPlugin();
ayounes47e93992019-10-28 12:09:53 -04001483 binding.recyclerPicker.setVisibility(View.GONE);
ayounesc6c2c012019-11-11 11:09:51 -05001484 movePreview(false);
ayounes47e93992019-10-28 12:09:53 -04001485 displayHangupButton(true);
1486 }
agsantos4d495c92020-07-10 12:01:36 -04001487
1488 //change preview image
1489 displayVideoSurface(true,true);
ayounes47e93992019-10-28 12:09:53 -04001490 }
1491
ayounesc6c2c012019-11-11 11:09:51 -05001492 /**
1493 * Called whenever a plugin drawable in the recycler picker is clicked or scrolled to
1494 * @param position
1495 */
ayounes47e93992019-10-28 12:09:53 -04001496 @Override
1497 public void onItemSelected(int position) {
1498 Log.i(TAG, "selected position: " + position);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001499 /** If there was a different plugin before, unload it
1500 * If previousPluginPosition = -1 or 0, there was no plugin
1501 */
1502 if (previousPluginPosition > 0) {
1503 String callMediaId = callMediaHandlers.get(previousPluginPosition-1);
agsantos4f7b5a12020-07-08 16:18:07 -04001504 presenter.toggleCallMediaHandler(callMediaId, false);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001505 }
1506
1507 if (position > 0) {
1508 previousPluginPosition = position;
1509 String callMediaId = callMediaHandlers.get(position-1);
agsantos4f7b5a12020-07-08 16:18:07 -04001510 presenter.toggleCallMediaHandler(callMediaId, true);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001511 }
1512 }
1513
1514
1515 /**
1516 * Called whenever a plugin drawable in the recycler picker is clicked
1517 * @param position
1518 */
1519 @Override
1520 public void onItemClicked(int position) {
1521 Log.i(TAG, "selected position: " + position);
1522 if (position == 0) {
ayounes47e93992019-10-28 12:09:53 -04001523 /** If there was a different plugin before, unload it
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001524 * If previousPluginPosition = -1 or 0, there was no plugin
ayounes47e93992019-10-28 12:09:53 -04001525 */
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001526 if (previousPluginPosition > 0) {
1527 String callMediaId = callMediaHandlers.get(previousPluginPosition-1);
agsantos4f7b5a12020-07-08 16:18:07 -04001528 presenter.toggleCallMediaHandler(callMediaId, false);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001529 rp.scrollToPosition(previousPluginPosition);
ayounes47e93992019-10-28 12:09:53 -04001530 }
1531
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001532 CallActivity callActivity = (CallActivity) getActivity();
1533 callActivity.showSystemUI();
1534
1535 toggleVideoPluginsCarousel(false);
1536 displayVideoPluginsCarousel();
ayounes47e93992019-10-28 12:09:53 -04001537 }
1538 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001539}