blob: f89298709b65a93c5f5ddfc064833f2762a97840 [file] [log] [blame]
Adrien Béraud04d822c2015-04-02 17:44:36 -04001/*
Sébastien Blinab53ada2019-01-02 17:23:00 -05002 * Copyright (C) 2004-2019 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éraud34915fb2020-08-24 17:12:03 -040071import android.widget.TextView;
Adrien Béraud20bd7232020-03-16 11:33:23 -040072import android.widget.Toast;
Adrien Béraud04d822c2015-04-02 17:44:36 -040073
Rayan Osseiran3dd04662019-06-28 16:47:48 -040074import androidx.annotation.NonNull;
75import androidx.annotation.Nullable;
76import androidx.appcompat.app.ActionBar;
77import androidx.appcompat.app.AppCompatActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -040078import androidx.appcompat.view.menu.MenuBuilder;
79import androidx.appcompat.view.menu.MenuPopupHelper;
80import androidx.appcompat.widget.PopupMenu;
Rayan Osseiran3dd04662019-06-28 16:47:48 -040081import androidx.databinding.DataBindingUtil;
Adrien Béraude4f901a2019-10-25 17:26:30 -040082import androidx.fragment.app.FragmentActivity;
Adrien Béraud34915fb2020-08-24 17:12:03 -040083import androidx.percentlayout.widget.PercentFrameLayout;
Rayan Osseiran3dd04662019-06-28 16:47:48 -040084
Pierre Ducheminbb833672018-03-09 16:18:33 -050085import com.rodolfonavalon.shaperipplelibrary.model.Circle;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040086
Adrien Béraud79808d02018-02-20 00:16:28 +010087import java.util.ArrayList;
Adrien Béraude4f901a2019-10-25 17:26:30 -040088import java.util.List;
Romain Bertozzi64a66782016-08-02 12:10:38 -040089import java.util.Locale;
ayounes81087472019-11-08 15:26:05 -050090import java.util.Map;
Adrien Béraud79808d02018-02-20 00:16:28 +010091import java.util.Random;
Adrien Béraud04d822c2015-04-02 17:44:36 -040092
Rayan Osseiran38206c62019-05-15 14:49:03 -040093import javax.inject.Inject;
94
Adrien Béraud162427f2016-04-12 18:04:08 -040095import cx.ring.R;
Adrien Bérauda0226ff2019-11-21 15:24:42 -050096import cx.ring.adapters.ConfParticipantAdapter;
Adrien Béraude4f901a2019-10-25 17:26:30 -040097import cx.ring.application.JamiApplication;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -040098import cx.ring.call.CallPresenter;
99import cx.ring.call.CallView;
Rayan Osseiran3dd04662019-06-28 16:47:48 -0400100import cx.ring.client.CallActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400101import cx.ring.client.ContactDetailsActivity;
Adrien Béraud162427f2016-04-12 18:04:08 -0400102import cx.ring.client.ConversationActivity;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400103import cx.ring.client.ConversationSelectionActivity;
Thibault Wittemberg4f33d072016-10-06 17:11:41 -0400104import cx.ring.client.HomeActivity;
ayounes019267f2020-01-13 15:14:08 -0500105import cx.ring.daemon.Ringservice;
Adrien Béraud86a1e372018-11-23 23:24:30 -0500106import cx.ring.databinding.FragCallBinding;
Adrien Béraud34915fb2020-08-24 17:12:03 -0400107import cx.ring.databinding.ItemParticipantLabelBinding;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400108import cx.ring.model.CallContact;
Adrien Béraud34915fb2020-08-24 17:12:03 -0400109import cx.ring.model.Conference;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400110import cx.ring.model.SipCall;
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500111import cx.ring.mvp.BaseSupportFragment;
ayounesc6c2c012019-11-11 11:09:51 -0500112import cx.ring.plugins.PluginUtils;
113import cx.ring.plugins.RecyclerPicker.RecyclerPicker;
114import cx.ring.plugins.RecyclerPicker.RecyclerPickerLayoutManager;
Alexandre Lision5da46fa2017-08-09 10:25:50 -0400115import cx.ring.service.DRingService;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400116import cx.ring.services.DeviceRuntimeService;
Adrien Béraud34a6fa22019-07-28 16:02:59 -0400117import cx.ring.services.HardwareService;
Adrien Béraud79808d02018-02-20 00:16:28 +0100118import cx.ring.services.NotificationService;
ayounes019267f2020-01-13 15:14:08 -0500119import cx.ring.settings.pluginssettings.PluginDetails;
Alexandre Lision4865f7d2016-11-16 18:03:35 -0500120import cx.ring.utils.ActionHelper;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400121import cx.ring.utils.ContentUriHandler;
122import cx.ring.utils.ConversationPath;
Pierre Duchemin42788c32018-03-08 16:21:15 -0500123import cx.ring.utils.DeviceUtils;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400124import cx.ring.utils.KeyboardVisibilityManager;
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -0500125import cx.ring.utils.MediaButtonsHelper;
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -0400126import cx.ring.utils.StringUtils;
Adrien Béraud8f9d2702018-09-16 18:24:01 -0400127import cx.ring.views.AvatarDrawable;
Adrien Béraud2c378b32018-07-11 15:24:02 -0400128import io.reactivex.disposables.CompositeDisposable;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400129
agsantos00e3a9d2020-07-06 15:08:43 -0400130import static cx.ring.daemon.Ringservice.getPluginsEnabled;
agsantos00e3a9d2020-07-06 15:08:43 -0400131
ayounes47e93992019-10-28 12:09:53 -0400132public class CallFragment extends BaseSupportFragment<CallPresenter> implements CallView, MediaButtonsHelper.MediaButtonsHelperCallback, RecyclerPickerLayoutManager.ItemSelectedListener {
Adrien Béraud04d822c2015-04-02 17:44:36 -0400133
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400134 public static final String TAG = CallFragment.class.getSimpleName();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400135
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400136 public static final String ACTION_PLACE_CALL = "PLACE_CALL";
137 public static final String ACTION_GET_CALL = "GET_CALL";
Adrien Béraud04d822c2015-04-02 17:44:36 -0400138
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400139 public static final String KEY_ACTION = "action";
140 public static final String KEY_ACCOUNT_ID = "accountId";
141 public static final String KEY_CONF_ID = "confId";
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500142 public static final String KEY_AUDIO_ONLY = "AUDIO_ONLY";
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400143
Adrien Béraude4f901a2019-10-25 17:26:30 -0400144 private static final int REQUEST_CODE_ADD_PARTICIPANT = 6;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400145 private static final int REQUEST_PERMISSION_INCOMING = 1003;
146 private static final int REQUEST_PERMISSION_OUTGOING = 1004;
Adrien Béraudade9bee2019-12-02 17:13:26 -0500147 private static final int REQUEST_CODE_SCREEN_SHARE = 7;
Adrien Béraude4f901a2019-10-25 17:26:30 -0400148
Adrien Béraud86a1e372018-11-23 23:24:30 -0500149 private FragCallBinding binding;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400150 private OrientationEventListener mOrientationListener;
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400151
Romain Bertozziad8fd842016-05-11 14:30:35 -0400152 private MenuItem dialPadBtn = null;
ayounes47e93992019-10-28 12:09:53 -0400153 private MenuItem pluginsMenuBtn = null;
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400154 private boolean restartVideo = false;
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400155 private boolean restartPreview = false;
Rayan Osseirande9ac142019-07-02 13:01:32 -0400156 private PowerManager.WakeLock mScreenWakeLock = null;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400157 private int mCurrentOrientation = 0;
158
159 private int mVideoWidth = -1;
160 private int mVideoHeight = -1;
Adrien Béraudde0d4522018-12-12 12:11:02 -0500161 private int mPreviewWidth = 720, mPreviewHeight = 1280;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400162 private int mPreviewSurfaceWidth = 0, mPreviewSurfaceHeight = 0;
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400163
Adrien Béraudade9bee2019-12-02 17:13:26 -0500164 private MediaProjectionManager mProjectionManager;
165
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400166 private boolean mBackstackLost = false;
167
Adrien Béraude4f901a2019-10-25 17:26:30 -0400168 private ConfParticipantAdapter confAdapter = null;
169 private boolean mConferenceMode = false;
agsantosa6d68a82020-07-09 11:33:30 -0400170 private boolean choosePluginMode = false;
171 public boolean isChoosePluginMode() {
172 return choosePluginMode;
173 }
ayounes81087472019-11-08 15:26:05 -0500174 private boolean pluginsModeFirst = true;
ayounes019267f2020-01-13 15:14:08 -0500175 private List<String> callMediaHandlers;
ayounes47e93992019-10-28 12:09:53 -0400176 private int previousPluginPosition = -1;
177 private RecyclerPicker rp;
ayounesc6c2c012019-11-11 11:09:51 -0500178 private boolean toggleVideoPluginsCarousel = true;
179 private final ValueAnimator animation = new ValueAnimator();
180
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400181 private PointF previewDrag = null;
182 private final ValueAnimator previewSnapAnimation = new ValueAnimator();
183 private final int[] previewMargins = new int[4];
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400184 private float previewHiddenState = 0;
185 private enum PreviewPosition {LEFT, RIGHT}
186 private PreviewPosition previewPosition = PreviewPosition.RIGHT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400187
Rayan Osseiran38206c62019-05-15 14:49:03 -0400188 @Inject
189 DeviceRuntimeService mDeviceRuntimeService;
190
Adrien Béraud2c378b32018-07-11 15:24:02 -0400191 private final CompositeDisposable mCompositeDisposable = new CompositeDisposable();
192
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500193 public static CallFragment newInstance(@NonNull String action, @Nullable String accountID, @Nullable String contactRingId, boolean audioOnly) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400194 Bundle bundle = new Bundle();
195 bundle.putString(KEY_ACTION, action);
196 bundle.putString(KEY_ACCOUNT_ID, accountID);
Hadrien De Sousa0dc83162017-11-10 16:15:18 -0500197 bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactRingId);
Hadrien De Sousa203164c2017-12-05 17:41:42 -0500198 bundle.putBoolean(KEY_AUDIO_ONLY, audioOnly);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400199 CallFragment countDownFragment = new CallFragment();
200 countDownFragment.setArguments(bundle);
201 return countDownFragment;
202 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500203
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400204 public static CallFragment newInstance(@NonNull String action, @Nullable String confId) {
205 Bundle bundle = new Bundle();
206 bundle.putString(KEY_ACTION, action);
207 bundle.putString(KEY_CONF_ID, confId);
208 CallFragment countDownFragment = new CallFragment();
209 countDownFragment.setArguments(bundle);
210 return countDownFragment;
211 }
212
Rayan Osseiran6f415662019-10-25 14:23:25 -0400213 public static int callStateToHumanState(final SipCall.CallStatus state) {
Loïc Siret0202fbf2017-09-28 16:34:28 -0400214 switch (state) {
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400215 case SEARCHING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400216 return R.string.call_human_state_searching;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400217 case CONNECTING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400218 return R.string.call_human_state_connecting;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400219 case RINGING:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400220 return R.string.call_human_state_ringing;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400221 case CURRENT:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400222 return R.string.call_human_state_current;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400223 case HUNGUP:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400224 return R.string.call_human_state_hungup;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400225 case BUSY:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400226 return R.string.call_human_state_busy;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400227 case FAILURE:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400228 return R.string.call_human_state_failure;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400229 case HOLD:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400230 return R.string.call_human_state_hold;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400231 case UNHOLD:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400232 return R.string.call_human_state_unhold;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400233 case OVER:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400234 return R.string.call_human_state_over;
Adrien Bérauda3f0b4b2018-08-09 11:41:53 -0400235 case NONE:
Loïc Siret0202fbf2017-09-28 16:34:28 -0400236 default:
Adrien Béraude4f901a2019-10-25 17:26:30 -0400237 return R.string.call_human_state_none;
Loïc Siret0202fbf2017-09-28 16:34:28 -0400238 }
239 }
240
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400241 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400242 protected void initPresenter(CallPresenter presenter) {
243 super.initPresenter(presenter);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400244 Bundle args = getArguments();
245 if (args != null) {
246 String action = args.getString(KEY_ACTION);
247 if (action != null) {
248 if (action.equals(ACTION_PLACE_CALL)) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -0400249 prepareCall(false);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400250 } else if (action.equals(ACTION_GET_CALL) || action.equals(CallActivity.ACTION_CALL_ACCEPT)) {
Rayan Osseiraned9feeb2019-07-05 16:04:30 -0400251 presenter.initIncomingCall(getArguments().getString(KEY_CONF_ID), action.equals(ACTION_GET_CALL));
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400252 }
Pierre Duchemin45707ca2018-01-15 15:05:23 -0500253 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500254 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500255 }
256
Adrien Béraud79808d02018-02-20 00:16:28 +0100257 public void onUserLeave() {
258 presenter.requestPipMode();
259 }
260
261 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400262 public void enterPipMode(String callId) {
Adrien Béraud79808d02018-02-20 00:16:28 +0100263 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
264 return;
265 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400266 Context context = requireContext();
Adrien Béraud79808d02018-02-20 00:16:28 +0100267 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
268 PictureInPictureParams.Builder paramBuilder = new PictureInPictureParams.Builder();
Adrien Béraud86a1e372018-11-23 23:24:30 -0500269 if (binding.videoSurface.getVisibility() == View.VISIBLE) {
Adrien Béraud79808d02018-02-20 00:16:28 +0100270 int[] l = new int[2];
Adrien Béraud86a1e372018-11-23 23:24:30 -0500271 binding.videoSurface.getLocationInWindow(l);
Adrien Béraud79808d02018-02-20 00:16:28 +0100272 int x = l[0];
273 int y = l[1];
Adrien Béraud86a1e372018-11-23 23:24:30 -0500274 int w = binding.videoSurface.getWidth();
275 int h = binding.videoSurface.getHeight();
Adrien Béraud79808d02018-02-20 00:16:28 +0100276 Rect videoBounds = new Rect(x, y, x + w, y + h);
277 paramBuilder.setAspectRatio(new Rational(w, h));
278 paramBuilder.setSourceRectHint(videoBounds);
279 }
280 ArrayList<RemoteAction> actions = new ArrayList<>(1);
281 actions.add(new RemoteAction(
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400282 Icon.createWithResource(context, R.drawable.baseline_call_end_24),
Adrien Béraud79808d02018-02-20 00:16:28 +0100283 getString(R.string.action_call_hangup),
284 getString(R.string.action_call_hangup),
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400285 PendingIntent.getService(context, new Random().nextInt(),
Adrien Béraud79808d02018-02-20 00:16:28 +0100286 new Intent(DRingService.ACTION_CALL_END)
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400287 .setClass(context, DRingService.class)
Adrien Béraude4f901a2019-10-25 17:26:30 -0400288 .putExtra(NotificationService.KEY_CALL_ID, callId), PendingIntent.FLAG_ONE_SHOT)));
Adrien Béraud79808d02018-02-20 00:16:28 +0100289 paramBuilder.setActions(actions);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400290 requireActivity().enterPictureInPictureMode(paramBuilder.build());
291 } else if (DeviceUtils.isTv(context)) {
292 requireActivity().enterPictureInPictureMode();
Adrien Béraud79808d02018-02-20 00:16:28 +0100293 }
294 }
295
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500296 @Override
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400297 public void onStart() {
298 super.onStart();
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400299 if (restartVideo && restartPreview) {
300 displayVideoSurface(true, !presenter.isPipMode());
301 restartVideo = false;
302 restartPreview = false;
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400303 } else if (restartVideo) {
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400304 displayVideoSurface(true, false);
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400305 restartVideo = false;
306 }
307 }
308
309 @Override
310 public void onStop() {
311 super.onStop();
Adrien Béraud86a1e372018-11-23 23:24:30 -0500312 if (binding.videoSurface.getVisibility() == View.VISIBLE) {
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400313 restartVideo = true;
314 }
agsantosa6d68a82020-07-09 11:33:30 -0400315 if (!choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -0400316 if (binding.previewContainer.getVisibility() == View.VISIBLE) {
317 restartPreview = true;
318 }
319 }else {
320 if (binding.pluginPreviewContainer.getVisibility() == View.VISIBLE) {
321 restartPreview = true;
322 }
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400323 }
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400324 }
325
Adrien Béraud86a1e372018-11-23 23:24:30 -0500326 @Nullable
327 @Override
Adrien Béraudc14d55d2019-01-02 16:33:40 -0500328 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
AGS5ef482ce2020-06-12 13:28:51 -0400329
Adrien Béraud7307cd52020-04-13 23:29:11 -0400330 ((JamiApplication) requireActivity().getApplication()).getInjectionComponent().inject(this);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500331 binding = DataBindingUtil.inflate(inflater, R.layout.frag_call, container, false);
332 binding.setPresenter(this);
ayounes47e93992019-10-28 12:09:53 -0400333 rp = new RecyclerPicker(requireActivity(),
334 binding.recyclerPicker,
ayounesc6c2c012019-11-11 11:09:51 -0500335 R.layout.item_picker,
ayounes47e93992019-10-28 12:09:53 -0400336 LinearLayout.HORIZONTAL, this);
ayounesc6c2c012019-11-11 11:09:51 -0500337 rp.setFirstLastElementsWidths(112, 112);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500338 return binding.getRoot();
339 }
340
Adrien Béraudde0d4522018-12-12 12:11:02 -0500341 private TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
342 @Override
343 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400344 mPreviewSurfaceWidth = width;
345 mPreviewSurfaceHeight = height;
Adrien Béraudde0d4522018-12-12 12:11:02 -0500346 presenter.previewVideoSurfaceCreated(binding.previewSurface);
347 }
348
349 @Override
350 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400351 mPreviewSurfaceWidth = width;
352 mPreviewSurfaceHeight = height;
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400353 configurePreview(width, 1);
Adrien Béraudde0d4522018-12-12 12:11:02 -0500354 }
355
356 @Override
357 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
358 presenter.previewVideoSurfaceDestroyed();
359 return true;
360 }
361
362 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400363 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
364 }
Adrien Béraudde0d4522018-12-12 12:11:02 -0500365 };
366
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400367 /**
368 * @param hiddenState 0.f if fully shown, 1.f if fully hidden.
369 */
370 private void setPreviewDragHiddenState(float hiddenState) {
371 binding.previewSurface.setAlpha(1.f - (3 * hiddenState / 4));
AGS5ef482ce2020-06-12 13:28:51 -0400372 binding.pluginPreviewSurface.setAlpha(1.f - (3 * hiddenState / 4));
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400373 binding.previewHandle.setAlpha(hiddenState);
AGS5ef482ce2020-06-12 13:28:51 -0400374 binding.pluginPreviewHandle.setAlpha(hiddenState);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400375 }
376
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400377 @SuppressLint("ClickableViewAccessibility")
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400378 @Override
Adrien Béraudc14d55d2019-01-02 16:33:40 -0500379 public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400380 setHasOptionsMenu(true);
Hadrien De Sousa73d6dd72017-09-07 10:54:51 -0400381 super.onViewCreated(view, savedInstanceState);
Adrien Béraud79808d02018-02-20 00:16:28 +0100382 mCurrentOrientation = getResources().getConfiguration().orientation;
ayounesc6c2c012019-11-11 11:09:51 -0500383 float dpRatio = requireActivity().getResources().getDisplayMetrics().density;
384
385 animation.setDuration(150);
386 animation.addUpdateListener(valueAnimator -> {
387 int upBy = (int) valueAnimator.getAnimatedValue();
388 RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) binding.previewContainer.getLayoutParams();
389 layoutParams.setMargins(0, 0, 0, (int) (upBy * dpRatio));
390 binding.previewContainer.setLayoutParams(layoutParams);
391 });
Adrien Béraud04d822c2015-04-02 17:44:36 -0400392
Adrien Béraude4f901a2019-10-25 17:26:30 -0400393 FragmentActivity activity = getActivity();
394 if (activity != null) {
395 activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
396 if (activity instanceof AppCompatActivity) {
397 AppCompatActivity ac_activity = (AppCompatActivity) activity;
398 ActionBar ab = ac_activity.getSupportActionBar();
399 if (ab != null) {
400 ab.setHomeAsUpIndicator(R.drawable.baseline_chat_24);
401 ab.setDisplayHomeAsUpEnabled(true);
402 }
403 }
404 }
405
Adrien Béraudade9bee2019-12-02 17:13:26 -0500406 mProjectionManager = (MediaProjectionManager) requireContext().getSystemService(Context.MEDIA_PROJECTION_SERVICE);
407
Adrien Béraude4f901a2019-10-25 17:26:30 -0400408 PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
409 if (powerManager != null) {
410 mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
411 mScreenWakeLock.setReferenceCounted(false);
412 if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
413 mScreenWakeLock.acquire();
414 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400415 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500416
Adrien Béraud86a1e372018-11-23 23:24:30 -0500417 binding.videoSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
418 binding.videoSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400419 @Override
420 public void surfaceCreated(SurfaceHolder holder) {
421 presenter.videoSurfaceCreated(holder);
422 }
423
424 @Override
425 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
426
427 }
428
429 @Override
430 public void surfaceDestroyed(SurfaceHolder holder) {
431 presenter.videoSurfaceDestroyed();
432 }
433 });
AGS5ef482ce2020-06-12 13:28:51 -0400434
435 binding.pluginPreviewSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
436 binding.pluginPreviewSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
437 @Override
438 public void surfaceCreated(SurfaceHolder holder) {
439 presenter.pluginSurfaceCreated(holder);
440 }
441
442 @Override
443 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
444
445 }
446
447 @Override
448 public void surfaceDestroyed(SurfaceHolder holder) {
449 presenter.pluginSurfaceDestroyed();
450 }
451 });
452
Pierre Duchemin45707ca2018-01-15 15:05:23 -0500453 view.setOnSystemUiVisibilityChangeListener(visibility -> {
454 boolean ui = (visibility & (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN)) == 0;
455 presenter.uiVisibilityChanged(ui);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400456 });
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400457 view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
458 resetVideoSize(mVideoWidth, mVideoHeight));
459
460 WindowManager windowManager = (WindowManager) requireContext().getSystemService(Context.WINDOW_SERVICE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400461 if (windowManager != null) {
462 mOrientationListener = new OrientationEventListener(getContext()) {
463 @Override
464 public void onOrientationChanged(int orientation) {
465 int rot = windowManager.getDefaultDisplay().getRotation();
466 if (mCurrentOrientation != rot) {
467 mCurrentOrientation = rot;
468 presenter.configurationChanged(rot);
469 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400470 }
Adrien Béraude4f901a2019-10-25 17:26:30 -0400471 };
472 if (mOrientationListener.canDetectOrientation()) {
473 mOrientationListener.enable();
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400474 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400475 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400476
Adrien Béraud86a1e372018-11-23 23:24:30 -0500477 binding.shapeRipple.setRippleShape(new Circle());
478 binding.callSpeakerBtn.setChecked(presenter.isSpeakerphoneOn());
Adrien Béraudec19fad2018-12-30 16:51:05 -0500479 binding.callMicBtn.setChecked(presenter.isMicrophoneMuted());
AGS5ef482ce2020-06-12 13:28:51 -0400480 binding.pluginPreviewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
481 configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
Adrien Béraudde0d4522018-12-12 12:11:02 -0500482 binding.previewSurface.setSurfaceTextureListener(listener);
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400483 binding.previewSurface.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
484 configureTransform(mPreviewSurfaceWidth, mPreviewSurfaceHeight));
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500485
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400486 previewSnapAnimation.setDuration(250);
487 previewSnapAnimation.setFloatValues(0.f, 1.f);
488 previewSnapAnimation.setInterpolator(new DecelerateInterpolator());
489 previewSnapAnimation.addUpdateListener(animation -> {
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400490 float animatedFraction = animation == null ? 1 : animation.getAnimatedFraction();
491 configurePreview(mPreviewSurfaceWidth, animatedFraction);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400492 });
493
494 binding.previewContainer.setOnTouchListener((v, event) -> {
495 int action = event.getActionMasked();
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400496 RelativeLayout parent = (RelativeLayout) v.getParent();
497 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
498
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400499 if (action == MotionEvent.ACTION_DOWN) {
500 previewSnapAnimation.cancel();
501 previewDrag = new PointF(event.getX(), event.getY());
502 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400503 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
504 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
505 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
506 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400507 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 -0400508 v.setLayoutParams(params);
509 return true;
510 } else if (action == MotionEvent.ACTION_MOVE) {
511 if (previewDrag != null) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400512 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
513 int currentYPosition = params.topMargin + (int) (event.getY() - previewDrag.y);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400514 params.setMargins(
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400515 currentXPosition,
516 currentYPosition,
517 -((currentXPosition + v.getWidth()) - (int) event.getX()),
518 -((currentYPosition + v.getHeight()) - (int) event.getY()));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400519 v.setLayoutParams(params);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400520
521 float outPosition = binding.previewContainer.getWidth() * 0.85f;
522 float drapOut = 0.f;
523 if (currentXPosition < 0) {
524 drapOut = Math.min(1.f, -currentXPosition / outPosition);
525 } else if (currentXPosition + v.getWidth() > parent.getWidth()) {
526 drapOut = Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition);
527 }
528 setPreviewDragHiddenState(drapOut);
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400529 return true;
530 }
531 return false;
532 } else if (action == MotionEvent.ACTION_UP) {
533 if (previewDrag != null) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400534 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
535
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400536 previewSnapAnimation.cancel();
537 previewDrag = null;
538 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation));
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400539 int ml = 0, mr = 0, mt = 0, mb = 0;
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400540
541 FrameLayout.LayoutParams hp = (FrameLayout.LayoutParams) binding.previewHandle.getLayoutParams();
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400542 if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) {
543 params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
544 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
545 mr = (int) (parent.getWidth() - v.getWidth() - v.getX());
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400546 previewPosition = PreviewPosition.RIGHT;
547 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400548 } else {
549 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
550 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
551 ml = (int) v.getX();
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400552 previewPosition = PreviewPosition.LEFT;
553 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400554 }
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400555 binding.previewHandle.setLayoutParams(hp);
556
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400557 if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) {
558 params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
559 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
560 mb = (int) (parent.getHeight() - v.getHeight() - v.getY());
561 } else {
562 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
563 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
564 mt = (int) v.getY();
565 }
566 previewMargins[0] = ml;
567 previewMargins[1] = mt;
568 previewMargins[2] = mr;
569 previewMargins[3] = mb;
570 params.setMargins(ml, mt, mr, mb);
571 v.setLayoutParams(params);
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400572
573 float outPosition = binding.previewContainer.getWidth() * 0.85f;
574 previewHiddenState = currentXPosition < 0
575 ? Math.min(1.f, -currentXPosition / outPosition)
576 : ((currentXPosition + v.getWidth() > parent.getWidth())
577 ? Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition)
578 : 0.f);
579 setPreviewDragHiddenState(previewHiddenState);
580
Adrien Béraud2d50acb2020-03-23 22:02:15 -0400581 previewSnapAnimation.start();
582 return true;
583 }
584 return false;
585 } else {
586 return false;
587 }
588 });
589
AGS5ef482ce2020-06-12 13:28:51 -0400590 binding.pluginPreviewContainer.setOnTouchListener((v, event) -> {
591 int action = event.getActionMasked();
592 RelativeLayout parent = (RelativeLayout) v.getParent();
593 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) v.getLayoutParams();
594
595 if (action == MotionEvent.ACTION_DOWN) {
596 previewSnapAnimation.cancel();
597 previewDrag = new PointF(event.getX(), event.getY());
598 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation_dragged));
599 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
600 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
601 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
602 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
603 params.setMargins((int) v.getX(), (int) v.getY(), parent.getWidth() - ((int) v.getX() + v.getWidth()), parent.getHeight() - ((int) v.getY() + v.getHeight()));
604 v.setLayoutParams(params);
605 return true;
606 } else if (action == MotionEvent.ACTION_MOVE) {
607 if (previewDrag != null) {
608 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
609 int currentYPosition = params.topMargin + (int) (event.getY() - previewDrag.y);
610 params.setMargins(
611 currentXPosition,
612 currentYPosition,
613 -((currentXPosition + v.getWidth()) - (int) event.getX()),
614 -((currentYPosition + v.getHeight()) - (int) event.getY()));
615 v.setLayoutParams(params);
616
617 float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
618 float drapOut = 0.f;
619 if (currentXPosition < 0) {
620 drapOut = Math.min(1.f, -currentXPosition / outPosition);
621 } else if (currentXPosition + v.getWidth() > parent.getWidth()) {
622 drapOut = Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition);
623 }
624 setPreviewDragHiddenState(drapOut);
625 return true;
626 }
627 return false;
628 } else if (action == MotionEvent.ACTION_UP) {
629 if (previewDrag != null) {
630 int currentXPosition = params.leftMargin + (int) (event.getX() - previewDrag.x);
631
632 previewSnapAnimation.cancel();
633 previewDrag = null;
634 v.setElevation(v.getContext().getResources().getDimension(R.dimen.call_preview_elevation));
635 int ml = 0, mr = 0, mt = 0, mb = 0;
636
637 FrameLayout.LayoutParams hp = (FrameLayout.LayoutParams) binding.pluginPreviewHandle.getLayoutParams();
638 if (params.leftMargin + (v.getWidth() / 2) > parent.getWidth() / 2) {
639 params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
640 params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
641 mr = (int) (parent.getWidth() - v.getWidth() - v.getX());
642 previewPosition = PreviewPosition.RIGHT;
643 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
644 } else {
645 params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
646 params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
647 ml = (int) v.getX();
648 previewPosition = PreviewPosition.LEFT;
649 hp.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT;
650 }
651 binding.pluginPreviewHandle.setLayoutParams(hp);
652
653 if (params.topMargin + (v.getHeight() / 2) > parent.getHeight() / 2) {
654 params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
655 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
656 mb = (int) (parent.getHeight() - v.getHeight() - v.getY());
657 } else {
658 params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
659 params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
660 mt = (int) v.getY();
661 }
662 previewMargins[0] = ml;
663 previewMargins[1] = mt;
664 previewMargins[2] = mr;
665 previewMargins[3] = mb;
666 params.setMargins(ml, mt, mr, mb);
667 v.setLayoutParams(params);
668
669 float outPosition = binding.pluginPreviewContainer.getWidth() * 0.85f;
670 previewHiddenState = currentXPosition < 0
671 ? Math.min(1.f, -currentXPosition / outPosition)
672 : ((currentXPosition + v.getWidth() > parent.getWidth())
673 ? Math.min(1.f, (currentXPosition + v.getWidth() - parent.getWidth()) / outPosition)
674 : 0.f);
675 setPreviewDragHiddenState(previewHiddenState);
676
677 previewSnapAnimation.start();
678 return true;
679 }
680 return false;
681 } else {
682 return false;
683 }
684 });
685
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500686 binding.dialpadEditText.addTextChangedListener(new TextWatcher() {
687 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400688 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
689 }
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500690
691 @Override
692 public void onTextChanged(CharSequence s, int start, int before, int count) {
693 presenter.sendDtmf(s.subSequence(start, start + count));
694 }
695
696 @Override
Rayan Osseiran38206c62019-05-15 14:49:03 -0400697 public void afterTextChanged(Editable s) {
698 }
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500699 });
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500700 }
701
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400702 private void configurePreview(int width, float animatedFraction) {
703 float margin = getResources().getDimension(R.dimen.call_preview_margin);
704 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.previewContainer.getLayoutParams();
705 float r = 1.f - animatedFraction;
706 float hideMargin = 0.f;
707 float targetHiddenState = 0.f;
708 if (previewHiddenState > 0.f) {
709 targetHiddenState = 1.f;
710 float v = width * 0.85f * animatedFraction;
711 hideMargin = previewPosition == PreviewPosition.RIGHT ? v : -v;
712 }
713 setPreviewDragHiddenState(previewHiddenState * r + targetHiddenState * animatedFraction);
714
715 float f = margin * animatedFraction;
716 params.setMargins(
717 (int) (previewMargins[0] * r + f + hideMargin),
718 (int) (previewMargins[1] * r + f),
719 (int) (previewMargins[2] * r + f - hideMargin),
720 (int) (previewMargins[3] * r + f));
721 binding.previewContainer.setLayoutParams(params);
AGS5ef482ce2020-06-12 13:28:51 -0400722 binding.pluginPreviewContainer.setLayoutParams(params);
Pierre Duchemin7c125f72020-05-29 15:23:53 -0400723 }
724
Rayan Osseirande9ac142019-07-02 13:01:32 -0400725 /**
726 * Releases current wakelock and acquires a new proximity wakelock if current call is audio only.
ayounesc6c2c012019-11-11 11:09:51 -0500727 *
Rayan Osseirande9ac142019-07-02 13:01:32 -0400728 * @param isAudioOnly true if it is an audio call
729 */
730 @Override
731 public void handleCallWakelock(boolean isAudioOnly) {
732 if (isAudioOnly) {
733 if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) {
734 mScreenWakeLock.release();
735 }
736 PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400737 if (powerManager != null) {
738 mScreenWakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
739 mScreenWakeLock.setReferenceCounted(false);
Rayan Osseirande9ac142019-07-02 13:01:32 -0400740
Adrien Béraude4f901a2019-10-25 17:26:30 -0400741 if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
742 mScreenWakeLock.acquire();
743 }
Rayan Osseirande9ac142019-07-02 13:01:32 -0400744 }
745 }
746 }
747
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500748 @Override
Adrien Béraud2c378b32018-07-11 15:24:02 -0400749 public void onDestroyView() {
750 super.onDestroyView();
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400751 if (mOrientationListener != null) {
752 mOrientationListener.disable();
753 mOrientationListener = null;
754 }
Adrien Béraud2c378b32018-07-11 15:24:02 -0400755 mCompositeDisposable.clear();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500756 if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) {
757 mScreenWakeLock.release();
758 }
Adrien Béraud7307cd52020-04-13 23:29:11 -0400759 binding = null;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400760 }
761
Adrien Béraud7307cd52020-04-13 23:29:11 -0400762 @Override
763 public void onDestroy() {
764 super.onDestroy();
765 mCompositeDisposable.dispose();
766 }
Rayan Osseiran38206c62019-05-15 14:49:03 -0400767
768 @Override
769 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
770 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Adrien Béraud63de6042019-05-31 09:38:31 -0400771 if (requestCode != REQUEST_PERMISSION_INCOMING && requestCode != REQUEST_PERMISSION_OUTGOING)
772 return;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400773 for (int i = 0, n = permissions.length; i < n; i++) {
774 boolean audioGranted = mDeviceRuntimeService.hasAudioPermission();
Adrien Béraud63de6042019-05-31 09:38:31 -0400775 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
Rayan Osseiran38206c62019-05-15 14:49:03 -0400776 switch (permissions[i]) {
777 case Manifest.permission.CAMERA:
Adrien Béraud63de6042019-05-31 09:38:31 -0400778 presenter.cameraPermissionChanged(granted);
779 if (audioGranted) {
780 initializeCall(requestCode == REQUEST_PERMISSION_INCOMING);
Rayan Osseiran38206c62019-05-15 14:49:03 -0400781 }
782 break;
783 case Manifest.permission.RECORD_AUDIO:
Adrien Béraud63de6042019-05-31 09:38:31 -0400784 presenter.audioPermissionChanged(granted);
785 initializeCall(requestCode == REQUEST_PERMISSION_INCOMING);
Rayan Osseiran38206c62019-05-15 14:49:03 -0400786 break;
787 }
788 }
789 }
790
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400791 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400792 public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
793 if (requestCode == REQUEST_CODE_ADD_PARTICIPANT) {
794 if (resultCode == Activity.RESULT_OK && data != null) {
795 ConversationPath path = ConversationPath.fromUri(data.getData());
796 if (path != null) {
797 presenter.addConferenceParticipant(path.getAccountId(), path.getContactId());
798 }
799 }
Adrien Béraudade9bee2019-12-02 17:13:26 -0500800 } else if (requestCode == REQUEST_CODE_SCREEN_SHARE) {
801 if (resultCode == Activity.RESULT_OK && data != null) {
802 startScreenShare(mProjectionManager.getMediaProjection(resultCode, data));
803 } else {
804 binding.callScreenshareBtn.setChecked(false);
805 }
Adrien Béraude4f901a2019-10-25 17:26:30 -0400806 }
807 }
808
809 @Override
810 public void onCreateOptionsMenu(@NonNull Menu m, @NonNull MenuInflater inf) {
Adrien Béraudda712a42015-11-22 23:45:26 -0500811 super.onCreateOptionsMenu(m, inf);
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500812 inf.inflate(R.menu.ac_call, m);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400813 dialPadBtn = m.findItem(R.id.menuitem_dialpad);
ayounes47e93992019-10-28 12:09:53 -0400814 pluginsMenuBtn = m.findItem(R.id.menuitem_video_plugins);
Adrien Béraudda712a42015-11-22 23:45:26 -0500815 }
816
817 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400818 public void onPrepareOptionsMenu(@NonNull Menu menu) {
Adrien Béraudda712a42015-11-22 23:45:26 -0500819 super.onPrepareOptionsMenu(menu);
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400820 presenter.prepareOptionMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400821 }
822
823 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400824 public boolean onOptionsItemSelected(@NonNull MenuItem item) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400825 super.onOptionsItemSelected(item);
826 switch (item.getItemId()) {
827 case android.R.id.home:
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400828 presenter.chatClick();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400829 break;
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400830 case R.id.menuitem_dialpad:
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -0400831 presenter.dialpadClick();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400832 break;
ayounes47e93992019-10-28 12:09:53 -0400833 case R.id.menuitem_video_plugins:
834 displayVideoPluginsCarousel();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400835 }
836 return true;
837 }
838
Adrien Béraud79808d02018-02-20 00:16:28 +0100839 @Override
Adrien Bérauda373e3b2018-12-12 11:14:50 -0500840 public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400841 AppCompatActivity activity = (AppCompatActivity) getActivity();
842 ActionBar actionBar = activity == null ? null : activity.getSupportActionBar();
843 if (actionBar != null) {
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400844 if (isInPictureInPictureMode) {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400845 actionBar.hide();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400846 } else {
847 mBackstackLost = true;
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400848 actionBar.show();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -0400849 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400850 }
Adrien Béraud79808d02018-02-20 00:16:28 +0100851 presenter.pipModeChanged(isInPictureInPictureMode);
852 }
853
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400854 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400855 public void displayContactBubble(final boolean display) {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500856 binding.contactBubbleLayout.getHandler().post(() -> binding.contactBubbleLayout.setVisibility(display ? View.VISIBLE : View.GONE));
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400857 }
858
859 @Override
Rayan Osseiranc1532d42019-06-05 13:17:53 -0400860 public void displayVideoSurface(final boolean displayVideoSurface, final boolean displayPreviewContainer) {
861 binding.videoSurface.setVisibility(displayVideoSurface ? View.VISIBLE : View.GONE);
agsantosa6d68a82020-07-09 11:33:30 -0400862 if (choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -0400863 binding.pluginPreviewSurface.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
864 binding.pluginPreviewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
865 binding.previewContainer.setVisibility(View.GONE);
866 } else {
867 binding.pluginPreviewSurface.setVisibility(View.GONE);
868 binding.pluginPreviewContainer.setVisibility(View.GONE);
869 binding.previewContainer.setVisibility(displayPreviewContainer ? View.VISIBLE : View.GONE);
870 }
Adrien Béraudace37a22018-06-22 14:58:36 -0400871 updateMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400872 }
873
874 @Override
Adrien Béraud79808d02018-02-20 00:16:28 +0100875 public void displayPreviewSurface(final boolean display) {
876 if (display) {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500877 binding.videoSurface.setZOrderOnTop(false);
Adrien Béraud86a1e372018-11-23 23:24:30 -0500878 binding.videoSurface.setZOrderMediaOverlay(false);
Adrien Béraud79808d02018-02-20 00:16:28 +0100879 } else {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500880 binding.videoSurface.setZOrderMediaOverlay(true);
881 binding.videoSurface.setZOrderOnTop(true);
Adrien Béraud79808d02018-02-20 00:16:28 +0100882 }
883 }
884
885 @Override
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400886 public void displayHangupButton(boolean display) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400887 Log.w(TAG, "displayHangupButton " + display);
agsantosa6d68a82020-07-09 11:33:30 -0400888 display &= !choosePluginMode;
Adrien Béraud86a1e372018-11-23 23:24:30 -0500889 binding.callControlGroup.setVisibility(display ? View.VISIBLE : View.GONE);
890 binding.callHangupBtn.setVisibility(display ? View.VISIBLE : View.GONE);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400891 binding.confControlGroup.setVisibility((mConferenceMode && display) ? View.VISIBLE : View.GONE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400892 }
893
894 @Override
895 public void displayDialPadKeyboard() {
Adrien Béraudbcbb4d42018-12-08 16:06:39 -0500896 KeyboardVisibilityManager.showKeyboard(getActivity(), binding.dialpadEditText, InputMethodManager.SHOW_FORCED);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400897 }
898
899 @Override
900 public void switchCameraIcon(boolean isFront) {
Adrien Béraud91f88742019-09-09 00:46:46 -0400901 binding.callCameraFlipBtn.setImageResource(isFront ? R.drawable.baseline_camera_front_24 : R.drawable.baseline_camera_rear_24);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400902 }
903
904 @Override
Adrien Béraud34a6fa22019-07-28 16:02:59 -0400905 public void updateAudioState(HardwareService.AudioState state) {
906 binding.callSpeakerBtn.setChecked(state.getOutputType() == HardwareService.AudioOutput.SPEAKERS);
907 }
908
909 @Override
Adrien Béraudd3bf4e42018-02-14 14:44:41 +0100910 public void updateMenu() {
Adrien Béraudeb4bb002019-03-14 15:52:48 -0400911 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400912 }
913
914 @Override
915 public void updateTime(final long duration) {
Pierre Duchemin37d0b3e2020-05-14 18:56:21 -0400916 if (binding != null) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400917 if (duration == 0)
918 binding.callStatusTxt.setText(null);
919 else
920 binding.callStatusTxt.setText(String.format(Locale.getDefault(), "%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
921 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400922 }
923
924 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -0400925 @SuppressLint("RestrictedApi")
926 public void updateContactBubble(@NonNull final List<SipCall> contacts) {
927 Log.w(TAG, "updateContactBubble " + contacts.size());
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400928
Adrien Béraude4f901a2019-10-25 17:26:30 -0400929 mConferenceMode = contacts.size() > 1;
930 String username = mConferenceMode ? "Conference with " + contacts.size() + " people" : contacts.get(0).getContact().getRingUsername();
931 String displayName = mConferenceMode ? null : contacts.get(0).getContact().getDisplayName();
Adrien Béraud5f8c3f72018-03-09 14:49:39 -0500932
Adrien Béraudafcdd962018-07-06 21:38:41 -0400933 boolean hasProfileName = displayName != null && !displayName.contentEquals(username);
Adrien Béraudbc0898e2018-08-23 14:31:11 -0400934
935 AppCompatActivity activity = (AppCompatActivity) getActivity();
936 if (activity != null) {
937 ActionBar ab = activity.getSupportActionBar();
938 if (ab != null) {
939 if (hasProfileName) {
940 ab.setTitle(displayName);
941 ab.setSubtitle(username);
942 } else {
943 ab.setTitle(username);
944 ab.setSubtitle(null);
945 }
946 ab.setDisplayShowTitleEnabled(true);
947 }
948 }
949
Adrien Béraudafcdd962018-07-06 21:38:41 -0400950 if (hasProfileName) {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500951 binding.contactBubbleNumTxt.setVisibility(View.VISIBLE);
952 binding.contactBubbleTxt.setText(displayName);
953 binding.contactBubbleNumTxt.setText(username);
Adrien Béraudafcdd962018-07-06 21:38:41 -0400954 } else {
Adrien Béraud86a1e372018-11-23 23:24:30 -0500955 binding.contactBubbleNumTxt.setVisibility(View.GONE);
956 binding.contactBubbleTxt.setText(username);
Adrien Béraudafcdd962018-07-06 21:38:41 -0400957 }
Adrien Béraud5f8c3f72018-03-09 14:49:39 -0500958
Andreas Traczykcee415a2019-12-03 15:45:04 -0500959 binding.contactBubble.setImageDrawable(
960 new AvatarDrawable.Builder()
961 .withContact(contacts.get(0).getContact())
962 .withCircleCrop(true)
963 .withPresence(false)
964 .build(getActivity())
965 );
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400966
Adrien Béraude4f901a2019-10-25 17:26:30 -0400967 if (!mConferenceMode) {
968 binding.confControlGroup.setVisibility(View.GONE);
969 } else {
970 binding.confControlGroup.setVisibility(View.VISIBLE);
ayounesc6c2c012019-11-11 11:09:51 -0500971 if (confAdapter == null) {
Adrien Béraude4f901a2019-10-25 17:26:30 -0400972 confAdapter = new ConfParticipantAdapter((view, call) -> {
Adrien Bérauda165bee2020-06-08 10:30:26 -0400973 PopupMenu popup = new PopupMenu(view.getContext(), view);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400974 popup.inflate(R.menu.conference_participant_actions);
975 popup.setOnMenuItemClickListener(item -> {
Adrien Bérauda165bee2020-06-08 10:30:26 -0400976 if (presenter != null)
977 switch (item.getItemId()) {
978 case R.id.conv_contact_details:
979 presenter.openParticipantContact(call);
980 break;
981 case R.id.conv_contact_hangup:
982 presenter.hangupParticipant(call);
983 break;
984 default:
985 return false;
986 }
Adrien Béraude4f901a2019-10-25 17:26:30 -0400987 return true;
988 });
Adrien Bérauda165bee2020-06-08 10:30:26 -0400989 MenuPopupHelper menuHelper = new MenuPopupHelper(view.getContext(), (MenuBuilder) popup.getMenu(), view);
Adrien Béraude4f901a2019-10-25 17:26:30 -0400990 menuHelper.setForceShowIcon(true);
991 menuHelper.show();
992 });
993 }
994 confAdapter.updateFromCalls(contacts);
995 if (binding.confControlGroup.getAdapter() == null)
996 binding.confControlGroup.setAdapter(confAdapter);
Adrien Béraud3f9f6cd2018-12-12 15:05:28 -0500997 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -0400998 }
999
1000 @Override
Adrien Béraud34915fb2020-08-24 17:12:03 -04001001 public void updateConfInfo(List<Conference.ParticipantInfo> info) {
1002 binding.participantLabelContainer.removeAllViews();
1003 if (!info.isEmpty()) {
1004 LayoutInflater inflater = LayoutInflater.from(binding.participantLabelContainer.getContext());
1005 for (Conference.ParticipantInfo i : info) {
1006 String displayName = i.contact.getDisplayName();
1007 if (!TextUtils.isEmpty(displayName)) {
1008 ItemParticipantLabelBinding label = ItemParticipantLabelBinding.inflate(inflater);
1009 PercentFrameLayout.LayoutParams params = new PercentFrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
1010 params.getPercentLayoutInfo().leftMarginPercent = i.x / (float) mVideoWidth;
1011 params.getPercentLayoutInfo().topMarginPercent = i.y / (float) mVideoHeight;
1012 label.participantName.setText(displayName);
1013 binding.participantLabelContainer.addView(label.getRoot(), params);
1014 }
1015 }
1016 }
1017 binding.participantLabelContainer.setVisibility(info.isEmpty() ? View.GONE : View.VISIBLE);
1018 }
1019
1020 @Override
Adrien Béraude4f901a2019-10-25 17:26:30 -04001021 public void updateCallStatus(final SipCall.CallStatus callStatus) {
1022 binding.callStatusTxt.setText(callStateToHumanState(callStatus));
1023 }
1024
1025 @Override
ayounes47e93992019-10-28 12:09:53 -04001026 public void initMenu(boolean isSpeakerOn, boolean displayFlip, boolean canDial,
1027 boolean showPluginBtn, boolean onGoingCall) {
1028 if (binding.callCameraFlipBtn != null) {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001029 binding.callCameraFlipBtn.setVisibility(displayFlip ? View.VISIBLE : View.GONE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001030 }
Romain Bertozziad8fd842016-05-11 14:30:35 -04001031 if (dialPadBtn != null) {
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001032 dialPadBtn.setVisible(canDial);
Romain Bertozziad8fd842016-05-11 14:30:35 -04001033 }
ayounes47e93992019-10-28 12:09:53 -04001034
ayounesc6c2c012019-11-11 11:09:51 -05001035 if (pluginsMenuBtn != null) {
ayounes47e93992019-10-28 12:09:53 -04001036 pluginsMenuBtn.setVisible(showPluginBtn);
1037 }
1038 updateMenu();
Adrien Béraud04d822c2015-04-02 17:44:36 -04001039 }
1040
1041 @Override
Adrien Béraud34a6fa22019-07-28 16:02:59 -04001042 public void initNormalStateDisplay(final boolean audioOnly, boolean isMuted) {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001043 Log.w(TAG, "initNormalStateDisplay");
Adrien Béraud86a1e372018-11-23 23:24:30 -05001044 binding.shapeRipple.stopRipple();
Pierre Ducheminbb833672018-03-09 16:18:33 -05001045
Adrien Béraud86a1e372018-11-23 23:24:30 -05001046 binding.callAcceptBtn.setVisibility(View.GONE);
1047 binding.callRefuseBtn.setVisibility(View.GONE);
1048 binding.callControlGroup.setVisibility(View.VISIBLE);
1049 binding.callHangupBtn.setVisibility(View.VISIBLE);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001050
Adrien Béraud86a1e372018-11-23 23:24:30 -05001051 binding.contactBubbleLayout.setVisibility(audioOnly ? View.VISIBLE : View.GONE);
Adrien Béraudec19fad2018-12-30 16:51:05 -05001052 binding.callMicBtn.setChecked(isMuted);
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001053
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001054 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001055 }
1056
1057 @Override
1058 public void initIncomingCallDisplay() {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001059 Log.w(TAG, "initIncomingCallDisplay");
1060
Adrien Béraud86a1e372018-11-23 23:24:30 -05001061 binding.callAcceptBtn.setVisibility(View.VISIBLE);
1062 binding.callRefuseBtn.setVisibility(View.VISIBLE);
1063 binding.callControlGroup.setVisibility(View.GONE);
1064 binding.callHangupBtn.setVisibility(View.GONE);
Hadrien De Sousa841d15a2017-06-02 11:52:10 -04001065
Adrien Béraud86a1e372018-11-23 23:24:30 -05001066 binding.contactBubbleLayout.setVisibility(View.VISIBLE);
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001067 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001068 }
1069
1070 @Override
1071 public void initOutGoingCallDisplay() {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001072 Log.w(TAG, "initOutGoingCallDisplay");
1073
Adrien Béraud86a1e372018-11-23 23:24:30 -05001074 binding.callAcceptBtn.setVisibility(View.GONE);
1075 binding.callRefuseBtn.setVisibility(View.VISIBLE);
1076 binding.callControlGroup.setVisibility(View.GONE);
1077 binding.callHangupBtn.setVisibility(View.GONE);
Hadrien De Sousa841d15a2017-06-02 11:52:10 -04001078
Adrien Béraud86a1e372018-11-23 23:24:30 -05001079 binding.contactBubbleLayout.setVisibility(View.VISIBLE);
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001080 requireActivity().invalidateOptionsMenu();
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001081 }
1082
1083 @Override
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001084 public void resetPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
1085 if (previewWidth == -1 && previewHeight == -1)
1086 return;
1087 mPreviewWidth = previewWidth;
1088 mPreviewHeight = previewHeight;
1089 boolean flip = (rot % 180) != 0;
1090 binding.previewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
1091 }
1092
1093 @Override
AGS5ef482ce2020-06-12 13:28:51 -04001094 public void resetPluginPreviewVideoSize(int previewWidth, int previewHeight, int rot) {
1095 if (previewWidth == -1 && previewHeight == -1)
1096 return;
1097 mPreviewWidth = previewWidth;
1098 mPreviewHeight = previewHeight;
1099 boolean flip = (rot % 180) != 0;
1100 binding.pluginPreviewSurface.setAspectRatio(flip ? mPreviewHeight : mPreviewWidth, flip ? mPreviewWidth : mPreviewHeight);
1101 }
1102
1103 @Override
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001104 public void resetVideoSize(int videoWidth, int videoHeight) {
Adrien Béraudace37a22018-06-22 14:58:36 -04001105 ViewGroup rootView = (ViewGroup) getView();
1106 if (rootView == null)
1107 return;
Adrien Béraudace37a22018-06-22 14:58:36 -04001108 double videoRatio = videoWidth / (double) videoHeight;
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001109 double screenRatio = rootView.getWidth() / (double) rootView.getHeight();
Adrien Béraud86a1e372018-11-23 23:24:30 -05001110 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) binding.videoSurface.getLayoutParams();
Adrien Béraudace37a22018-06-22 14:58:36 -04001111 int oldW = params.width;
1112 int oldH = params.height;
1113 if (videoRatio >= screenRatio) {
1114 params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
1115 params.height = (int) (videoHeight * (double) rootView.getWidth() / (double) videoWidth);
1116 } else {
1117 params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
1118 params.width = (int) (videoWidth * (double) rootView.getHeight() / (double) videoHeight);
1119 }
Thibault Wittembergb3280502016-12-16 17:34:53 -05001120
Adrien Béraudace37a22018-06-22 14:58:36 -04001121 if (oldW != params.width || oldH != params.height) {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001122 binding.videoSurface.setLayoutParams(params);
Adrien Béraudace37a22018-06-22 14:58:36 -04001123 }
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001124 mVideoWidth = videoWidth;
1125 mVideoHeight = videoHeight;
Adrien Béraudde0d4522018-12-12 12:11:02 -05001126 }
Adrien Béraud30532a52018-09-11 15:10:05 -04001127
Adrien Béraudde0d4522018-12-12 12:11:02 -05001128 private void configureTransform(int viewWidth, int viewHeight) {
1129 Activity activity = getActivity();
Adrien Béraud3f9f6cd2018-12-12 15:05:28 -05001130 if (null == binding.previewSurface || null == activity) {
Adrien Béraudde0d4522018-12-12 12:11:02 -05001131 return;
Adrien Béraud30532a52018-09-11 15:10:05 -04001132 }
Adrien Béraudde0d4522018-12-12 12:11:02 -05001133 int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
1134 boolean rot = Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation;
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001135 // Log.w(TAG, "configureTransform " + viewWidth + "x" + viewHeight + " rot=" + rot + " mPreviewWidth=" + mPreviewWidth + " mPreviewHeight=" + mPreviewHeight);
Adrien Béraudde0d4522018-12-12 12:11:02 -05001136 Matrix matrix = new Matrix();
1137 RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
1138 float centerX = viewRect.centerX();
1139 float centerY = viewRect.centerY();
1140 if (rot) {
1141 RectF bufferRect = new RectF(0, 0, mPreviewHeight, mPreviewWidth);
1142 bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
1143 matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
1144 float scale = Math.max(
1145 (float) viewHeight / mPreviewHeight,
1146 (float) viewWidth / mPreviewWidth);
1147 matrix.postScale(scale, scale, centerX, centerY);
1148 matrix.postRotate(90 * (rotation - 2), centerX, centerY);
1149 } else if (Surface.ROTATION_180 == rotation) {
1150 matrix.postRotate(180, centerX, centerY);
Adrien Béraudace37a22018-06-22 14:58:36 -04001151 }
agsantosa6d68a82020-07-09 11:33:30 -04001152 if(!choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -04001153// binding.pluginPreviewSurface.setTransform(matrix);
1154// }
1155// else {
1156 binding.previewSurface.setTransform(matrix);
1157 }
Adrien Béraud04d822c2015-04-02 17:44:36 -04001158 }
1159
1160 @Override
Hadrien De Sousa0dc83162017-11-10 16:15:18 -05001161 public void goToConversation(String accountId, String conversationId) {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001162 Context context = requireContext();
1163 if (DeviceUtils.isTablet(context)) {
Adrien Béraud52d46a42020-05-15 14:41:08 -04001164 startActivity(new Intent(DRingService.ACTION_CONV_ACCEPT, ConversationPath.toUri(accountId, conversationId), context, HomeActivity.class));
Adrien Béraudda712a42015-11-22 23:45:26 -05001165 } else {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001166 startActivityForResult(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), context, ConversationActivity.class)
1167 .setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT), HomeActivity.REQUEST_CODE_CONVERSATION);
Adrien Béraudda712a42015-11-22 23:45:26 -05001168 }
Adrien Béraud04d822c2015-04-02 17:44:36 -04001169 }
1170
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001171 @Override
1172 public void goToAddContact(CallContact callContact) {
1173 startActivityForResult(ActionHelper.getAddNumberIntentForContact(callContact),
1174 ConversationFragment.REQ_ADD_CONTACT);
1175 }
1176
Adrien Béraude4f901a2019-10-25 17:26:30 -04001177 @Override
1178 public void goToContact(String accountId, CallContact contact) {
1179 startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contact.getPrimaryNumber()))
1180 .setClass(requireContext(), ContactDetailsActivity.class));
1181 }
1182
Rayan Osseiran38206c62019-05-15 14:49:03 -04001183 /**
1184 * 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 -04001185 * Initializes the call if permissions are accepted.
Rayan Osseiran38206c62019-05-15 14:49:03 -04001186 *
1187 * @param isIncoming true if call is incoming, false for outgoing
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001188 * @see #initializeCall(boolean) initializeCall
Rayan Osseiran38206c62019-05-15 14:49:03 -04001189 */
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001190 @Override
1191 public void prepareCall(boolean isIncoming) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001192 boolean audioGranted = mDeviceRuntimeService.hasAudioPermission();
1193 boolean audioOnly;
1194 int permissionType;
1195
1196 if (isIncoming) {
1197 audioOnly = presenter.isAudioOnly();
1198 permissionType = REQUEST_PERMISSION_INCOMING;
Rayan Osseiran38206c62019-05-15 14:49:03 -04001199 } else {
Adrien Béraude4f901a2019-10-25 17:26:30 -04001200 Bundle args = getArguments();
1201 audioOnly = args != null && args.getBoolean(KEY_AUDIO_ONLY);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001202 permissionType = REQUEST_PERMISSION_OUTGOING;
1203 }
1204 if (!audioOnly) {
1205 boolean videoGranted = mDeviceRuntimeService.hasVideoPermission();
1206
Adrien Bérauda0226ff2019-11-21 15:24:42 -05001207 if ((!audioGranted || !videoGranted) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001208 ArrayList<String> perms = new ArrayList<>();
1209 if (!videoGranted) {
1210 perms.add(Manifest.permission.CAMERA);
1211 }
1212 if (!audioGranted) {
1213 perms.add(Manifest.permission.RECORD_AUDIO);
1214 }
1215 requestPermissions(perms.toArray(new String[perms.size()]), permissionType);
1216 } else if (audioGranted && videoGranted) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001217 initializeCall(isIncoming);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001218 }
1219 } else {
Adrien Bérauda0226ff2019-11-21 15:24:42 -05001220 if (!audioGranted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001221 requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, permissionType);
1222 } else if (audioGranted) {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001223 initializeCall(isIncoming);
Rayan Osseiran38206c62019-05-15 14:49:03 -04001224 }
1225 }
Rayan Osseiran38206c62019-05-15 14:49:03 -04001226 }
1227
1228 /**
1229 * Starts a call. Takes into account whether call is incoming or outgoing.
1230 *
1231 * @param isIncoming true if call is incoming, false for outgoing
1232 */
Adrien Béraude4f901a2019-10-25 17:26:30 -04001233 private void initializeCall(boolean isIncoming) {
Rayan Osseiran38206c62019-05-15 14:49:03 -04001234 if (isIncoming) {
1235 presenter.acceptCall();
1236 } else {
1237 Bundle args;
1238 args = getArguments();
1239 if (args != null) {
1240 presenter.initOutGoing(getArguments().getString(KEY_ACCOUNT_ID),
1241 getArguments().getString(ConversationFragment.KEY_CONTACT_RING_ID),
1242 getArguments().getBoolean(KEY_AUDIO_ONLY));
1243 }
1244 }
1245 }
1246
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001247 @Override
1248 public void finish() {
Adrien Béraudeb4bb002019-03-14 15:52:48 -04001249 Activity activity = getActivity();
Rayan Osseiranf7dfe232019-06-06 10:26:10 -04001250 if (activity != null) {
1251 if (mBackstackLost) {
1252 activity.finishAndRemoveTask();
1253 startActivity(
1254 Intent.makeMainActivity(
1255 new ComponentName(activity, HomeActivity.class)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
1256 } else {
1257 activity.finish();
1258 }
1259 }
Alexandre Lision1532d952016-11-17 09:41:00 -05001260 }
1261
Rayan Osseiranf7dfe232019-06-06 10:26:10 -04001262
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001263 public void speakerClicked() {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001264 presenter.speakerClick(binding.callSpeakerBtn.isChecked());
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001265 }
1266
Adrien Béraudade9bee2019-12-02 17:13:26 -05001267 private void startScreenShare(MediaProjection mediaProjection) {
Adrien Béraud20bd7232020-03-16 11:33:23 -04001268 if (presenter.startScreenShare(mediaProjection)) {
agsantosa6d68a82020-07-09 11:33:30 -04001269 if(choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -04001270 binding.pluginPreviewSurface.setVisibility(View.GONE);
1271 } else {
1272 binding.previewSurface.setVisibility(View.GONE);
1273 }
Adrien Béraud20bd7232020-03-16 11:33:23 -04001274 } else {
1275 Toast.makeText(requireContext(), "Can't start screen sharing", Toast.LENGTH_SHORT).show();
1276 }
Adrien Béraudade9bee2019-12-02 17:13:26 -05001277 }
1278
1279 private void stopShareScreen() {
agsantosa6d68a82020-07-09 11:33:30 -04001280 if(choosePluginMode)
AGS5ef482ce2020-06-12 13:28:51 -04001281 {
1282 binding.previewSurface.setVisibility(View.VISIBLE);
1283 }
1284 else {
1285 binding.previewSurface.setVisibility(View.VISIBLE);
1286 }
Adrien Béraudade9bee2019-12-02 17:13:26 -05001287 presenter.stopScreenShare();
1288 }
1289
1290 public void shareScreenClicked(boolean checked) {
1291 if (!checked) {
1292 stopShareScreen();
1293 } else {
1294 startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE_SCREEN_SHARE);
1295 }
1296 }
1297
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001298 public void micClicked() {
Adrien Béraud86a1e372018-11-23 23:24:30 -05001299 presenter.muteMicrophoneToggled(binding.callMicBtn.isChecked());
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001300 }
1301
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001302 public void hangUpClicked() {
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -04001303 presenter.hangupCall();
Alexandre Lision1532d952016-11-17 09:41:00 -05001304 }
1305
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001306 public void refuseClicked() {
Hadrien De Sousaf5774ee2017-05-17 14:04:17 -04001307 presenter.refuseCall();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001308 }
1309
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001310 public void acceptClicked() {
Rayan Osseiran3dd04662019-06-28 16:47:48 -04001311 prepareCall(true);
Thibault Wittembergb70d5b02016-07-08 16:50:14 -04001312 }
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001313
Adrien Béraudbc0898e2018-08-23 14:31:11 -04001314 public void cameraFlip() {
1315 presenter.switchVideoInputClick();
1316 }
1317
Adrien Béraude4f901a2019-10-25 17:26:30 -04001318 public void addParticipant() {
1319 presenter.startAddParticipant();
1320 }
1321
1322 @Override
1323 public void startAddParticipant(String conferenceId) {
1324 startActivityForResult(
1325 new Intent(Intent.ACTION_PICK)
1326 .setClass(requireActivity(), ConversationSelectionActivity.class)
1327 .putExtra(KEY_CONF_ID, conferenceId),
1328 CallFragment.REQUEST_CODE_ADD_PARTICIPANT);
1329 }
ayounes019267f2020-01-13 15:14:08 -05001330 public void toggleCallMediaHandler(String id, boolean toggle) {
1331 Ringservice.toggleCallMediaHandler(id, toggle);
ayounes47e93992019-10-28 12:09:53 -04001332 }
1333
ayounes019267f2020-01-13 15:14:08 -05001334 public Map<String, String> getCallMediaHandlerDetails(String id) {
1335 return Ringservice.getCallMediaHandlerDetails(id).toNative();
ayounesc6c2c012019-11-11 11:09:51 -05001336 }
ayounes81087472019-11-08 15:26:05 -05001337
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001338 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001339 public void positiveMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001340 presenter.positiveButtonClicked();
1341 }
1342
1343 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001344 public void negativeMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001345 presenter.negativeButtonClicked();
1346 }
1347
1348 @Override
Pierre Duchemin1fa61922018-01-18 10:09:02 -05001349 public void toggleMediaButtonClicked() {
Pierre Duchemin8b2c1b52017-12-29 17:17:13 -05001350 presenter.toggleButtonClicked();
1351 }
Rayan Osseiran38206c62019-05-15 14:49:03 -04001352
ayounesc6c2c012019-11-11 11:09:51 -05001353 public boolean displayPluginsButton() {
agsantosa6d68a82020-07-09 11:33:30 -04001354 return getPluginsEnabled();
ayounesc6c2c012019-11-11 11:09:51 -05001355 }
1356
ayounes47e93992019-10-28 12:09:53 -04001357 @Override
1358 public void onConfigurationChanged(@NonNull Configuration newConfig) {
1359 super.onConfigurationChanged(newConfig);
agsantos00e3a9d2020-07-06 15:08:43 -04001360 // Reset the padding of the RecyclerPicker on each
ayounesc6c2c012019-11-11 11:09:51 -05001361 rp.setFirstLastElementsWidths(112, 112);
ayounes47e93992019-10-28 12:09:53 -04001362 binding.recyclerPicker.setVisibility(View.GONE);
ayounesc6c2c012019-11-11 11:09:51 -05001363 Log.i("ZZZ", "Height: " + binding.recyclerPicker.getHeight());
agsantosa6d68a82020-07-09 11:33:30 -04001364 if (choosePluginMode) {
ayounes47e93992019-10-28 12:09:53 -04001365 displayHangupButton(false);
1366 binding.recyclerPicker.setVisibility(View.VISIBLE);
ayounesc6c2c012019-11-11 11:09:51 -05001367 movePreview(true);
1368 if (previousPluginPosition != -1) {
ayounes47e93992019-10-28 12:09:53 -04001369 rp.scrollToPosition(previousPluginPosition);
1370 }
1371 } else {
ayounesc6c2c012019-11-11 11:09:51 -05001372 movePreview(false);
ayounes47e93992019-10-28 12:09:53 -04001373 displayHangupButton(true);
1374 }
1375 }
1376
ayounesc6c2c012019-11-11 11:09:51 -05001377 public void toggleVideoPluginsCarousel(boolean toggle) {
1378 toggleVideoPluginsCarousel = toggle;
agsantosa6d68a82020-07-09 11:33:30 -04001379 if (choosePluginMode) {
ayounesc6c2c012019-11-11 11:09:51 -05001380 if (toggleVideoPluginsCarousel) {
1381 binding.recyclerPicker.setVisibility(View.VISIBLE);
1382 movePreview(true);
1383 } else {
1384 binding.recyclerPicker.setVisibility(View.INVISIBLE);
1385 movePreview(false);
1386 }
1387 }
1388
1389 }
1390
1391 public void movePreview(boolean up) {
1392 // Move the preview container (cardview) by a certain margin
1393 if(up) {
1394 animation.setIntValues(12, 128);
1395 } else {
1396 animation.setIntValues(128, 12);
1397 }
1398 animation.start();
1399 }
1400
1401 /**
1402 * Function that is called to show/hide the plugins recycler viewer and update UI
1403 */
ayounes47e93992019-10-28 12:09:53 -04001404 public void displayVideoPluginsCarousel() {
agsantosa6d68a82020-07-09 11:33:30 -04001405 choosePluginMode = !choosePluginMode;
AGS5ef482ce2020-06-12 13:28:51 -04001406
ayounes81087472019-11-08 15:26:05 -05001407 Context context = requireActivity();
1408
ayounes019267f2020-01-13 15:14:08 -05001409 // Create callMediaHandlers and videoPluginsItems in a lazy manner
ayounesc6c2c012019-11-11 11:09:51 -05001410 if (pluginsModeFirst) {
1411 // Init
ayounes019267f2020-01-13 15:14:08 -05001412 callMediaHandlers = Ringservice.listCallMediaHandlers();
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001413 List<Drawable> videoPluginsItems = new ArrayList<>(callMediaHandlers.size() + 1);
ayounes47e93992019-10-28 12:09:53 -04001414
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001415 videoPluginsItems.add(context.getDrawable(R.drawable.baseline_cancel_24));
ayounes019267f2020-01-13 15:14:08 -05001416 // Search for plugin call media handlers icons
1417 // If a call media handler doesn't have an icon use a standard android icon
1418 for (String callMediaHandler : callMediaHandlers) {
1419 Map<String, String> details = getCallMediaHandlerDetails(callMediaHandler);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001420 String drawablePath = details.get("icoPath");
1421 Drawable handlerIcon = StringUtils.isEmpty(drawablePath) ? null : Drawable.createFromPath(details.get("icoPath"));
1422 if (handlerIcon == null) {
1423 handlerIcon = context.getDrawable(R.drawable.ic_jami);
ayounes47e93992019-10-28 12:09:53 -04001424 }
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001425 videoPluginsItems.add(handlerIcon);
ayounes47e93992019-10-28 12:09:53 -04001426 }
1427
1428 rp.updateData(videoPluginsItems);
1429
ayounesc6c2c012019-11-11 11:09:51 -05001430 pluginsModeFirst = false;
1431 }
1432
agsantosa6d68a82020-07-09 11:33:30 -04001433 if (choosePluginMode) {
AGS5ef482ce2020-06-12 13:28:51 -04001434 //change preview image
1435 displayVideoSurface(true,true);
ayounesc6c2c012019-11-11 11:09:51 -05001436 // hide hang up button and other call buttons
1437 displayHangupButton(false);
1438 // Display the plugins recyclerpicker
1439 binding.recyclerPicker.setVisibility(View.VISIBLE);
1440 movePreview(true);
1441
1442 // Start loading the first or previous plugin if one was active
ayounes019267f2020-01-13 15:14:08 -05001443 if(callMediaHandlers.size() > 0) {
ayounesc6c2c012019-11-11 11:09:51 -05001444 // If no previous plugin was active, take the first, else previous
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001445 int position;
1446 if(previousPluginPosition < 1) {
1447 rp.scrollToPosition(1);
1448 position = 1;
1449 previousPluginPosition = 1;
1450 } else {
1451 position = previousPluginPosition;
1452 }
1453 if (position > 0) {
1454 String callMediaId = callMediaHandlers.get(position-1);
1455 toggleCallMediaHandler(callMediaId, true);
1456 }
ayounesc6c2c012019-11-11 11:09:51 -05001457 }
1458
ayounes47e93992019-10-28 12:09:53 -04001459 } else {
AGS5ef482ce2020-06-12 13:28:51 -04001460 //change preview image
1461 displayVideoSurface(true,true);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001462 if (previousPluginPosition > 0) {
ayounes019267f2020-01-13 15:14:08 -05001463 String callMediaId = callMediaHandlers.
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001464 get(previousPluginPosition-1);
ayounes81087472019-11-08 15:26:05 -05001465
ayounes019267f2020-01-13 15:14:08 -05001466 toggleCallMediaHandler(callMediaId, false);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001467 rp.scrollToPosition(previousPluginPosition);
ayounes47e93992019-10-28 12:09:53 -04001468 }
1469 binding.recyclerPicker.setVisibility(View.GONE);
ayounesc6c2c012019-11-11 11:09:51 -05001470 movePreview(false);
ayounes47e93992019-10-28 12:09:53 -04001471 displayHangupButton(true);
1472 }
ayounes47e93992019-10-28 12:09:53 -04001473 }
1474
ayounesc6c2c012019-11-11 11:09:51 -05001475 /**
1476 * Called whenever a plugin drawable in the recycler picker is clicked or scrolled to
1477 * @param position
1478 */
ayounes47e93992019-10-28 12:09:53 -04001479 @Override
1480 public void onItemSelected(int position) {
1481 Log.i(TAG, "selected position: " + position);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001482 /** If there was a different plugin before, unload it
1483 * If previousPluginPosition = -1 or 0, there was no plugin
1484 */
1485 if (previousPluginPosition > 0) {
1486 String callMediaId = callMediaHandlers.get(previousPluginPosition-1);
1487 toggleCallMediaHandler(callMediaId, false);
1488 }
1489
1490 if (position > 0) {
1491 previousPluginPosition = position;
1492 String callMediaId = callMediaHandlers.get(position-1);
1493 toggleCallMediaHandler(callMediaId, true);
1494 }
1495 }
1496
1497
1498 /**
1499 * Called whenever a plugin drawable in the recycler picker is clicked
1500 * @param position
1501 */
1502 @Override
1503 public void onItemClicked(int position) {
1504 Log.i(TAG, "selected position: " + position);
1505 if (position == 0) {
ayounes47e93992019-10-28 12:09:53 -04001506 /** If there was a different plugin before, unload it
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001507 * If previousPluginPosition = -1 or 0, there was no plugin
ayounes47e93992019-10-28 12:09:53 -04001508 */
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001509 if (previousPluginPosition > 0) {
1510 String callMediaId = callMediaHandlers.get(previousPluginPosition-1);
ayounes019267f2020-01-13 15:14:08 -05001511 toggleCallMediaHandler(callMediaId, false);
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001512 rp.scrollToPosition(previousPluginPosition);
ayounes47e93992019-10-28 12:09:53 -04001513 }
1514
Aline Gondim Santosf781c5b2020-06-26 12:44:44 -04001515 CallActivity callActivity = (CallActivity) getActivity();
1516 callActivity.showSystemUI();
1517
1518 toggleVideoPluginsCarousel(false);
1519 displayVideoPluginsCarousel();
ayounes47e93992019-10-28 12:09:53 -04001520 }
1521 }
Hadrien De Sousaccc947d2017-04-12 14:26:52 -04001522}