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