RtpSessionActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.Manifest;
  4import android.annotation.SuppressLint;
  5import android.content.Context;
  6import android.content.Intent;
  7import android.databinding.DataBindingUtil;
  8import android.os.Build;
  9import android.os.Bundle;
 10import android.os.PowerManager;
 11import android.support.annotation.NonNull;
 12import android.support.annotation.StringRes;
 13import android.util.Log;
 14import android.view.View;
 15import android.view.WindowManager;
 16import android.widget.Toast;
 17
 18import com.google.common.base.Optional;
 19import com.google.common.collect.ImmutableList;
 20
 21import org.webrtc.SurfaceViewRenderer;
 22import org.webrtc.VideoTrack;
 23
 24import java.lang.ref.WeakReference;
 25import java.util.Arrays;
 26import java.util.Set;
 27
 28import eu.siacs.conversations.Config;
 29import eu.siacs.conversations.R;
 30import eu.siacs.conversations.databinding.ActivityRtpSessionBinding;
 31import eu.siacs.conversations.entities.Account;
 32import eu.siacs.conversations.entities.Contact;
 33import eu.siacs.conversations.services.AppRTCAudioManager;
 34import eu.siacs.conversations.services.XmppConnectionService;
 35import eu.siacs.conversations.utils.PermissionUtils;
 36import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
 37import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
 38import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
 39import rocks.xmpp.addr.Jid;
 40
 41import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied;
 42import static java.util.Arrays.asList;
 43
 44public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate {
 45
 46    private static final String PROXIMITY_WAKE_LOCK_TAG = "conversations:in-rtp-session";
 47
 48    private static final int REQUEST_ACCEPT_CALL = 0x1111;
 49
 50    public static final String EXTRA_WITH = "with";
 51    public static final String EXTRA_SESSION_ID = "session_id";
 52    public static final String EXTRA_LAST_REPORTED_STATE = "last_reported_state";
 53
 54    public static final String ACTION_ACCEPT_CALL = "action_accept_call";
 55    public static final String ACTION_MAKE_VOICE_CALL = "action_make_voice_call";
 56    public static final String ACTION_MAKE_VIDEO_CALL = "action_make_video_call";
 57
 58
 59    private WeakReference<JingleRtpConnection> rtpConnectionReference;
 60
 61    private ActivityRtpSessionBinding binding;
 62    private PowerManager.WakeLock mProximityWakeLock;
 63
 64    @Override
 65    public void onCreate(Bundle savedInstanceState) {
 66        super.onCreate(savedInstanceState);
 67        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
 68                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
 69                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
 70                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
 71        Log.d(Config.LOGTAG, "RtpSessionActivity.onCreate()");
 72        this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
 73        setSupportActionBar(binding.toolbar);
 74    }
 75
 76    @Override
 77    public void onStart() {
 78        super.onStart();
 79        Log.d(Config.LOGTAG, "RtpSessionActivity.onStart()");
 80    }
 81
 82    private void endCall(View view) {
 83        endCall();
 84    }
 85
 86    private void endCall() {
 87        if (this.rtpConnectionReference == null) {
 88            final Intent intent = getIntent();
 89            final Account account = extractAccount(intent);
 90            final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
 91            xmppConnectionService.getJingleConnectionManager().retractSessionProposal(account, with.asBareJid());
 92            finish();
 93        } else {
 94            requireRtpConnection().endCall();
 95        }
 96    }
 97
 98    private void rejectCall(View view) {
 99        requireRtpConnection().rejectCall();
100        finish();
101    }
102
103    private void acceptCall(View view) {
104        requestPermissionsAndAcceptCall();
105    }
106
107    private void requestPermissionsAndAcceptCall() {
108        if (PermissionUtils.hasPermission(this, ImmutableList.of(Manifest.permission.RECORD_AUDIO), REQUEST_ACCEPT_CALL)) {
109            //TODO like wise the propose; we might just wait here for the audio manager to come up
110            putScreenInCallMode();
111            requireRtpConnection().acceptCall();
112        }
113    }
114
115    @SuppressLint("WakelockTimeout")
116    private void putScreenInCallMode() {
117        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
118        final JingleRtpConnection rtpConnection = rtpConnectionReference != null ? rtpConnectionReference.get() : null;
119        final AppRTCAudioManager audioManager = rtpConnection == null ? null : rtpConnection.getAudioManager();
120        if (audioManager == null || audioManager.getSelectedAudioDevice() == AppRTCAudioManager.AudioDevice.EARPIECE) {
121            acquireProximityWakeLock();
122        }
123    }
124
125    private void acquireProximityWakeLock() {
126        final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
127        if (powerManager == null) {
128            Log.e(Config.LOGTAG, "power manager not available");
129            return;
130        }
131        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
132            if (this.mProximityWakeLock == null) {
133                this.mProximityWakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, PROXIMITY_WAKE_LOCK_TAG);
134            }
135            if (!this.mProximityWakeLock.isHeld()) {
136                Log.d(Config.LOGTAG, "acquiring proximity wake lock");
137                this.mProximityWakeLock.acquire();
138            }
139        }
140    }
141
142    private void releaseProximityWakeLock() {
143        if (this.mProximityWakeLock != null && mProximityWakeLock.isHeld()) {
144            Log.d(Config.LOGTAG, "releasing proximity wake lock");
145            this.mProximityWakeLock.release();
146            this.mProximityWakeLock = null;
147        }
148    }
149
150    private void putProximityWakeLockInProperState() {
151        if (requireRtpConnection().getAudioManager().getSelectedAudioDevice() == AppRTCAudioManager.AudioDevice.EARPIECE) {
152            acquireProximityWakeLock();
153        } else {
154            releaseProximityWakeLock();
155        }
156    }
157
158    @Override
159    protected void refreshUiReal() {
160
161    }
162
163    @Override
164    public void onNewIntent(final Intent intent) {
165        super.onNewIntent(intent);
166        setIntent(intent);
167        if (xmppConnectionService == null) {
168            Log.d(Config.LOGTAG, "RtpSessionActivity: background service wasn't bound in onNewIntent()");
169            return;
170        }
171        final Account account = extractAccount(intent);
172        final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
173        final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
174        if (sessionId != null) {
175            Log.d(Config.LOGTAG, "reinitializing from onNewIntent()");
176            initializeActivityWithRunningRtpSession(account, with, sessionId);
177            if (ACTION_ACCEPT_CALL.equals(intent.getAction())) {
178                Log.d(Config.LOGTAG, "accepting call from onNewIntent()");
179                requestPermissionsAndAcceptCall();
180                resetIntent(intent.getExtras());
181            }
182        } else {
183            throw new IllegalStateException("received onNewIntent without sessionId");
184        }
185    }
186
187    @Override
188    void onBackendConnected() {
189        final Intent intent = getIntent();
190        final Account account = extractAccount(intent);
191        final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
192        final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
193        if (sessionId != null) {
194            initializeActivityWithRunningRtpSession(account, with, sessionId);
195            if (ACTION_ACCEPT_CALL.equals(intent.getAction())) {
196                Log.d(Config.LOGTAG, "intent action was accept");
197                requestPermissionsAndAcceptCall();
198                resetIntent(intent.getExtras());
199            }
200        } else if (asList(ACTION_MAKE_VIDEO_CALL, ACTION_MAKE_VOICE_CALL).contains(intent.getAction())) {
201            proposeJingleRtpSession(account, with);
202            binding.with.setText(account.getRoster().getContact(with).getDisplayName());
203        } else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
204            final String extraLastState = intent.getStringExtra(EXTRA_LAST_REPORTED_STATE);
205            if (extraLastState != null) {
206                Log.d(Config.LOGTAG, "restored last state from intent extra");
207                RtpEndUserState state = RtpEndUserState.valueOf(extraLastState);
208                updateButtonConfiguration(state);
209                updateStateDisplay(state);
210            }
211            binding.with.setText(account.getRoster().getContact(with).getDisplayName());
212        }
213    }
214
215    private void proposeJingleRtpSession(final Account account, final Jid with) {
216        xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with);
217        //TODO maybe we don’t want to acquire a wake lock just yet and wait for audio manager to discover what speaker we are using
218        putScreenInCallMode();
219    }
220
221    @Override
222    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
223        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
224        if (PermissionUtils.allGranted(grantResults)) {
225            if (requestCode == REQUEST_ACCEPT_CALL) {
226                requireRtpConnection().acceptCall();
227            }
228        } else {
229            @StringRes int res;
230            final String firstDenied = getFirstDenied(grantResults, permissions);
231            if (Manifest.permission.RECORD_AUDIO.equals(firstDenied)) {
232                res = R.string.no_microphone_permission;
233            } else if (Manifest.permission.CAMERA.equals(firstDenied)) {
234                res = R.string.no_camera_permission;
235            } else {
236                throw new IllegalStateException("Invalid permission result request");
237            }
238            Toast.makeText(this, res, Toast.LENGTH_SHORT).show();
239        }
240    }
241
242    @Override
243    public void onStop() {
244        releaseProximityWakeLock();
245        //TODO maybe we want to finish if call had ended
246        super.onStop();
247    }
248
249    @Override
250    public void onBackPressed() {
251        endCall();
252        super.onBackPressed();
253    }
254
255
256    private void initializeActivityWithRunningRtpSession(final Account account, Jid with, String sessionId) {
257        final WeakReference<JingleRtpConnection> reference = xmppConnectionService.getJingleConnectionManager()
258                .findJingleRtpConnection(account, with, sessionId);
259        if (reference == null || reference.get() == null) {
260            finish();
261            return;
262        }
263        this.rtpConnectionReference = reference;
264        final RtpEndUserState currentState = requireRtpConnection().getEndUserState();
265        if (currentState == RtpEndUserState.ENDED) {
266            finish();
267            return;
268        }
269        if (currentState == RtpEndUserState.INCOMING_CALL) {
270            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
271        }
272        if (JingleRtpConnection.STATES_SHOWING_ONGOING_CALL.contains(requireRtpConnection().getState())) {
273            putScreenInCallMode();
274        }
275        binding.with.setText(getWith().getDisplayName());
276        updateStateDisplay(currentState);
277        updateButtonConfiguration(currentState);
278    }
279
280    private void reInitializeActivityWithRunningRapSession(final Account account, Jid with, String sessionId) {
281        runOnUiThread(() -> {
282            initializeActivityWithRunningRtpSession(account, with, sessionId);
283        });
284        final Intent intent = new Intent(Intent.ACTION_VIEW);
285        intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
286        intent.putExtra(EXTRA_WITH, with.toEscapedString());
287        intent.putExtra(EXTRA_SESSION_ID, sessionId);
288        setIntent(intent);
289    }
290
291    private void updateVideoViews() {
292        final Optional<VideoTrack> localVideoTrack = requireRtpConnection().geLocalVideoTrack();
293        if (localVideoTrack.isPresent()) {
294            try {
295                binding.localVideo.init(requireRtpConnection().getEglBaseContext(), null);
296            } catch (IllegalStateException e) {
297                Log.d(Config.LOGTAG,"ignoring already init for now",e);
298            }
299            binding.localVideo.setEnableHardwareScaler(true);
300            binding.localVideo.setMirror(true);
301            localVideoTrack.get().addSink(binding.localVideo);
302        }
303        final Optional<VideoTrack> remoteVideoTrack = requireRtpConnection().getRemoteVideoTrack();
304        if (remoteVideoTrack.isPresent()) {
305            try {
306                binding.remoteVideo.init(requireRtpConnection().getEglBaseContext(), null);
307            } catch (IllegalStateException e) {
308                Log.d(Config.LOGTAG,"ignoring already init for now",e);
309            }
310            binding.remoteVideo.setEnableHardwareScaler(true);
311            remoteVideoTrack.get().addSink(binding.remoteVideo);
312        }
313    }
314
315    private void updateStateDisplay(final RtpEndUserState state) {
316        switch (state) {
317            case INCOMING_CALL:
318                setTitle(R.string.rtp_state_incoming_call);
319                break;
320            case CONNECTING:
321                setTitle(R.string.rtp_state_connecting);
322                break;
323            case CONNECTED:
324                setTitle(R.string.rtp_state_connected);
325                break;
326            case ACCEPTING_CALL:
327                setTitle(R.string.rtp_state_accepting_call);
328                break;
329            case ENDING_CALL:
330                setTitle(R.string.rtp_state_ending_call);
331                break;
332            case FINDING_DEVICE:
333                setTitle(R.string.rtp_state_finding_device);
334                break;
335            case RINGING:
336                setTitle(R.string.rtp_state_ringing);
337                break;
338            case DECLINED_OR_BUSY:
339                setTitle(R.string.rtp_state_declined_or_busy);
340                break;
341            case CONNECTIVITY_ERROR:
342                setTitle(R.string.rtp_state_connectivity_error);
343                break;
344            case APPLICATION_ERROR:
345                setTitle(R.string.rtp_state_application_failure);
346                break;
347            case ENDED:
348                throw new IllegalStateException("Activity should have called finishAndReleaseWakeLock();");
349            default:
350                throw new IllegalStateException(String.format("State %s has not been handled in UI", state));
351        }
352    }
353
354    @SuppressLint("RestrictedApi")
355    private void updateButtonConfiguration(final RtpEndUserState state) {
356        if (state == RtpEndUserState.INCOMING_CALL) {
357            this.binding.rejectCall.setOnClickListener(this::rejectCall);
358            this.binding.rejectCall.setImageResource(R.drawable.ic_call_end_white_48dp);
359            this.binding.rejectCall.setVisibility(View.VISIBLE);
360            this.binding.endCall.setVisibility(View.INVISIBLE);
361            this.binding.acceptCall.setOnClickListener(this::acceptCall);
362            this.binding.acceptCall.setImageResource(R.drawable.ic_call_white_48dp);
363            this.binding.acceptCall.setVisibility(View.VISIBLE);
364        } else if (state == RtpEndUserState.ENDING_CALL) {
365            this.binding.rejectCall.setVisibility(View.INVISIBLE);
366            this.binding.endCall.setVisibility(View.INVISIBLE);
367            this.binding.acceptCall.setVisibility(View.INVISIBLE);
368        } else if (state == RtpEndUserState.DECLINED_OR_BUSY) {
369            this.binding.rejectCall.setVisibility(View.INVISIBLE);
370            this.binding.endCall.setOnClickListener(this::exit);
371            this.binding.endCall.setImageResource(R.drawable.ic_clear_white_48dp);
372            this.binding.endCall.setVisibility(View.VISIBLE);
373            this.binding.acceptCall.setVisibility(View.INVISIBLE);
374        } else if (state == RtpEndUserState.CONNECTIVITY_ERROR || state == RtpEndUserState.APPLICATION_ERROR) {
375            this.binding.rejectCall.setOnClickListener(this::exit);
376            this.binding.rejectCall.setImageResource(R.drawable.ic_clear_white_48dp);
377            this.binding.rejectCall.setVisibility(View.VISIBLE);
378            this.binding.endCall.setVisibility(View.INVISIBLE);
379            this.binding.acceptCall.setOnClickListener(this::retry);
380            this.binding.acceptCall.setImageResource(R.drawable.ic_replay_white_48dp);
381            this.binding.acceptCall.setVisibility(View.VISIBLE);
382        } else {
383            this.binding.rejectCall.setVisibility(View.INVISIBLE);
384            this.binding.endCall.setOnClickListener(this::endCall);
385            this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
386            this.binding.endCall.setVisibility(View.VISIBLE);
387            this.binding.acceptCall.setVisibility(View.INVISIBLE);
388        }
389        updateInCallButtonConfiguration(state);
390    }
391
392    private void updateInCallButtonConfiguration() {
393        updateInCallButtonConfiguration(requireRtpConnection().getEndUserState());
394    }
395
396    @SuppressLint("RestrictedApi")
397    private void updateInCallButtonConfiguration(final RtpEndUserState state) {
398        if (state == RtpEndUserState.CONNECTED) {
399            final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager();
400            updateInCallButtonConfiguration(
401                    audioManager.getSelectedAudioDevice(),
402                    audioManager.getAudioDevices().size(),
403                    requireRtpConnection().isMicrophoneEnabled()
404            );
405        } else {
406            this.binding.inCallActionLeft.setVisibility(View.GONE);
407            this.binding.inCallActionRight.setVisibility(View.GONE);
408        }
409    }
410
411    @SuppressLint("RestrictedApi")
412    private void updateInCallButtonConfiguration(final AppRTCAudioManager.AudioDevice selectedAudioDevice, final int numberOfChoices, final boolean microphoneEnabled) {
413        switch (selectedAudioDevice) {
414            case EARPIECE:
415                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_volume_off_black_24dp);
416                if (numberOfChoices >= 2) {
417                    this.binding.inCallActionLeft.setOnClickListener(this::switchToSpeaker);
418                } else {
419                    this.binding.inCallActionLeft.setOnClickListener(null);
420                    this.binding.inCallActionLeft.setClickable(false);
421                }
422                break;
423            case WIRED_HEADSET:
424                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_headset_black_24dp);
425                this.binding.inCallActionLeft.setOnClickListener(null);
426                this.binding.inCallActionLeft.setClickable(false);
427                break;
428            case SPEAKER_PHONE:
429                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_volume_up_black_24dp);
430                if (numberOfChoices >= 2) {
431                    this.binding.inCallActionLeft.setOnClickListener(this::switchToEarpiece);
432                } else {
433                    this.binding.inCallActionLeft.setOnClickListener(null);
434                    this.binding.inCallActionLeft.setClickable(false);
435                }
436                break;
437            case BLUETOOTH:
438                this.binding.inCallActionLeft.setImageResource(R.drawable.ic_bluetooth_audio_black_24dp);
439                this.binding.inCallActionLeft.setOnClickListener(null);
440                this.binding.inCallActionLeft.setClickable(false);
441                break;
442        }
443        this.binding.inCallActionLeft.setVisibility(View.VISIBLE);
444        if (microphoneEnabled) {
445            this.binding.inCallActionRight.setImageResource(R.drawable.ic_mic_black_24dp);
446            this.binding.inCallActionRight.setOnClickListener(this::disableMicrophone);
447        } else {
448            this.binding.inCallActionRight.setImageResource(R.drawable.ic_mic_off_black_24dp);
449            this.binding.inCallActionRight.setOnClickListener(this::enableMicrophone);
450        }
451        this.binding.inCallActionRight.setVisibility(View.VISIBLE);
452    }
453
454    private void disableMicrophone(View view) {
455        JingleRtpConnection rtpConnection = requireRtpConnection();
456        rtpConnection.setMicrophoneEnabled(false);
457        updateInCallButtonConfiguration();
458    }
459
460    private void enableMicrophone(View view) {
461        JingleRtpConnection rtpConnection = requireRtpConnection();
462        rtpConnection.setMicrophoneEnabled(true);
463        updateInCallButtonConfiguration();
464    }
465
466    private void switchToEarpiece(View view) {
467        requireRtpConnection().getAudioManager().setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.EARPIECE);
468        acquireProximityWakeLock();
469    }
470
471    private void switchToSpeaker(View view) {
472        requireRtpConnection().getAudioManager().setDefaultAudioDevice(AppRTCAudioManager.AudioDevice.SPEAKER_PHONE);
473        releaseProximityWakeLock();
474    }
475
476    private void retry(View view) {
477        Log.d(Config.LOGTAG, "attempting retry");
478        final Intent intent = getIntent();
479        final Account account = extractAccount(intent);
480        final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
481        this.rtpConnectionReference = null;
482        proposeJingleRtpSession(account, with);
483    }
484
485    private void exit(View view) {
486        finish();
487    }
488
489    private Contact getWith() {
490        final AbstractJingleConnection.Id id = requireRtpConnection().getId();
491        final Account account = id.account;
492        return account.getRoster().getContact(id.with);
493    }
494
495    private JingleRtpConnection requireRtpConnection() {
496        final JingleRtpConnection connection = this.rtpConnectionReference != null ? this.rtpConnectionReference.get() : null;
497        if (connection == null) {
498            throw new IllegalStateException("No RTP connection found");
499        }
500        return connection;
501    }
502
503    @Override
504    public void onJingleRtpConnectionUpdate(Account account, Jid with, final String sessionId, RtpEndUserState state) {
505        if (Arrays.asList(RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.DECLINED_OR_BUSY).contains(state)) {
506            releaseProximityWakeLock();
507        }
508        Log.d(Config.LOGTAG, "onJingleRtpConnectionUpdate(" + state + ")");
509        if (with.isBareJid()) {
510            updateRtpSessionProposalState(account, with, state);
511            return;
512        }
513        if (this.rtpConnectionReference == null) {
514            //this happens when going from proposed session to actual session
515            reInitializeActivityWithRunningRapSession(account, with, sessionId);
516            return;
517        }
518        final AbstractJingleConnection.Id id = requireRtpConnection().getId();
519        if (account == id.account && id.with.equals(with) && id.sessionId.equals(sessionId)) {
520            if (state == RtpEndUserState.ENDED) {
521                finish();
522                return;
523            } else if (asList(RtpEndUserState.APPLICATION_ERROR, RtpEndUserState.DECLINED_OR_BUSY, RtpEndUserState.CONNECTIVITY_ERROR).contains(state)) {
524                resetIntent(account, with, state);
525            }
526            runOnUiThread(() -> {
527                updateStateDisplay(state);
528                updateButtonConfiguration(state);
529                updateVideoViews();
530            });
531        } else {
532            Log.d(Config.LOGTAG, "received update for other rtp session");
533            //TODO if we only ever have one; we might just switch over? Maybe!
534        }
535    }
536
537    @Override
538    public void onAudioDeviceChanged(AppRTCAudioManager.AudioDevice selectedAudioDevice, Set<AppRTCAudioManager.AudioDevice> availableAudioDevices) {
539        Log.d(Config.LOGTAG, "onAudioDeviceChanged in activity: selected:" + selectedAudioDevice + ", available:" + availableAudioDevices);
540        try {
541            if (requireRtpConnection().getEndUserState() == RtpEndUserState.CONNECTED) {
542                final AppRTCAudioManager audioManager = requireRtpConnection().getAudioManager();
543                updateInCallButtonConfiguration(
544                        audioManager.getSelectedAudioDevice(),
545                        audioManager.getAudioDevices().size(),
546                        requireRtpConnection().isMicrophoneEnabled()
547                );
548            }
549            putProximityWakeLockInProperState();
550        } catch (IllegalStateException e) {
551            Log.d(Config.LOGTAG, "RTP connection was not available when audio device changed");
552        }
553    }
554
555    private void updateRtpSessionProposalState(final Account account, final Jid with, final RtpEndUserState state) {
556        final Intent currentIntent = getIntent();
557        final String withExtra = currentIntent == null ? null : currentIntent.getStringExtra(EXTRA_WITH);
558        if (withExtra == null) {
559            return;
560        }
561        if (Jid.ofEscaped(withExtra).asBareJid().equals(with)) {
562            runOnUiThread(() -> {
563                updateStateDisplay(state);
564                updateButtonConfiguration(state);
565            });
566            resetIntent(account, with, state);
567        }
568    }
569
570    private void resetIntent(final Bundle extras) {
571        final Intent intent = new Intent(Intent.ACTION_VIEW);
572        intent.putExtras(extras);
573        setIntent(intent);
574    }
575
576    private void resetIntent(final Account account, Jid with, final RtpEndUserState state) {
577        final Intent intent = new Intent(Intent.ACTION_VIEW);
578        intent.putExtra(EXTRA_WITH, with.asBareJid().toEscapedString());
579        intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
580        intent.putExtra(EXTRA_LAST_REPORTED_STATE, state.toString());
581        setIntent(intent);
582    }
583}