From 365f1dbbe6dc609bf8dbdd2c82538327bb37c8bc Mon Sep 17 00:00:00 2001 From: adbenitez Date: Fri, 20 Jun 2025 18:56:45 +0200 Subject: [PATCH] basic call --- jni/deltachat-core-rust | 2 +- src/main/assets/call.html | 72 ++++++++++++++++++ .../securesms/ConversationListFragment.java | 5 ++ .../videochat/VideochatActivity.java | 75 +++++++++++++++---- .../securesms/videochat/VideochatUtil.java | 16 ++-- 5 files changed, 148 insertions(+), 22 deletions(-) create mode 100644 src/main/assets/call.html diff --git a/jni/deltachat-core-rust b/jni/deltachat-core-rust index 47b9bfc8b..c1e2f0bb1 160000 --- a/jni/deltachat-core-rust +++ b/jni/deltachat-core-rust @@ -1 +1 @@ -Subproject commit 47b9bfc8bf807ad099d2211a59d6ba80290b0c95 +Subproject commit c1e2f0bb18bfadaaf0d78848b0e990ad3b1538c7 diff --git a/src/main/assets/call.html b/src/main/assets/call.html new file mode 100644 index 000000000..15da98d8c --- /dev/null +++ b/src/main/assets/call.html @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + +
+ + diff --git a/src/main/java/org/thoughtcrime/securesms/ConversationListFragment.java b/src/main/java/org/thoughtcrime/securesms/ConversationListFragment.java index ea928ec74..af81a13b6 100644 --- a/src/main/java/org/thoughtcrime/securesms/ConversationListFragment.java +++ b/src/main/java/org/thoughtcrime/securesms/ConversationListFragment.java @@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.RelayUtil; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.videochat.VideochatUtil; import java.util.Timer; import java.util.TimerTask; @@ -81,6 +82,7 @@ public class ConversationListFragment extends BaseConversationListFragment eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_MSG, this); eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_MSGS_NOTICED, this); eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_CHAT_DELETED, this); + eventCenter.addMultiAccountObserver(DcContext.DC_EVENT_INCOMING_CALL, this); eventCenter.addObserver(DcContext.DC_EVENT_CHAT_MODIFIED, this); eventCenter.addObserver(DcContext.DC_EVENT_CONTACTS_CHANGED, this); eventCenter.addObserver(DcContext.DC_EVENT_MSGS_CHANGED, this); @@ -343,6 +345,9 @@ public class ConversationListFragment extends BaseConversationListFragment ((ConversationListActivity) activity).refreshAvatar(); } + } else if (event.getId() == DcContext.DC_EVENT_INCOMING_CALL) { + // TODO: show notification + VideochatUtil.joinCall(getActivity(), event.getData1Int(), event.getData2Str()); } else { loadChatlistAsync(); } diff --git a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java index 5997e4cd0..7833b63d4 100644 --- a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java +++ b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatActivity.java @@ -1,57 +1,71 @@ package org.thoughtcrime.securesms.videochat; +import android.annotation.SuppressLint; import android.os.Bundle; import android.view.Menu; +import android.webkit.JavascriptInterface; import android.webkit.PermissionRequest; import android.webkit.WebChromeClient; import android.webkit.WebSettings; +import androidx.annotation.NonNull; + import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcEvent; import org.thoughtcrime.securesms.WebViewActivity; +import org.thoughtcrime.securesms.connect.DcEventCenter; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.Util; -public class VideochatActivity extends WebViewActivity { - private static final String TAG = VideochatActivity.class.getSimpleName(); +import java.util.Objects; + +public class VideochatActivity extends WebViewActivity implements DcEventCenter.DcEventDelegate { public static final String EXTRA_CHAT_ID = "chat_id"; + public static final String EXTRA_CALL_ID = "call_id"; public static final String EXTRA_HASH = "hash"; private DcContext dcContext; - private String url = "file:///android_asset/call.html"; + private int chatId; + private int callId; + @SuppressLint("SetJavaScriptEnabled") @Override protected void onCreate(Bundle state, boolean ready) { super.onCreate(state, ready); this.dcContext = DcHelper.getContext(getApplicationContext()); - Bundle b = getIntent().getExtras(); - String hash = b.getString(EXTRA_HASH, ""); - int chatId = b.getInt(EXTRA_CHAT_ID, 0); + Bundle bundle = getIntent().getExtras(); + assert bundle != null; + String hash = bundle.getString(EXTRA_HASH, ""); + chatId = bundle.getInt(EXTRA_CHAT_ID, 0); + callId = bundle.getInt(EXTRA_CALL_ID, 0); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setMediaPlaybackRequiresUserGesture(false); + webView.addJavascriptInterface(new InternalJSApi(), "calls"); webView.setWebChromeClient(new WebChromeClient() { @Override public void onPermissionRequest(PermissionRequest request) { - Util.runOnMain(() -> { - request.grant(request.getResources()); - }); + Util.runOnMain(() -> request.grant(request.getResources())); } }); + DcEventCenter eventCenter = DcHelper.getEventCenter(getApplicationContext()); + eventCenter.addObserver(DcContext.DC_EVENT_OUTGOING_CALL_ACCEPTED, this); + eventCenter.addObserver(DcContext.DC_EVENT_CALL_ENDED, this); + Util.runOnAnyBackgroundThread(() -> { final DcChat chat = dcContext.getChat(chatId); - Util.runOnMain(() -> { - getSupportActionBar().setTitle(chat.getName()); - }); + Util.runOnMain(() -> Objects.requireNonNull(getSupportActionBar()).setTitle(chat.getName())); }); - webView.loadUrl(url+hash); + String url = "file:///android_asset/call.html"; + webView.loadUrl(url + hash); } @Override @@ -65,4 +79,39 @@ public class VideochatActivity extends WebViewActivity { finish(); return true; } + + @Override + public void handleEvent(@NonNull DcEvent event) { + switch (event.getId()) { + case DcContext.DC_EVENT_OUTGOING_CALL_ACCEPTED: + if (event.getData1Int() == callId) { + String hash = "#answer=" + event.getData2Str(); + webView.evaluateJavascript("window.location.hash = `"+hash+"`", null); + } + break; + case DcContext.DC_EVENT_CALL_ENDED: + if (event.getData1Int() == callId) { + finish(); + } + break; + } + } + + + class InternalJSApi { + @JavascriptInterface + public void startCall(String payload) { + callId = dcContext.placeOutgoingCall(chatId, payload); + } + + @JavascriptInterface + public void acceptCall(String payload) { + dcContext.acceptIncomingCall(callId, payload); + } + + @JavascriptInterface + public void endCall() { + dcContext.endCall(callId); + } + } } diff --git a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java index 716faf0c4..00778f577 100644 --- a/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java +++ b/src/main/java/org/thoughtcrime/securesms/videochat/VideochatUtil.java @@ -15,10 +15,6 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.permissions.Permissions; import org.thoughtcrime.securesms.util.IntentUtils; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - public class VideochatUtil { public static void startMeeting(Activity activity, int chatId) { @@ -53,16 +49,19 @@ public class VideochatUtil { .setTitle(activity.getString(R.string.videochat_invite_user_to_videochat, dcChat.getName())) .setNegativeButton(R.string.cancel, null) .setPositiveButton(R.string.ok, (dialog, which) -> { - joinCall(activity, chatId, "#call"); + openCall(activity, chatId, 0, "#call"); }) .show(); } - public static void joinCall(Activity activity, int chatId) { - joinCall(activity, chatId, ""); + public static void joinCall(Activity activity, int callId, String payload) { + DcContext dcContext = DcHelper.getContext(activity); + DcMsg dcMsg = dcContext.getMsg(callId); + String hash = "#offer=" + payload; + openCall(activity, dcMsg.getChatId(), callId, hash); } - private static void joinCall(Activity activity, int chatId, String hash) { + private static void openCall(Activity activity, int chatId, int callId, String hash) { Permissions.with(activity) .request(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO) .ifNecessary() @@ -71,6 +70,7 @@ public class VideochatUtil { Intent intent = new Intent(activity, VideochatActivity.class); intent.setAction(Intent.ACTION_VIEW); intent.putExtra(VideochatActivity.EXTRA_CHAT_ID, chatId); + intent.putExtra(VideochatActivity.EXTRA_CALL_ID, callId); intent.putExtra(VideochatActivity.EXTRA_HASH, hash); activity.startActivity(intent); })