diff options
author | 2018-10-03 15:38:57 -0700 | |
---|---|---|
committer | 2019-01-19 10:27:23 -0800 | |
commit | 68a73a4d0d720607ffc47c3d80fb91ebc1171653 (patch) | |
tree | e198a44e68b91691e17c1fd45f714542635f5bba | |
parent | eb678ba1d38f34a8e28fd51c44640e3b03ab1303 (diff) |
Support for treating single party IMS conference as a standalone call.
Adding @hide APIs which Telephony can use to make a conference call with
a single participant look like its a standalone call.
Test: Manual testing
Bug: 75975913
Change-Id: Id8532234ab295785fc749b120898f43911e12637
6 files changed, 131 insertions, 0 deletions
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index a39e885204b7..7d1f8ce75919 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -19,6 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.telecom.Connection.VideoProvider; @@ -64,6 +65,10 @@ public abstract class Conference extends Conferenceable { public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {} public void onExtrasChanged(Conference c, Bundle extras) {} public void onExtrasRemoved(Conference c, List<String> keys) {} + public void onConferenceStateChanged(Conference c, boolean isConference) {} + public void onAddressChanged(Conference c, Uri newAddress, int presentation) {} + public void onCallerDisplayNameChanged( + Conference c, String callerDisplayName, int presentation) {} } private final Set<Listener> mListeners = new CopyOnWriteArraySet<>(); @@ -946,6 +951,62 @@ public abstract class Conference extends Conferenceable { public void onExtrasChanged(Bundle extras) {} /** + * Set whether Telecom should treat this {@link Conference} as a conference call or if it + * should treat it as a single-party call. + * This method is used as part of a workaround regarding IMS conference calls and user + * expectation. In IMS, once a conference is formed, the UE is connected to an IMS conference + * server. If all participants of the conference drop out of the conference except for one, the + * UE is still connected to the IMS conference server. At this point, the user logically + * assumes they're no longer in a conference, yet the underlying network actually is. + * To help provide a better user experiece, IMS conference calls can pretend to actually be a + * single-party call when the participant count drops to 1. Although the dialer/phone app + * could perform this trickery, it makes sense to do this in Telephony since a fix there will + * ensure that bluetooth head units, auto and wearable apps all behave consistently. + * + * @param isConference {@code true} if this {@link Conference} should be treated like a + * conference call, {@code false} if it should be treated like a single-party call. + * @hide + */ + public void setConferenceState(boolean isConference) { + for (Listener l : mListeners) { + l.onConferenceStateChanged(this, isConference); + } + } + + /** + * Sets the address of this {@link Conference}. Used when {@link #setConferenceState(boolean)} + * is called to mark a conference temporarily as NOT a conference. + * + * @param address The new address. + * @param presentation The presentation requirements for the address. + * See {@link TelecomManager} for valid values. + * @hide + */ + public final void setAddress(Uri address, int presentation) { + Log.d(this, "setAddress %s", address); + for (Listener l : mListeners) { + l.onAddressChanged(this, address, presentation); + } + } + + /** + * Sets the caller display name (CNAP) of this {@link Conference}. Used when + * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a + * conference. + * + * @param callerDisplayName The new display name. + * @param presentation The presentation requirements for the handle. + * See {@link TelecomManager} for valid values. + * @hide + */ + public final void setCallerDisplayName(String callerDisplayName, int presentation) { + Log.d(this, "setCallerDisplayName %s", callerDisplayName); + for (Listener l : mListeners) { + l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); + } + } + + /** * Handles a change to extras received from Telecom. * * @param extras The new extras. diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 4c2d22fdc0de..82db0d2ecb96 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -1254,6 +1254,31 @@ public abstract class ConnectionService extends Service { mAdapter.removeExtras(id, keys); } } + + @Override + public void onConferenceStateChanged(Conference c, boolean isConference) { + String id = mIdByConference.get(c); + if (id != null) { + mAdapter.setConferenceState(id, isConference); + } + } + + @Override + public void onAddressChanged(Conference c, Uri newAddress, int presentation) { + String id = mIdByConference.get(c); + if (id != null) { + mAdapter.setAddress(id, newAddress, presentation); + } + } + + @Override + public void onCallerDisplayNameChanged(Conference c, String callerDisplayName, + int presentation) { + String id = mIdByConference.get(c); + if (id != null) { + mAdapter.setCallerDisplayName(id, callerDisplayName, presentation); + } + } }; private final Connection.Listener mConnectionListener = new Connection.Listener() { diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java index 520e7eda6f69..6c3f4f34ff2d 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java @@ -653,4 +653,22 @@ final class ConnectionServiceAdapter implements DeathRecipient { } } } + + /** + * Sets whether a conference is treated as a conference or a single party call. + * See {@link Conference#setConferenceState(boolean)} for more information. + * + * @param callId The ID of the telecom call. + * @param isConference {@code true} if this call should be treated as a conference, + * {@code false} otherwise. + */ + void setConferenceState(String callId, boolean isConference) { + Log.v(this, "setConferenceState: %s %b", callId, isConference); + for (IConnectionServiceAdapter adapter : mAdapters) { + try { + adapter.setConferenceState(callId, isConference, Log.getExternalSession()); + } catch (RemoteException ignored) { + } + } + } } diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java index 78d65e643abc..f99b218bd9b9 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java @@ -74,6 +74,7 @@ final class ConnectionServiceAdapterServant { private static final int MSG_ON_RTT_UPGRADE_REQUEST = 33; private static final int MSG_SET_PHONE_ACCOUNT_CHANGED = 34; private static final int MSG_CONNECTION_SERVICE_FOCUS_RELEASED = 35; + private static final int MSG_SET_CONFERENCE_STATE = 36; private final IConnectionServiceAdapter mDelegate; @@ -333,6 +334,14 @@ final class ConnectionServiceAdapterServant { case MSG_CONNECTION_SERVICE_FOCUS_RELEASED: mDelegate.onConnectionServiceFocusReleased(null /*Session.Info*/); break; + case MSG_SET_CONFERENCE_STATE: + SomeArgs args = (SomeArgs) msg.obj; + try { + mDelegate.setConferenceState((String) args.arg1, (Boolean) args.arg2, + (Session.Info) args.arg3); + } finally { + args.recycle(); + } } } }; @@ -615,6 +624,16 @@ final class ConnectionServiceAdapterServant { public void resetConnectionTime(String callId, Session.Info sessionInfo) { // Do nothing } + + @Override + public void setConferenceState(String callId, boolean isConference, + Session.Info sessionInfo) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.arg2 = isConference; + args.arg3 = sessionInfo; + mHandler.obtainMessage(MSG_SET_CONFERENCE_STATE, args).sendToTarget(); + } }; public ConnectionServiceAdapterServant(IConnectionServiceAdapter delegate) { diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 9821dcbce85e..744544eb01f1 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -471,6 +471,12 @@ final class RemoteConnectionService { public void resetConnectionTime(String callId, Session.Info sessionInfo) { // Do nothing } + + @Override + public void setConferenceState(String callId, boolean isConference, + Session.Info sessionInfo) { + // Do nothing + } }; private final ConnectionServiceAdapterServant mServant = diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl index 0157a5863363..76ac88e9fbaa 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl @@ -123,4 +123,6 @@ oneway interface IConnectionServiceAdapter { void onConnectionServiceFocusReleased(in Session.Info sessionInfo); void resetConnectionTime(String callIdi, in Session.Info sessionInfo); + + void setConferenceState(String callId, boolean isConference, in Session.Info sessionInfo); } |