From 6132024c169e2ffdc4d8ccbd7e174791b6d28e5b Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 27 Oct 2021 13:58:04 -0500 Subject: [PATCH 1/4] Revert "Intercept DIAL and CALL to tel: and rewrite to cheogram" This reverts commit 227dd8d2bcbb86599b22483bc56972aab66d7890. --- src/main/AndroidManifest.xml | 8 -------- .../eu/siacs/conversations/ui/UriHandlerActivity.java | 2 -- src/main/java/eu/siacs/conversations/utils/XmppUri.java | 2 -- 3 files changed, 12 deletions(-) diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 07923d9597ff9b169233f510042ede55abddd5ce..ff41c07c2049b0efaf9ce05d13dcc7e274c1c5db 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -143,14 +143,6 @@ - - - - - - - - diff --git a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java index a3f062814ba47e26580a3d1dd0cee4bc62f56c58..5583fb5fbe1c304b25ea9957d70bd8f679af56a1 100644 --- a/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/UriHandlerActivity.java @@ -260,8 +260,6 @@ public class UriHandlerActivity extends AppCompatActivity { break; case Intent.ACTION_VIEW: case Intent.ACTION_SENDTO: - case Intent.ACTION_DIAL: - case Intent.ACTION_CALL: if (handleUri(data.getData())) { finish(); } diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index 59f8cb822448297641d99443349fcf6d682693f3..6c3075be9b7ec1194d979d961c6bc3096aae76cf 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -179,8 +179,6 @@ public class XmppUri { } catch (final UnsupportedEncodingException ignored) { jid = null; } - } else if ("tel".equalsIgnoreCase(scheme)) { - jid = uri.getSchemeSpecificPart().replaceAll("[^\\d\\+]+", "") + "@cheogram.com"; } else { jid = null; } From 7296a11945c14843cd797601ab743451c240e61b Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 27 Oct 2021 14:57:36 -0500 Subject: [PATCH 2/4] First version of dialer integration When a contact comes online, we check if it is a gateway/pstn. If so, we register a new PhoneAccount with the OS for the account+gateway pair. When the roster is being saved after any change, we check for any items that have been removed and remove any associated PhoneAccount registration. To activate a PhoneAccount, a user navigates to Phone App > Settings > Calls > Calling Accounts. When a call is placed from the Phone app using one of our PhoneAccount, the ConnectionService is called by the OS. Its job is to place the call and keep the OS calling UI up to date via a returned Connection subclass. Calling in Conversations is currently rather tied to the UI, so rather than seperate it out for this prototype, I launch the Intent to bring up the UI for the desired call. This should do jabber:iq:gateway on the gateway and possibly other fallbacks, but for this prototype it just strips any non-digit and prepend +1 if not present, appending @gateway.tld for the associated gateway. We don't actually tell the OS UI when the call is active, because if we do it steals focus and puts the whole system in "in a call" mode, which causes Conversations to deactivate its UI. This is something to explore more if we want to use the OS in-call UI completely. We also haven't wired up the OS UI for DTMF since it never shows if the call is never active. We *do* tell the OS UI when the call is over, so it can clean up and close the other window. This means that after you hang up in Conversations, you are taken back to the OS UI showing "call ended" for a few moments. It also means that if an outgoing call fails you will see the OS UI for a few moments before being returned to Conversations to see the normal call failure screen. This is perhaps the biggest wart of the current prototype. As an alternative, we could just pretend the call immediately failed and have the OS UI close itself before the Conversations UI ever comes up. This basically causes a indeterminately-long "flash" of the OS UI, possibly long enough to see it say "call ended" before we get the Conversations UI which then works after that. I thought that was more confusing that what I'm doing now, but maybe others disagree. Finally, outbound calls placed from the Phone app do show in the Phone app call log. Other calls started from Conversations or inbound calls could show there with a full integration, but that's not part of this work. --- src/cheogram/AndroidManifest.xml | 11 ++ .../cheogram/android/ConnectionService.java | 114 ++++++++++++++++++ .../siacs/conversations/entities/Contact.java | 37 ++++++ .../conversations/entities/Presences.java | 15 +++ .../services/XmppConnectionService.java | 14 +++ .../conversations/ui/RtpSessionActivity.java | 37 ++++++ 6 files changed, 228 insertions(+) create mode 100644 src/cheogram/java/com/cheogram/android/ConnectionService.java diff --git a/src/cheogram/AndroidManifest.xml b/src/cheogram/AndroidManifest.xml index 62396bed1af27fcdcac16db152115fbd362223ec..956e892fe1b1768858702f10c6c8aac4617bc18d 100644 --- a/src/cheogram/AndroidManifest.xml +++ b/src/cheogram/AndroidManifest.xml @@ -3,7 +3,18 @@ xmlns:tools="http://schemas.android.com/tools" package="eu.siacs.conversations"> + + + + + + + + + clazz) { if (clazz == JabberIdContact.class) { return Options.SYNCED_VIA_ADDRESSBOOK; diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java index 04d378cc2602e9fd47b1da60d9a9fdf3433114c6..d0a25e884d52d0f3274bbceb0c961b99c1ccd5de 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presences.java +++ b/src/main/java/eu/siacs/conversations/entities/Presences.java @@ -149,6 +149,21 @@ public class Presences { return false; } + public boolean anyIdentity(final String category, final String type) { + synchronized (this.presences) { + if (this.presences.size() == 0) { + return true; + } + for (Presence presence : this.presences.values()) { + ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult(); + if (disco != null && disco.hasIdentity(category, type)) { + return true; + } + } + } + return false; + } + public Pair, Map> toTypeAndNameMap() { Map typeMap = new HashMap<>(); Map nameMap = new HashMap<>(); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 42b699e46e806cf95b0048f0fd320930a94cb967..9c533e4905df42f2e96fa22295657518410556b2 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -233,6 +233,11 @@ public class XmppConnectionService extends Service { } } } + + if (contact.getPresences().size() > 0 && + contact.getPresences().anyIdentity("gateway", "pstn")) { + contact.registerAsPhoneAccount(this); + } }; private final PresenceGenerator mPresenceGenerator = new PresenceGenerator(this); private List accounts; @@ -1968,6 +1973,7 @@ public class XmppConnectionService extends Service { public void syncRoster(final Account account) { + unregisterPhoneAccounts(account); mRosterSyncTaskManager.execute(account, () -> databaseBackend.writeRoster(account.getRoster())); } @@ -3449,6 +3455,14 @@ public class XmppConnectionService extends Service { } } + protected void unregisterPhoneAccounts(final Account account) { + for (final Contact contact : account.getRoster().getContacts()) { + if (!contact.showInRoster()) { + contact.unregisterAsPhoneAccount(this); + } + } + } + public void createContact(final Contact contact, final boolean autoGrant) { createContact(contact, autoGrant, null); } diff --git a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java index 8a2b87b47ed5d2499521b6fa367cca69d960a6f9..7a94829c3ac34da311c64f4cb24f7e3916fcd309 100644 --- a/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/RtpSessionActivity.java @@ -71,12 +71,18 @@ import eu.siacs.conversations.xmpp.jingle.JingleRtpConnection; import eu.siacs.conversations.xmpp.jingle.Media; import eu.siacs.conversations.xmpp.jingle.RtpEndUserState; +import com.cheogram.android.ConnectionService.ConnectionBinder; + +import static eu.siacs.conversations.utils.PermissionUtils.getFirstDenied; +import static java.util.Arrays.asList; + public class RtpSessionActivity extends XmppActivity implements XmppConnectionService.OnJingleRtpConnectionUpdate, eu.siacs.conversations.ui.widget.SurfaceViewRenderer.OnAspectRatioChanged { public static final String EXTRA_WITH = "with"; public static final String EXTRA_SESSION_ID = "session_id"; public static final String EXTRA_LAST_REPORTED_STATE = "last_reported_state"; public static final String EXTRA_LAST_ACTION = "last_action"; + public static final String EXTRA_CONNECTION_BINDER = "connection_binder"; public static final String ACTION_ACCEPT_CALL = "action_accept_call"; public static final String ACTION_MAKE_VOICE_CALL = "action_make_voice_call"; public static final String ACTION_MAKE_VIDEO_CALL = "action_make_video_call"; @@ -142,6 +148,8 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe } } + protected android.os.IBinder connectionBinder = null; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -160,6 +168,8 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe boolean dialpadVisible = savedInstanceState.getBoolean("dialpad_visible"); binding.dialpad.setVisibility(dialpadVisible ? View.VISIBLE : View.GONE); } + + this.connectionBinder = getIntent().getExtras().getBinder(EXTRA_CONNECTION_BINDER); } @Override @@ -262,6 +272,29 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe } else { requireRtpConnection().endCall(); } + disconnectConnectionBinder(); + } + + private void disconnectConnectionBinder() { + if (connectionBinder != null) { + android.os.Parcel args = android.os.Parcel.obtain(); + try { + connectionBinder.transact(ConnectionBinder.TRANSACT_DISCONNECT, args, null, 0); + } catch (android.os.RemoteException e) {} + args.recycle(); + } + } + + private void activateConnectionBinder() { + // If we do this, the other UI takes over and kills our call + // So we can't activate that UI unless we are going to use it. + /*if (connectionBinder != null) { + android.os.Parcel args = android.os.Parcel.obtain(); + try { + connectionBinder.transact(ConnectionBinder.TRANSACT_ACTIVE, args, null, 0); + } catch (android.os.RemoteException e) {} + args.recycle(); + }*/ } private void retractSessionProposal() { @@ -1153,10 +1186,14 @@ public class RtpSessionActivity extends XmppActivity implements XmppConnectionSe @Override public void onJingleRtpConnectionUpdate(Account account, Jid with, final String sessionId, RtpEndUserState state) { Log.d(Config.LOGTAG, "onJingleRtpConnectionUpdate(" + state + ")"); + if (state == RtpEndUserState.CONNECTED) { + activateConnectionBinder(); + } if (END_CARD.contains(state)) { Log.d(Config.LOGTAG, "end card reached"); releaseProximityWakeLock(); runOnUiThread(() -> getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); + disconnectConnectionBinder(); } if (with.isBareJid()) { updateRtpSessionProposalState(account, with, state); From 2924ec071f62fc3446abd428a1c40fdb9d355dd5 Mon Sep 17 00:00:00 2001 From: root21 Date: Fri, 12 Nov 2021 20:25:51 -0600 Subject: [PATCH 3/4] Small fix to address cheogram adding "+1" when making calls from the default dialer. Now only adds "+1" or "+" when necessary. --- src/cheogram/java/com/cheogram/android/ConnectionService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cheogram/java/com/cheogram/android/ConnectionService.java b/src/cheogram/java/com/cheogram/android/ConnectionService.java index ddeb53465e3a686c0683d3b36def5a045473accb..c5e304ec78030aeebe70f1fa553a5a7e3708c92a 100644 --- a/src/cheogram/java/com/cheogram/android/ConnectionService.java +++ b/src/cheogram/java/com/cheogram/android/ConnectionService.java @@ -37,7 +37,9 @@ public class ConnectionService extends android.telecom.ConnectionService { // TODO: jabber:iq:gateway String tel = request.getAddress().getSchemeSpecificPart(). replaceAll("[^\\+0-9]", ""); - if (!tel.startsWith("+1")) { + if (tel.startsWith("1")) { + tel = "+" + tel; + } else if (!tel.startsWith("+")) { tel = "+1" + tel; } From ffc1daaa56f1246c97777c1c74b18e204dbc69e2 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 16 Feb 2022 16:04:19 -0500 Subject: [PATCH 4/4] any means none means false (ie there exist) unless upstream reports a reason --- src/main/java/eu/siacs/conversations/entities/Presences.java | 3 ++- .../eu/siacs/conversations/services/XmppConnectionService.java | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java index d0a25e884d52d0f3274bbceb0c961b99c1ccd5de..4753e2138f7e4949a00d2180e2253f5434c2a78f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presences.java +++ b/src/main/java/eu/siacs/conversations/entities/Presences.java @@ -152,7 +152,8 @@ public class Presences { public boolean anyIdentity(final String category, final String type) { synchronized (this.presences) { if (this.presences.size() == 0) { - return true; + // https://github.com/iNPUTmice/Conversations/issues/4230 + return false; } for (Presence presence : this.presences.values()) { ServiceDiscoveryResult disco = presence.getServiceDiscoveryResult(); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9c533e4905df42f2e96fa22295657518410556b2..c6e79d3af47ae6db8c5063a675c4dacc970befa5 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -234,8 +234,7 @@ public class XmppConnectionService extends Service { } } - if (contact.getPresences().size() > 0 && - contact.getPresences().anyIdentity("gateway", "pstn")) { + if (contact.getPresences().anyIdentity("gateway", "pstn")) { contact.registerAsPhoneAccount(this); } };