blob: 2dd88f8f432fe0b988254215278458933d62287b [file] [log] [blame]
Adrien Béraud04d822c2015-04-02 17:44:36 -04001/*
Adrien Béraudec528bb2016-01-14 16:52:51 -05002 * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
Adrien Béraud04d822c2015-04-02 17:44:36 -04003 *
4 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
Adrien Béraudda712a42015-11-22 23:45:26 -05005 * Author: 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 */
21
22package cx.ring.fragments;
23
24import android.app.Activity;
Adrien Béraudfb6341f2016-03-07 16:18:54 -050025import android.app.Fragment;
26import android.content.BroadcastReceiver;
Adrien Béraud162427f2016-04-12 18:04:08 -040027import android.content.Context;
28import android.content.Intent;
Adrien Béraudfb6341f2016-03-07 16:18:54 -050029import android.content.IntentFilter;
30import android.content.res.Configuration;
31import android.graphics.PixelFormat;
Adrien Béraud8d6a4832016-04-12 18:06:11 -040032import android.hardware.display.DisplayManager;
Adrien Béraudfdff91d2015-12-09 17:54:16 -050033import android.media.AudioManager;
Adrien Béraudb179bab2015-10-08 12:04:22 -040034import android.net.Uri;
Adrien Béraud8d6a4832016-04-12 18:06:11 -040035import android.os.Build;
Adrien Béraud04d822c2015-04-02 17:44:36 -040036import android.os.Bundle;
37import android.os.PowerManager;
38import android.os.PowerManager.WakeLock;
39import android.os.RemoteException;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040040import android.support.annotation.Nullable;
Adrien Béraud162427f2016-04-12 18:04:08 -040041import android.support.v4.app.NotificationManagerCompat;
Romain Bertozzi64a66782016-08-02 12:10:38 -040042import android.support.v4.content.res.ResourcesCompat;
Adrien Bérauddde513c2015-10-22 11:21:52 -040043import android.support.v7.app.ActionBar;
Romain Bertozziad8fd842016-05-11 14:30:35 -040044import android.text.Editable;
Romain Bertozzi64a66782016-08-02 12:10:38 -040045import android.text.TextUtils;
Romain Bertozziad8fd842016-05-11 14:30:35 -040046import android.text.TextWatcher;
Adrien Béraudfb6341f2016-03-07 16:18:54 -050047import android.util.DisplayMetrics;
Adrien Béraud04d822c2015-04-02 17:44:36 -040048import android.util.Log;
Adrien Béraud162427f2016-04-12 18:04:08 -040049import android.view.LayoutInflater;
50import android.view.Menu;
51import android.view.MenuInflater;
52import android.view.MenuItem;
53import android.view.SurfaceHolder;
54import android.view.SurfaceView;
55import android.view.View;
Adrien Béraud162427f2016-04-12 18:04:08 -040056import android.view.ViewGroup;
Romain Bertozziad8fd842016-05-11 14:30:35 -040057import android.view.inputmethod.InputMethodManager;
Romain Bertozziad8fd842016-05-11 14:30:35 -040058import android.widget.EditText;
Adrien Béraud162427f2016-04-12 18:04:08 -040059import android.widget.FrameLayout;
60import android.widget.ImageView;
61import android.widget.RelativeLayout;
62import android.widget.TextView;
63import android.widget.ViewSwitcher;
Adrien Béraud04d822c2015-04-02 17:44:36 -040064
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040065import com.skyfishjy.library.RippleBackground;
66
Adrien Béraudfb6341f2016-03-07 16:18:54 -050067import java.lang.ref.WeakReference;
68import java.util.HashMap;
Romain Bertozzi64a66782016-08-02 12:10:38 -040069import java.util.Locale;
Adrien Béraud04d822c2015-04-02 17:44:36 -040070
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040071import butterknife.BindView;
72import butterknife.ButterKnife;
73import butterknife.OnClick;
Adrien Béraud162427f2016-04-12 18:04:08 -040074import cx.ring.R;
75import cx.ring.adapters.ContactPictureTask;
76import cx.ring.client.ConversationActivity;
Adrien Béraud162427f2016-04-12 18:04:08 -040077import cx.ring.interfaces.CallInterface;
Adrien Béraud04d822c2015-04-02 17:44:36 -040078import cx.ring.model.CallContact;
79import cx.ring.model.Conference;
80import cx.ring.model.SecureSipCall;
81import cx.ring.model.SipCall;
Adrien Béraudfb6341f2016-03-07 16:18:54 -050082import cx.ring.service.CallManagerCallBack;
83import cx.ring.service.DRingService;
84import cx.ring.service.IDRingService;
Adrien Béraudb179bab2015-10-08 12:04:22 -040085import cx.ring.service.LocalService;
Romain Bertozzi64a66782016-08-02 12:10:38 -040086import cx.ring.utils.CropImageUtils;
Romain Bertozziad8fd842016-05-11 14:30:35 -040087import cx.ring.utils.KeyboardVisibilityManager;
Romain Bertozzi64a66782016-08-02 12:10:38 -040088import cx.ring.utils.VCardUtils;
89import ezvcard.VCard;
90import ezvcard.property.Photo;
Adrien Béraud04d822c2015-04-02 17:44:36 -040091
Adrien Béraudfb6341f2016-03-07 16:18:54 -050092public class CallFragment extends Fragment implements CallInterface {
Adrien Béraud04d822c2015-04-02 17:44:36 -040093
Thibault Wittembergb70d5b02016-07-08 16:50:14 -040094 static final private String TAG = CallFragment.class.getSimpleName();
Adrien Béraud04d822c2015-04-02 17:44:36 -040095
Adrien Béraud04d822c2015-04-02 17:44:36 -040096 public static final int REQUEST_TRANSFER = 10;
97
Romain Bertozziad8fd842016-05-11 14:30:35 -040098 //~ Regular expression to match DTMF supported characters : 0 to 9, A, B, C, D, * and #
99 public static final String DTMF_SUPPORTED_CHARS_REGEX = "^[a-dA-D0-9#*]*$";
100
Adrien Béraud04d822c2015-04-02 17:44:36 -0400101 // Screen wake lock for incoming call
102 private WakeLock mScreenWakeLock;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400103
104 @BindView(R.id.contact_bubble_layout)
105 View contactBubbleLayout;
106
107 @BindView(R.id.contact_bubble)
108 ImageView contactBubbleView;
109
110 @BindView(R.id.contact_bubble_txt)
111 TextView contactBubbleTxt;
112
113 @BindView(R.id.contact_bubble_num_txt)
114 TextView contactBubbleNumTxt;
115
116 @BindView(R.id.call_accept_btn)
117 View acceptButton;
118
119 @BindView(R.id.call_refuse_btn)
120 View refuseButton;
121
122 @BindView(R.id.call_hangup_btn)
123 View hangupButton;
124
125 @BindView(R.id.call_status_txt)
126 TextView mCallStatusTxt;
127
128 @BindView(R.id.security_indicator)
129 View securityIndicator;
130
131 @BindView(R.id.security_switcher)
132 ViewSwitcher mSecuritySwitch;
133
134 @BindView(R.id.dialpad_edit_text)
135 EditText mNumeralDialEditText;
136
137 @BindView(R.id.ripple_animation)
138 RippleBackground mPulseAnimation;
139
140 @BindView(R.id.video_preview_surface)
141 SurfaceView mVideoSurface = null;
142
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500143 private MenuItem speakerPhoneBtn = null;
144 private MenuItem addContactBtn = null;
Adrien Béraudf54c4ef2016-03-14 14:41:47 -0400145 private MenuItem flipCameraBtn = null;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400146 private MenuItem dialPadBtn = null;
Adrien Béraudb179bab2015-10-08 12:04:22 -0400147
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400148 @BindView(R.id.camera_preview_surface)
149 SurfaceView videoPreview = null;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400150
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400151 public ConversationCallbacks mCallbacks = sDummyCallbacks;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400152
Adrien Béraudfdff91d2015-12-09 17:54:16 -0500153 private AudioManager audioManager;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500154 private boolean haveVideo = false;
155 private int videoWidth = -1, videoHeight = -1;
156 private int previewWidth = -1, previewHeight = -1;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400157
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500158 private boolean lastVideoSource = true;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500159 private Conference mCachedConference = null;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500160
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400161 private boolean ongoingCall = false;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400162
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400163 private DisplayManager.DisplayListener displayListener;
164
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500165 @Override
166 public void onAttach(Activity activity) {
167 Log.i(TAG, "onAttach");
168 super.onAttach(activity);
169
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400170 if (!(activity instanceof ConversationCallbacks)) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500171 throw new IllegalStateException("Activity must implement fragment's callbacks.");
172 }
173
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400174 mCallbacks = (ConversationCallbacks) activity;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500175
176 IntentFilter intentFilter = new IntentFilter();
177 intentFilter.addAction(CallManagerCallBack.RECORD_STATE_CHANGED);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500178 intentFilter.addAction(CallManagerCallBack.RTCP_REPORT_RECEIVED);
Romain Bertozzi64a66782016-08-02 12:10:38 -0400179 intentFilter.addAction(CallManagerCallBack.VCARD_COMPLETED);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500180
181 intentFilter.addAction(DRingService.VIDEO_EVENT);
182
183 intentFilter.addAction(LocalService.ACTION_CONF_UPDATE);
184
185 getActivity().registerReceiver(mReceiver, intentFilter);
186 }
187
188 @Override
189 public void onDetach() {
190 Log.i(TAG, "onDetach");
191 getActivity().unregisterReceiver(mReceiver);
192 mCallbacks = sDummyCallbacks;
193 super.onDetach();
194 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400195
196 @Override
197 public void onCreate(Bundle savedBundle) {
Adrien Béraudb179bab2015-10-08 12:04:22 -0400198 Log.i(TAG, "onCreate");
Adrien Béraud04d822c2015-04-02 17:44:36 -0400199 super.onCreate(savedBundle);
200
Adrien Béraudfdff91d2015-12-09 17:54:16 -0500201 audioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400202
203 setHasOptionsMenu(true);
204 PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400205 mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "cx.ring.onIncomingCall");
Adrien Béraud04d822c2015-04-02 17:44:36 -0400206 mScreenWakeLock.setReferenceCounted(false);
207
Adrien Béraud04d822c2015-04-02 17:44:36 -0400208 if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
209 mScreenWakeLock.acquire();
210 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500211
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400212 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
213 displayListener = new DisplayManager.DisplayListener() {
214 @Override
Romain Bertozziad8fd842016-05-11 14:30:35 -0400215 public void onDisplayAdded(int displayId) {
216 }
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400217
218 @Override
Romain Bertozziad8fd842016-05-11 14:30:35 -0400219 public void onDisplayRemoved(int displayId) {
220 }
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400221
222 @Override
223 public void onDisplayChanged(int displayId) {
224 getActivity().runOnUiThread(new Runnable() {
225 @Override
226 public void run() {
227 try {
228 mCallbacks.getRemoteService().switchInput(getConference().getId(), lastVideoSource);
229 } catch (RemoteException e) {
230 e.printStackTrace();
231 }
232 }
233 });
234 }
235 };
236 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500237 }
238
239 @Override
240 public void onDestroy() {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400241 super.onDestroy();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500242 Log.i(TAG, "onDestroy");
243 if (mScreenWakeLock != null && mScreenWakeLock.isHeld()) {
244 mScreenWakeLock.release();
245 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400246 }
247
248 /**
Adrien Béraudb179bab2015-10-08 12:04:22 -0400249 * The Activity calling this fragment has to implement this interface
250 */
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400251 public interface ConversationCallbacks extends LocalService.Callbacks {
Adrien Béraudb179bab2015-10-08 12:04:22 -0400252 void startTimer();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400253
Adrien Béraudb179bab2015-10-08 12:04:22 -0400254 void terminateCall();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400255
Adrien Béraudb179bab2015-10-08 12:04:22 -0400256 Conference getDisplayedConference();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400257
Adrien Béraudb179bab2015-10-08 12:04:22 -0400258 void updateDisplayedConference(Conference c);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400259
Adrien Bérauddde513c2015-10-22 11:21:52 -0400260 ActionBar getSupportActionBar();
Adrien Béraudb179bab2015-10-08 12:04:22 -0400261 }
262
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400263 private static final ConversationCallbacks sDummyCallbacks = new ConversationCallbacks() {
264 @Override
265 public void startTimer() {
266 //Dummy implementation
267 }
268
Adrien Béraud04d822c2015-04-02 17:44:36 -0400269 @Override
Romain Bertozziad8fd842016-05-11 14:30:35 -0400270 public void terminateCall() {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400271 //Dummy implementation
Romain Bertozziad8fd842016-05-11 14:30:35 -0400272 }
273
Adrien Béraud04d822c2015-04-02 17:44:36 -0400274 @Override
275 public Conference getDisplayedConference() {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400276 //Dummy implementation
Adrien Béraud04d822c2015-04-02 17:44:36 -0400277 return null;
278 }
Romain Bertozziad8fd842016-05-11 14:30:35 -0400279
Adrien Béraud04d822c2015-04-02 17:44:36 -0400280 @Override
Romain Bertozziad8fd842016-05-11 14:30:35 -0400281 public void updateDisplayedConference(Conference c) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400282 //Dummy implementation
Romain Bertozziad8fd842016-05-11 14:30:35 -0400283 }
284
Adrien Béraud04d822c2015-04-02 17:44:36 -0400285 @Override
Romain Bertozziad8fd842016-05-11 14:30:35 -0400286 public ActionBar getSupportActionBar() {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400287 //Dummy implementation
Romain Bertozziad8fd842016-05-11 14:30:35 -0400288 return null;
289 }
290
Adrien Bérauddde513c2015-10-22 11:21:52 -0400291 @Override
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400292 public IDRingService getRemoteService() {
293 //Dummy implementation
294 return null;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400295 }
Romain Bertozziad8fd842016-05-11 14:30:35 -0400296
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400297 @Override
298 public LocalService getService() {
299 //Dummy implementation
300 return null;
301 }
302 };
Adrien Béraud04d822c2015-04-02 17:44:36 -0400303
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500304 public class CallReceiver extends BroadcastReceiver {
305 private final String TAG = CallReceiver.class.getSimpleName();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400306
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500307 @Override
308 public void onReceive(Context context, Intent intent) {
309 String action = intent.getAction();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500310 if (action.contentEquals(LocalService.ACTION_CONF_UPDATE)) {
311 confUpdate();
312 } else if (action.contentEquals(DRingService.VIDEO_EVENT)) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400313 if (mVideoSurface == null)
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500314 return;
315 Conference conf = getConference();
316 if (intent.hasExtra("start")) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400317 mVideoSurface.setVisibility(View.VISIBLE);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500318 videoPreview.setVisibility(View.VISIBLE);
319 } else if (intent.hasExtra("camera")) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500320 previewWidth = intent.getIntExtra("width", 0);
321 previewHeight = intent.getIntExtra("height", 0);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400322 } else if (conf != null && conf.getId().equals(intent.getStringExtra("call"))) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400323 if (mVideoSurface != null) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500324 haveVideo = intent.getBooleanExtra("started", false);
325 if (haveVideo) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400326 mVideoSurface.setVisibility(View.VISIBLE);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500327 videoPreview.setVisibility(View.VISIBLE);
328 videoWidth = intent.getIntExtra("width", 0);
329 videoHeight = intent.getIntExtra("height", 0);
330 } else {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400331 mVideoSurface.setVisibility(View.GONE);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500332 videoPreview.setVisibility(View.GONE);
333 }
334 }
335 refreshState();
336 }
337 resetVideoSizes();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400338 } else if (action.contentEquals(CallManagerCallBack.RECORD_STATE_CHANGED)) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500339 recordingChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"), intent.getStringExtra("file"));
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500340 } else if (action.contentEquals(CallManagerCallBack.RTCP_REPORT_RECEIVED)) {
341 rtcpReportReceived(null, null); // FIXME
Romain Bertozzi64a66782016-08-02 12:10:38 -0400342 } else if (action.contentEquals(CallManagerCallBack.VCARD_COMPLETED)) {
343 updateContactBubble();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500344 } else {
345 Log.e(TAG, "Unknown action: " + intent.getAction());
346 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400347 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400348 }
Romain Bertozziad8fd842016-05-11 14:30:35 -0400349
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500350 private final CallReceiver mReceiver = new CallReceiver();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400351
Adrien Béraudb179bab2015-10-08 12:04:22 -0400352 public void refreshState() {
353 Conference conf = getConference();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500354
Romain Bertozziad8fd842016-05-11 14:30:35 -0400355 if (conf == null) {
Adrien Béraudb179bab2015-10-08 12:04:22 -0400356 contactBubbleView.setImageBitmap(null);
357 contactBubbleTxt.setText("");
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500358 contactBubbleNumTxt.setText("");
Adrien Béraudb179bab2015-10-08 12:04:22 -0400359 acceptButton.setVisibility(View.GONE);
360 refuseButton.setVisibility(View.GONE);
361 hangupButton.setVisibility(View.GONE);
362 } else if (conf.getParticipants().size() == 1) {
363 SipCall call = conf.getParticipants().get(0);
364 if (call.isIncoming() && call.isRinging()) {
365 Log.w(TAG, "CallFragment refreshState INCOMING " + call.getCallId());
366 initIncomingCallDisplay();
367 } else if (conf.getParticipants().get(0).isRinging()) {
368 Log.w(TAG, "CallFragment refreshState RINGING " + call.getCallId());
369 initOutGoingCallDisplay();
370 } else if (call.isOngoing()) {
371 initNormalStateDisplay();
372 }
373 } else if (conf.getParticipants().size() > 1) {
374 initNormalStateDisplay();
375 }
Adrien Béraud329aee72016-03-14 14:40:14 -0400376
377 getActivity().invalidateOptionsMenu();
Adrien Béraudb179bab2015-10-08 12:04:22 -0400378 }
379
Adrien Béraud04d822c2015-04-02 17:44:36 -0400380 @Override
381 public void onCreateOptionsMenu(Menu m, MenuInflater inf) {
Adrien Béraudda712a42015-11-22 23:45:26 -0500382 super.onCreateOptionsMenu(m, inf);
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500383 inf.inflate(R.menu.ac_call, m);
384 speakerPhoneBtn = m.findItem(R.id.menuitem_speaker);
385 addContactBtn = m.findItem(R.id.menuitem_addcontact);
Adrien Béraudf54c4ef2016-03-14 14:41:47 -0400386 flipCameraBtn = m.findItem(R.id.menuitem_camera_flip);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400387 dialPadBtn = m.findItem(R.id.menuitem_dialpad);
Adrien Béraudda712a42015-11-22 23:45:26 -0500388 }
389
390 @Override
391 public void onPrepareOptionsMenu(Menu menu) {
392 super.onPrepareOptionsMenu(menu);
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500393 if (speakerPhoneBtn != null) {
Adrien Béraudfdff91d2015-12-09 17:54:16 -0500394 boolean speakerPhone = audioManager.isSpeakerphoneOn();
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500395 if (speakerPhoneBtn.getIcon() != null)
396 speakerPhoneBtn.getIcon().setAlpha(speakerPhone ? 255 : 128);
397 speakerPhoneBtn.setChecked(speakerPhone);
398 }
399 if (addContactBtn != null) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400400 SipCall call = (getConference() != null && !getConference().getParticipants().isEmpty()) ? getFirstParticipant() : null;
Adrien Béraud162427f2016-04-12 18:04:08 -0400401 addContactBtn.setVisible(call != null && null != call.getContact() && call.getContact().isUnknown());
Adrien Béraudda712a42015-11-22 23:45:26 -0500402 }
Romain Bertozziad8fd842016-05-11 14:30:35 -0400403
Adrien Béraudf54c4ef2016-03-14 14:41:47 -0400404 flipCameraBtn.setVisible(haveVideo);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400405
406 if (dialPadBtn != null) {
407 dialPadBtn.setVisible(ongoingCall && getConference() != null && !getConference().isIncoming());
408 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400409 }
410
411 @Override
412 public boolean onOptionsItemSelected(MenuItem item) {
413 super.onOptionsItemSelected(item);
414 switch (item.getItemId()) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500415 case android.R.id.home:
416 mCallbacks.terminateCall();
417 break;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400418 case R.id.menuitem_chat:
Adrien Béraudb179bab2015-10-08 12:04:22 -0400419 Intent intent = new Intent()
420 .setClass(getActivity(), ConversationActivity.class)
421 .setAction(Intent.ACTION_VIEW)
Alexandre Lision57314dd2016-09-17 01:44:37 -0400422 .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP)
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400423 .setData(Uri.withAppendedPath(ConversationActivity.CONTENT_URI, getFirstParticipant().getContact().getIds().get(0)));
Alexandre Lision57314dd2016-09-17 01:44:37 -0400424 startActivity(intent);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400425 break;
Adrien Béraudda712a42015-11-22 23:45:26 -0500426 case R.id.menuitem_addcontact:
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400427 startActivityForResult(getFirstParticipant().getContact().getAddNumberIntent(), ConversationActivity.REQ_ADD_CONTACT);
Adrien Béraudda712a42015-11-22 23:45:26 -0500428 break;
429 case R.id.menuitem_speaker:
Adrien Béraudfdff91d2015-12-09 17:54:16 -0500430 audioManager.setSpeakerphoneOn(!audioManager.isSpeakerphoneOn());
Adrien Béraudda712a42015-11-22 23:45:26 -0500431 getActivity().invalidateOptionsMenu();
432 break;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500433 case R.id.menuitem_camera_flip:
434 lastVideoSource = !lastVideoSource;
435 try {
436 mCallbacks.getRemoteService().switchInput(getConference().getId(), lastVideoSource);
437 } catch (RemoteException e) {
438 e.printStackTrace();
439 }
440 item.setIcon(lastVideoSource ? R.drawable.ic_camera_front_white_24dp : R.drawable.ic_camera_rear_white_24dp);
441 break;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400442 case R.id.menuitem_dialpad:
443 KeyboardVisibilityManager.showKeyboard(getActivity(),
444 mNumeralDialEditText,
445 InputMethodManager.SHOW_IMPLICIT);
446 break;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400447 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400448 return true;
449 }
450
451 @Override
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500452 public void onStop() {
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400453 super.onStop();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500454
455 Conference c = getConference();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400456 Log.w(TAG, "onStop() haveVideo=" + haveVideo);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500457
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400458 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
459 DisplayManager displayManager = (DisplayManager) getActivity().getSystemService(Context.DISPLAY_SERVICE);
460 displayManager.unregisterDisplayListener(displayListener);
461 }
462
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500463 DRingService.videoSurfaces.remove(c.getId());
464 DRingService.mCameraPreviewSurface.clear();
465 try {
466 IDRingService service = mCallbacks.getRemoteService();
467 if (service != null) {
468 service.videoSurfaceRemoved(c.getId());
469 service.videoPreviewSurfaceRemoved();
470 }
471 } catch (RemoteException e) {
472 e.printStackTrace();
473 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400474 }
475
476 @Override
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500477 public void onStart() {
478 super.onStart();
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400479
480 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
481 DisplayManager displayManager = (DisplayManager) getActivity().getSystemService(Context.DISPLAY_SERVICE);
482 displayManager.registerDisplayListener(displayListener, null);
483 }
484
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500485 Conference c = getConference();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400486 if (c != null && mVideoSurface != null && c.resumeVideo) {
487 Log.i(TAG, "Resuming video");
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500488 haveVideo = true;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400489 mVideoSurface.setVisibility(View.VISIBLE);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500490 videoPreview.setVisibility(View.VISIBLE);
491 c.resumeVideo = false;
492 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400493 }
494
495 @Override
496 public void onResume() {
497 super.onResume();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400498 Log.i(TAG, "onResume()");
Adrien Béraudda712a42015-11-22 23:45:26 -0500499 Conference c = getConference();
Romain Bertozziad8fd842016-05-11 14:30:35 -0400500
501 this.confUpdate();
502
503 if (getActivity() != null) {
504 getActivity().invalidateOptionsMenu();
505 }
506
Adrien Béraudda712a42015-11-22 23:45:26 -0500507 if (c != null) {
508 c.mVisible = true;
509 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
510 notificationManager.cancel(c.notificationId);
Adrien Béraudecaa2052016-03-22 17:23:44 -0400511 if (c.resumeVideo) {
512 Log.w(TAG, "Resuming video");
513 haveVideo = true;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400514 mVideoSurface.setVisibility(View.VISIBLE);
Adrien Béraudecaa2052016-03-22 17:23:44 -0400515 videoPreview.setVisibility(View.VISIBLE);
516 c.resumeVideo = false;
517 }
Adrien Béraudda712a42015-11-22 23:45:26 -0500518 }
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500519
520 refreshState();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400521 }
522
523 @Override
524 public void onPause() {
Adrien Béraudecaa2052016-03-22 17:23:44 -0400525 Log.w(TAG, "onPause() haveVideo=" + haveVideo);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400526 super.onPause();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500527
Adrien Béraudda712a42015-11-22 23:45:26 -0500528 Conference c = getConference();
529 if (c != null) {
530 c.mVisible = false;
Adrien Béraudecaa2052016-03-22 17:23:44 -0400531 c.resumeVideo = haveVideo;
Adrien Béraudda712a42015-11-22 23:45:26 -0500532 c.showCallNotification(getActivity());
533 }
534 }
535
536 public void confUpdate() {
Adrien Béraudda2eb1a2016-01-11 13:15:12 -0500537 Log.w(TAG, "confUpdate()");
538
Adrien Béraudda712a42015-11-22 23:45:26 -0500539 LocalService service = mCallbacks.getService();
540 if (service == null)
541 return;
542
543 Conference c = service.getConference(getConference().getId());
544 mCallbacks.updateDisplayedConference(c);
545 if (c == null || c.getParticipants().isEmpty()) {
546 mCallbacks.terminateCall();
547 return;
548 }
549
Romain Bertozziad8fd842016-05-11 14:30:35 -0400550 int newState = c.getHumanState();
551 String newStateString = (newState == R.string.call_human_state_none ||
552 newState == R.string.conference_human_state_default)
553 ? "" :
554 getString(newState);
Adrien Béraudda712a42015-11-22 23:45:26 -0500555 if (c.isOnGoing()) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500556 ongoingCall = true;
Adrien Béraudda712a42015-11-22 23:45:26 -0500557 initNormalStateDisplay();
558 } else if (c.isRinging()) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500559 ongoingCall = false;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400560 mCallStatusTxt.setText(newStateString);
Adrien Béraudda712a42015-11-22 23:45:26 -0500561
562 if (c.isIncoming()) {
563 initIncomingCallDisplay();
564 } else
565 initOutGoingCallDisplay();
566 } else {
567 NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
568 notificationManager.cancel(c.notificationId);
Romain Bertozziad8fd842016-05-11 14:30:35 -0400569 mCallStatusTxt.setText(newStateString);
Adrien Béraudda712a42015-11-22 23:45:26 -0500570 mCallbacks.terminateCall();
571 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400572 }
573
574 @Override
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500575 public void recordingChanged(Conference c, String callID, String filename) {
576
577 }
578
579 @Override
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500580 public void rtcpReportReceived(Conference c, HashMap<String, Integer> stats) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400581 // No implementation yet
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500582 }
583
584 @Override
Adrien Béraud04d822c2015-04-02 17:44:36 -0400585 public void onActivityResult(int requestCode, int resultCode, Intent data) {
586 super.onActivityResult(requestCode, resultCode, data);
587 SipCall transfer;
588 if (requestCode == REQUEST_TRANSFER) {
589 switch (resultCode) {
590 case TransferDFragment.RESULT_TRANSFER_CONF:
591 Conference c = data.getParcelableExtra("target");
592 transfer = data.getParcelableExtra("transfer");
593 try {
Adrien Béraudb179bab2015-10-08 12:04:22 -0400594 mCallbacks.getRemoteService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId());
Adrien Béraud04d822c2015-04-02 17:44:36 -0400595 } catch (RemoteException e) {
596 e.printStackTrace();
597 }
598 break;
599
600 case TransferDFragment.RESULT_TRANSFER_NUMBER:
601 String to = data.getStringExtra("to_number");
602 transfer = data.getParcelableExtra("transfer");
603 try {
Adrien Béraudb179bab2015-10-08 12:04:22 -0400604 mCallbacks.getRemoteService().transfer(transfer.getCallId(), to);
605 mCallbacks.getRemoteService().hangUp(transfer.getCallId());
Adrien Béraud04d822c2015-04-02 17:44:36 -0400606 } catch (RemoteException e) {
607 e.printStackTrace();
608 }
609 break;
610 case Activity.RESULT_CANCELED:
611 default:
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500612 confUpdate();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400613 break;
614 }
615 }
616 }
617
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500618 void resetVideoSizes() {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400619 ViewGroup rootView = (ViewGroup) getView();
620 if (rootView == null)
621 return;
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500622
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400623 double videoRatio = videoWidth / (double) videoHeight;
624 double screenRatio = getView().getWidth() / (double) getView().getHeight();
625
626 FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) mVideoSurface.getLayoutParams();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500627 int oldW = params.width;
628 int oldH = params.height;
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400629 if (videoRatio >= screenRatio) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500630 params.width = RelativeLayout.LayoutParams.MATCH_PARENT;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400631 params.height = (int) (videoHeight * (double) rootView.getWidth() / (double) videoWidth);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500632 } else {
633 params.height = RelativeLayout.LayoutParams.MATCH_PARENT;
Romain Bertozziad8fd842016-05-11 14:30:35 -0400634 params.width = (int) (videoWidth * (double) rootView.getHeight() / (double) videoHeight);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500635 }
636
637 if (oldW != params.width || oldH != params.height) {
638 Log.w(TAG, "onLayoutChange " + params.width + " x " + params.height);
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400639 mVideoSurface.setLayoutParams(params);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500640 }
641
642 DisplayMetrics metrics = getResources().getDisplayMetrics();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400643 FrameLayout.LayoutParams paramsPreview = (FrameLayout.LayoutParams) videoPreview.getLayoutParams();
644 oldW = paramsPreview.width;
645 oldH = paramsPreview.height;
646 double previewMaxDim = Math.max(previewWidth, previewHeight);
647 double previewRatio = metrics.density * 160. / previewMaxDim;
648 paramsPreview.width = (int) (previewWidth * previewRatio);
649 paramsPreview.height = (int) (previewHeight * previewRatio);
650 if (oldW != paramsPreview.width || oldH != paramsPreview.height) {
651 Log.i(TAG, "onLayoutChange " + paramsPreview.width + " x " + paramsPreview.height);
652 videoPreview.setLayoutParams(paramsPreview);
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500653 }
654 }
655
656 @Override
657 public void onConfigurationChanged(Configuration newConfig) {
658 if (videoPreview.getVisibility() == View.VISIBLE) {
659 try {
Adrien Béraud8d6a4832016-04-12 18:06:11 -0400660 mCallbacks.getRemoteService().setPreviewSettings();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500661 mCallbacks.getRemoteService().videoPreviewSurfaceAdded();
662 } catch (RemoteException e) {
663 e.printStackTrace();
664 }
665 }
666 }
667
Adrien Béraud04d822c2015-04-02 17:44:36 -0400668 @Override
669 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
670 Log.i(TAG, "onCreateView");
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400671 View rootView = inflater.inflate(R.layout.frag_call, container, false);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400672
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400673 ButterKnife.bind(this, rootView);
674
Romain Bertozziad8fd842016-05-11 14:30:35 -0400675 mNumeralDialEditText.requestFocus();
676 mNumeralDialEditText.addTextChangedListener(new TextWatcher() {
677 @Override
678 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
679 //~ Empty
680 }
681
682 @Override
683 public void onTextChanged(CharSequence s, int start, int before, int count) {
684 String editTextString = s.toString();
685 String lastChar = editTextString.substring(start, start + count);
686 if (lastChar.matches(DTMF_SUPPORTED_CHARS_REGEX)) {
687 try {
688 Log.d(TAG, "Sending DTMF: " + lastChar.toUpperCase());
689 mCallbacks.getRemoteService().playDtmf(lastChar.toUpperCase());
690 } catch (RemoteException exc) {
691 exc.printStackTrace();
692 }
693 }
694 }
695
696 @Override
697 public void afterTextChanged(Editable s) {
698 //~ Empty
699 }
700 });
701
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500702
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400703 mVideoSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
704 mVideoSurface.getHolder().addCallback(new SurfaceHolder.Callback() {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500705 @Override
706 public void surfaceCreated(SurfaceHolder holder) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500707 contactBubbleLayout.setVisibility(View.GONE);
708 Conference c = getConference();
709 DRingService.videoSurfaces.put(c.getId(), new WeakReference<>(holder));
710 try {
711 mCallbacks.getRemoteService().videoSurfaceAdded(c.getId());
712 } catch (RemoteException e) {
713 e.printStackTrace();
714 }
715 }
716
717 @Override
718 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
719 Log.i(TAG, "video surfaceChanged " + format + ", " + width + " x " + height);
720 }
721
722 @Override
723 public void surfaceDestroyed(SurfaceHolder holder) {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500724 Conference c = getConference();
725 DRingService.videoSurfaces.remove(c.getId());
726 try {
727 IDRingService service = mCallbacks.getRemoteService();
728 if (service != null)
729 service.videoSurfaceRemoved(c.getId());
730 } catch (RemoteException e) {
731 e.printStackTrace();
732 }
733 }
734 });
735
736 rootView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
737 @Override
738 public void onLayoutChange(View parent, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
739 resetVideoSizes();
740 }
741 });
742 rootView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
743 @Override
744 public void onSystemUiVisibilityChange(int visibility) {
745 boolean ui = (visibility & (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN)) == 0;
746 if (ongoingCall) {
747 hangupButton.setVisibility(ui ? View.VISIBLE : View.GONE);
748 }
749 }
750 });
751
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500752 videoPreview.getHolder().setFormat(PixelFormat.RGBA_8888);
753 videoPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
754 @Override
755 public void surfaceCreated(SurfaceHolder holder) {
756 DRingService.mCameraPreviewSurface = new WeakReference<>(holder);
757 try {
758 mCallbacks.getRemoteService().videoPreviewSurfaceAdded();
759 } catch (RemoteException e) {
760 e.printStackTrace();
761 }
762 }
763
764 @Override
765 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
766 Log.i(TAG, "videoPreview surfaceChanged " + format + ", " + width + " x " + height);
767 }
768
769 @Override
770 public void surfaceDestroyed(SurfaceHolder holder) {
771 if (videoPreview != null && DRingService.mCameraPreviewSurface.get() == holder) {
772 DRingService.mCameraPreviewSurface.clear();
773 }
774 try {
775 IDRingService service = mCallbacks.getRemoteService();
776 if (service != null)
777 service.videoPreviewSurfaceRemoved();
778 } catch (RemoteException e) {
779 e.printStackTrace();
780 }
781 }
782 });
783 videoPreview.setZOrderMediaOverlay(true);
784
Adrien Béraud04d822c2015-04-02 17:44:36 -0400785 return rootView;
786 }
787
788 public Conference getConference() {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500789 Conference c = mCallbacks.getDisplayedConference();
790 if (c != null) {
791 if (mCachedConference != c)
792 mCachedConference = c;
793 return c;
794 }
795 return mCachedConference;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400796 }
797
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500798 private void initContactDisplay(final SipCall call) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400799
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500800 CallContact contact = call.getContact();
801 final String name = contact.getDisplayName();
802 contactBubbleTxt.setText(name);
803 if (call.getNumber().contentEquals(name)) {
804 contactBubbleNumTxt.setVisibility(View.GONE);
805 } else {
806 contactBubbleNumTxt.setVisibility(View.VISIBLE);
807 contactBubbleNumTxt.setText(call.getNumber());
808 }
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400809
810 mPulseAnimation.startRippleAnimation();
811
Romain Bertozzi64a66782016-08-02 12:10:38 -0400812 updateContactBubble();
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400813
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500814 ActionBar ab = mCallbacks.getSupportActionBar();
815 ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE);
816 ab.setTitle(name);
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500817 }
818
Adrien Béraud04d822c2015-04-02 17:44:36 -0400819 private void initNormalStateDisplay() {
820 Log.i(TAG, "Start normal display");
Adrien Béraudb179bab2015-10-08 12:04:22 -0400821 mCallbacks.startTimer();
822 acceptButton.setVisibility(View.GONE);
823 refuseButton.setVisibility(View.GONE);
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400824 hangupButton.setVisibility(View.VISIBLE);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400825
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400826 final SipCall call = getFirstParticipant();
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500827 initContactDisplay(call);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400828
Romain Bertozziad8fd842016-05-11 14:30:35 -0400829 if (getActivity() != null) {
830 getActivity().invalidateOptionsMenu();
831 }
832
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500833 contactBubbleLayout.setVisibility(haveVideo ? View.GONE : View.VISIBLE);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400834 updateSecurityDisplay();
835 }
836
837 private void updateSecurityDisplay() {
Adrien Béraudda712a42015-11-22 23:45:26 -0500838 //First we check if all participants use a security layer.
Romain Bertozzi64a66782016-08-02 12:10:38 -0400839 boolean secureCall = !getConference().getParticipants().isEmpty();
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500840 for (SipCall c : getConference().getParticipants())
Romain Bertozzi64a66782016-08-02 12:10:38 -0400841 secureCall &= c instanceof SecureSipCall && ((SecureSipCall) c).isSecure();
Adrien Béraudb179bab2015-10-08 12:04:22 -0400842
Romain Bertozzi64a66782016-08-02 12:10:38 -0400843 securityIndicator.setVisibility(secureCall ? View.VISIBLE : View.GONE);
844 if (!secureCall)
Adrien Béraud04d822c2015-04-02 17:44:36 -0400845 return;
846
847 Log.i(TAG, "Enable security display");
848 if (getConference().hasMultipleParticipants()) {
849 //TODO What layout should we put?
850 } else {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400851 final SecureSipCall secured = (SecureSipCall) getFirstParticipant();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400852 switch (secured.displayModule()) {
853 case SecureSipCall.DISPLAY_GREEN_LOCK:
854 Log.i(TAG, "DISPLAY_GREEN_LOCK");
855 showLock(R.drawable.green_lock);
856 break;
857 case SecureSipCall.DISPLAY_RED_LOCK:
858 Log.i(TAG, "DISPLAY_RED_LOCK");
859 showLock(R.drawable.red_lock);
860 break;
Adrien Béraud04d822c2015-04-02 17:44:36 -0400861 case SecureSipCall.DISPLAY_NONE:
862 break;
863 }
864 }
865 }
866
867 private void showLock(int resId) {
868 ImageView lock = (ImageView) mSecuritySwitch.findViewById(R.id.lock_image);
Romain Bertozzi64a66782016-08-02 12:10:38 -0400869 lock.setImageDrawable(ResourcesCompat.getDrawable(getResources(), resId, null));
Adrien Béraud04d822c2015-04-02 17:44:36 -0400870 mSecuritySwitch.setDisplayedChild(1);
871 mSecuritySwitch.setVisibility(View.VISIBLE);
872 }
873
874 private void initIncomingCallDisplay() {
875 Log.i(TAG, "Start incoming display");
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400876 final SipCall call = getFirstParticipant();
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500877 if (mCallbacks.getService().getAccount(call.getAccount()).isAutoanswerEnabled()) {
Adrien Béraud04d822c2015-04-02 17:44:36 -0400878 try {
Adrien Béraudfb6341f2016-03-07 16:18:54 -0500879 mCallbacks.getRemoteService().accept(call.getCallId());
880 } catch (Exception e) {
Adrien Béraud04d822c2015-04-02 17:44:36 -0400881 e.printStackTrace();
882 }
883 } else {
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500884 initContactDisplay(call);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400885 acceptButton.setVisibility(View.VISIBLE);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400886 refuseButton.setVisibility(View.VISIBLE);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400887 hangupButton.setVisibility(View.GONE);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400888 }
889 }
890
891 private void initOutGoingCallDisplay() {
892 Log.i(TAG, "Start outgoing display");
Adrien Béraudb179bab2015-10-08 12:04:22 -0400893
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400894 final SipCall call = getFirstParticipant();
Adrien Béraud6c4cedb2015-12-11 14:34:20 -0500895 initContactDisplay(call);
Adrien Béraudb179bab2015-10-08 12:04:22 -0400896
897 acceptButton.setVisibility(View.GONE);
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400898 refuseButton.setVisibility(View.VISIBLE);
899 hangupButton.setVisibility(View.GONE);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400900 }
Adrien Béraudda712a42015-11-22 23:45:26 -0500901
Adrien Béraud04d822c2015-04-02 17:44:36 -0400902 public void updateTime() {
Adrien Béraudda712a42015-11-22 23:45:26 -0500903 if (getConference() != null && !getConference().getParticipants().isEmpty()) {
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400904 long duration = System.currentTimeMillis() - getFirstParticipant().getTimestampStart();
Adrien Béraud04d822c2015-04-02 17:44:36 -0400905 duration = duration / 1000;
906 if (getConference().isOnGoing())
Romain Bertozzi64a66782016-08-02 12:10:38 -0400907 mCallStatusTxt.setText(String.format(Locale.getDefault(), "%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
Adrien Béraud04d822c2015-04-02 17:44:36 -0400908 }
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400909 }
Adrien Béraud04d822c2015-04-02 17:44:36 -0400910
Romain Bertozzi64a66782016-08-02 12:10:38 -0400911 /**
912 * Updates the bubble contact image with the vcard image, the contact image or by default the
913 * contact picture drawable.
914 */
915 private void updateContactBubble() {
916 Conference conference = this.getConference();
917 Context context = getActivity();
918 if (conference == null || context == null) {
919 return;
920 }
921
922 SipCall participant = getFirstParticipant();
923 if (participant == null) {
924 return;
925 }
926
927 VCard vcard;
928 String username = participant.getNumberUri().username;
929 vcard = VCardUtils.loadFromDisk(username + ".vcf", context);
930 if (vcard == null) {
931 Log.d(TAG, "No vcard.");
932 setDefaultPhoto();
933 return;
934 } else {
935 Log.d(TAG, "VCard found: " + vcard);
936 }
937
938 if (!vcard.getPhotos().isEmpty()) {
939 Photo tmp = vcard.getPhotos().get(0);
940 contactBubbleView.setImageBitmap(CropImageUtils.cropImageToCircle(tmp.getData()));
941 } else {
942 setDefaultPhoto();
943 }
944
945 if (TextUtils.isEmpty(vcard.getFormattedName().getValue())) {
946 return;
947 }
948 contactBubbleTxt.setText(vcard.getFormattedName().getValue());
949 if (participant.getNumber().contentEquals(vcard.getFormattedName().getValue())) {
950 contactBubbleNumTxt.setVisibility(View.GONE);
951 } else {
952 contactBubbleNumTxt.setVisibility(View.VISIBLE);
953 contactBubbleNumTxt.setText(participant.getNumber());
954 }
955 }
956
957
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400958 @OnClick({R.id.call_hangup_btn, R.id.call_refuse_btn})
959 public void hangUpClicked() {
960 try {
961 final SipCall call = getFirstParticipant();
962 if (call == null) {
963 return;
964 }
965 final String callId = call.getCallId();
966 mCallbacks.getRemoteService().hangUp(callId);
967 mCallbacks.terminateCall();
968 } catch (RemoteException e) {
969 e.printStackTrace();
970 }
971 }
972
973 @OnClick(R.id.call_accept_btn)
974 public void acceptClicked() {
975 final SipCall call = getFirstParticipant();
976 if (call == null) {
977 return;
978 }
979 try {
980 mCallbacks.getRemoteService().accept(call.getCallId());
981 } catch (RemoteException e) {
982 e.printStackTrace();
983 }
984 }
985
986 /**
987 * Helper accessor that check nullity or emptiness of components to access first call participant
Romain Bertozzi64a66782016-08-02 12:10:38 -0400988 *
Thibault Wittembergb70d5b02016-07-08 16:50:14 -0400989 * @return the first participant or null
990 */
991 @Nullable
992 private SipCall getFirstParticipant() {
993 if (getConference() == null || getConference().getParticipants() == null || getConference().getParticipants().isEmpty()) {
994 return null;
995 }
996 return getConference().getParticipants().get(0);
Adrien Béraud04d822c2015-04-02 17:44:36 -0400997 }
Romain Bertozzi64a66782016-08-02 12:10:38 -0400998
999 private void setDefaultPhoto() {
1000 if (getConference() != null
1001 && getConference().getParticipants() != null
1002 && !getConference().getParticipants().isEmpty()) {
1003 final SipCall call = getConference().getParticipants().get(0);
1004 final CallContact contact = call.getContact();
1005 if (contact != null) {
1006 new ContactPictureTask(getActivity(), contactBubbleView, contact).run();
1007 }
1008 } else {
1009 contactBubbleView.setImageDrawable(
1010 ResourcesCompat.getDrawable(getResources(), R.drawable.ic_contact_picture, null));
1011 }
1012 }
Adrien Béraud04d822c2015-04-02 17:44:36 -04001013}