Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68a73a4d authored by Tyler Gunn's avatar Tyler Gunn
Browse files

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
parent eb678ba1
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
@@ -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<>();
@@ -945,6 +950,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.
     *
+25 −0
Original line number Diff line number Diff line
@@ -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() {
+18 −0
Original line number Diff line number Diff line
@@ -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) {
            }
        }
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -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) {
+6 −0
Original line number Diff line number Diff line
@@ -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 =
Loading