RtpSessionActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.content.Intent;
  4import android.databinding.DataBindingUtil;
  5import android.os.Bundle;
  6import android.util.Log;
  7import android.view.View;
  8import android.view.WindowManager;
  9
 10import java.lang.ref.WeakReference;
 11
 12import eu.siacs.conversations.Config;
 13import eu.siacs.conversations.R;
 14import eu.siacs.conversations.databinding.ActivityRtpSessionBinding;
 15import eu.siacs.conversations.entities.Account;
 16import eu.siacs.conversations.entities.Contact;
 17import eu.siacs.conversations.services.XmppConnectionService;
 18import eu.siacs.conversations.xmpp.jingle.AbstractJingleConnection;
 19import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection;
 20import eu.siacs.conversations.xmpp.jingle.RtpEndUserState;
 21import rocks.xmpp.addr.Jid;
 22
 23import static java.util.Arrays.asList;
 24
 25//TODO if last state was BUSY (or RETRY); we want to reset action to view or something so we don’t automatically call again on recreate
 26
 27public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate {
 28
 29    public static final String EXTRA_WITH = "with";
 30    public static final String EXTRA_SESSION_ID = "session_id";
 31
 32    public static final String ACTION_ACCEPT_CALL = "action_accept_call";
 33    public static final String ACTION_MAKE_VOICE_CALL = "action_make_voice_call";
 34    public static final String ACTION_MAKE_VIDEO_CALL = "action_make_video_call";
 35
 36    private WeakReference<JingleRtpConnection> rtpConnectionReference;
 37
 38    private ActivityRtpSessionBinding binding;
 39
 40    @Override
 41    public void onCreate(Bundle savedInstanceState) {
 42        super.onCreate(savedInstanceState);
 43        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
 44                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
 45                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
 46                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
 47        ;
 48        Log.d(Config.LOGTAG, "RtpSessionActivity.onCreate()");
 49        this.binding = DataBindingUtil.setContentView(this, R.layout.activity_rtp_session);
 50        this.binding.rejectCall.setOnClickListener(this::rejectCall);
 51        this.binding.endCall.setOnClickListener(this::endCall);
 52        this.binding.acceptCall.setOnClickListener(this::acceptCall);
 53    }
 54
 55    @Override
 56    public void onStart() {
 57        super.onStart();
 58        Log.d(Config.LOGTAG, "RtpSessionActivity.onStart()");
 59    }
 60
 61    private void endCall(View view) {
 62        if (this.rtpConnectionReference == null) {
 63            final Intent intent = getIntent();
 64            final Account account = extractAccount(intent);
 65            final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
 66            xmppConnectionService.getJingleConnectionManager().retractSessionProposal(account, with.asBareJid());
 67            finish();
 68        } else {
 69            requireRtpConnection().endCall();
 70        }
 71    }
 72
 73    private void rejectCall(View view) {
 74        requireRtpConnection().rejectCall();
 75        finish();
 76    }
 77
 78    private void acceptCall(View view) {
 79        requireRtpConnection().acceptCall();
 80    }
 81
 82    @Override
 83    protected void refreshUiReal() {
 84
 85    }
 86
 87    @Override
 88    public void onNewIntent(final Intent intent) {
 89        super.onNewIntent(intent);
 90        if (ACTION_ACCEPT_CALL.equals(intent.getAction())) {
 91            Log.d(Config.LOGTAG, "accepting through onNewIntent()");
 92            requireRtpConnection().acceptCall();
 93        }
 94    }
 95
 96    @Override
 97    void onBackendConnected() {
 98        final Intent intent = getIntent();
 99        final Account account = extractAccount(intent);
100        final Jid with = Jid.of(intent.getStringExtra(EXTRA_WITH));
101        final String sessionId = intent.getStringExtra(EXTRA_SESSION_ID);
102        if (sessionId != null) {
103            initializeActivityWithRunningRapSession(account, with, sessionId);
104            if (ACTION_ACCEPT_CALL.equals(intent.getAction())) {
105                Log.d(Config.LOGTAG, "intent action was accept");
106                requireRtpConnection().acceptCall();
107            }
108        } else if (asList(ACTION_MAKE_VIDEO_CALL, ACTION_MAKE_VOICE_CALL).contains(intent.getAction())) {
109            xmppConnectionService.getJingleConnectionManager().proposeJingleRtpSession(account, with);
110            binding.with.setText(account.getRoster().getContact(with).getDisplayName());
111        }
112    }
113
114
115    private void initializeActivityWithRunningRapSession(final Account account, Jid with, String sessionId) {
116        final WeakReference<JingleRtpConnection> reference = xmppConnectionService.getJingleConnectionManager()
117                .findJingleRtpConnection(account, with, sessionId);
118        if (reference == null || reference.get() == null) {
119            finish();
120            return;
121        }
122        this.rtpConnectionReference = reference;
123        final RtpEndUserState currentState = requireRtpConnection().getEndUserState();
124        if (currentState == RtpEndUserState.ENDED) {
125            finish();
126            return;
127        }
128        binding.with.setText(getWith().getDisplayName());
129        updateStateDisplay(currentState);
130        updateButtonConfiguration(currentState);
131    }
132
133    private void reInitializeActivityWithRunningRapSession(final Account account, Jid with, String sessionId) {
134        runOnUiThread(() -> {
135            initializeActivityWithRunningRapSession(account, with, sessionId);
136        });
137        final Intent intent = new Intent(Intent.ACTION_VIEW);
138        intent.putExtra(EXTRA_ACCOUNT, account.getJid().toEscapedString());
139        intent.putExtra(EXTRA_WITH, with.toEscapedString());
140        intent.putExtra(EXTRA_SESSION_ID, sessionId);
141        setIntent(intent);
142    }
143
144    private void updateStateDisplay(final RtpEndUserState state) {
145        switch (state) {
146            case INCOMING_CALL:
147                binding.status.setText(R.string.rtp_state_incoming_call);
148                break;
149            case CONNECTING:
150                binding.status.setText(R.string.rtp_state_connecting);
151                break;
152            case CONNECTED:
153                binding.status.setText(R.string.rtp_state_connected);
154                break;
155            case ACCEPTING_CALL:
156                binding.status.setText(R.string.rtp_state_accepting_call);
157                break;
158            case ENDING_CALL:
159                binding.status.setText(R.string.rtp_state_ending_call);
160                break;
161            case FINDING_DEVICE:
162                binding.status.setText(R.string.rtp_state_finding_device);
163                break;
164            case RINGING:
165                binding.status.setText(R.string.rtp_state_ringing);
166                break;
167            case DECLINED_OR_BUSY:
168                binding.status.setText(R.string.rtp_state_declined_or_busy);
169                break;
170        }
171    }
172
173    private void updateButtonConfiguration(final RtpEndUserState state) {
174        if (state == RtpEndUserState.INCOMING_CALL) {
175            this.binding.rejectCall.show();
176            this.binding.endCall.hide();
177            this.binding.acceptCall.show();
178        } else if (state == RtpEndUserState.ENDING_CALL) {
179            this.binding.rejectCall.hide();
180            this.binding.endCall.hide();
181            this.binding.acceptCall.hide();
182        } else if (state == RtpEndUserState.DECLINED_OR_BUSY) {
183            this.binding.rejectCall.hide();
184            this.binding.endCall.setImageResource(R.drawable.ic_clear_white_48dp);
185            this.binding.endCall.show();
186            this.binding.endCall.setOnClickListener(this::exit);
187            this.binding.acceptCall.hide();
188        } else {
189            this.binding.rejectCall.hide();
190            this.binding.endCall.setImageResource(R.drawable.ic_call_end_white_48dp);
191            this.binding.endCall.show();
192            this.binding.endCall.setOnClickListener(this::endCall);
193            this.binding.acceptCall.hide();
194        }
195    }
196
197    private void exit(View view) {
198        finish();
199    }
200
201    private Contact getWith() {
202        final AbstractJingleConnection.Id id = requireRtpConnection().getId();
203        final Account account = id.account;
204        return account.getRoster().getContact(id.with);
205    }
206
207    private JingleRtpConnection requireRtpConnection() {
208        final JingleRtpConnection connection = this.rtpConnectionReference != null ? this.rtpConnectionReference.get() : null;
209        if (connection == null) {
210            throw new IllegalStateException("No RTP connection found");
211        }
212        return connection;
213    }
214
215    @Override
216    public void onJingleRtpConnectionUpdate(Account account, Jid with, final String sessionId, RtpEndUserState state) {
217        Log.d(Config.LOGTAG, "onJingleRtpConnectionUpdate(" + state + ")");
218        if (with.isBareJid()) {
219            updateRtpSessionProposalState(with, state);
220            return;
221        }
222        if (this.rtpConnectionReference == null) {
223            //this happens when going from proposed session to actual session
224            reInitializeActivityWithRunningRapSession(account, with, sessionId);
225            return;
226        }
227        final AbstractJingleConnection.Id id = requireRtpConnection().getId();
228        if (account == id.account && id.with.equals(with) && id.sessionId.equals(sessionId)) {
229            if (state == RtpEndUserState.ENDED) {
230                finish();
231                return;
232            }
233            runOnUiThread(() -> {
234                updateStateDisplay(state);
235                updateButtonConfiguration(state);
236            });
237        } else {
238            Log.d(Config.LOGTAG, "received update for other rtp session");
239        }
240    }
241
242    private void updateRtpSessionProposalState(Jid with, RtpEndUserState state) {
243        final Intent intent = getIntent();
244        final String intentExtraWith = intent == null ? null : intent.getStringExtra(EXTRA_WITH);
245        if (intentExtraWith == null) {
246            return;
247        }
248        if (Jid.ofEscaped(intentExtraWith).asBareJid().equals(with)) {
249            runOnUiThread(() -> {
250                updateStateDisplay(state);
251                updateButtonConfiguration(state);
252            });
253        }
254    }
255}