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

Commit c5b01573 authored by Sailesh Nepal's avatar Sailesh Nepal
Browse files

Add support for remote incoming calls

This CL allows a incoming call to be handled through the
remote connection API.

All calls, incoming and outgoing, are now routed through
ConnectionService.createConnection.

Change-Id: I5232d062ad3b559f4fe7c8224e7234b2c6bf8431
parent 77ec2cea
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -27953,10 +27953,10 @@ package android.telecomm {
  public class CallPropertyPresentation {
    ctor public CallPropertyPresentation();
    field public static final int ALLOWED = 0; // 0x0
    field public static final int PAYPHONE = 3; // 0x3
    field public static final int RESTRICTED = 1; // 0x1
    field public static final int UNKNOWN = 2; // 0x2
    field public static final int ALLOWED = 1; // 0x1
    field public static final int PAYPHONE = 4; // 0x4
    field public static final int RESTRICTED = 2; // 0x2
    field public static final int UNKNOWN = 3; // 0x3
  }
  public final class CallState extends java.lang.Enum {
@@ -28076,7 +28076,8 @@ package android.telecomm {
  public abstract class ConnectionService extends android.app.Service {
    ctor public ConnectionService();
    method public final void createRemoteOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.OutgoingCallResponse<android.telecomm.RemoteConnection>);
    method public final void createRemoteIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>);
    method public final void createRemoteOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.RemoteConnection>);
    method public final java.util.Collection<android.telecomm.Connection> getAllConnections();
    method public final void lookupRemoteAccounts(android.net.Uri, android.telecomm.SimpleResponse<android.net.Uri, java.util.List<android.telecomm.PhoneAccount>>);
    method public final void maybeRespondToAccountLookup();
@@ -28084,11 +28085,11 @@ package android.telecomm {
    method protected void onConnectionAdded(android.telecomm.Connection);
    method protected void onConnectionRemoved(android.telecomm.Connection);
    method protected void onCreateConferenceConnection(java.lang.String, android.telecomm.Connection, android.telecomm.Response<java.lang.String, android.telecomm.Connection>);
    method protected void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.OutgoingCallResponse<android.telecomm.Connection>);
    method protected void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
    method protected void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>);
    method protected void onCreateOutgoingConnection(android.telecomm.ConnectionRequest, android.telecomm.ConnectionService.CreateConnectionResponse<android.telecomm.Connection>);
  }
  public static abstract interface ConnectionService.OutgoingCallResponse {
  public static abstract interface ConnectionService.CreateConnectionResponse {
    method public abstract void onCancel(android.telecomm.ConnectionRequest);
    method public abstract void onFailure(android.telecomm.ConnectionRequest, int, java.lang.String);
    method public abstract void onSuccess(android.telecomm.ConnectionRequest, CONNECTION);
@@ -29427,6 +29428,7 @@ package android.test.mock {
    method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
    method public java.lang.String getInstallerPackageName(java.lang.String);
    method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.pm.KeySet getKeySetByAlias(java.lang.String, java.lang.String);
    method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
    method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
    method public java.lang.String getNameForUid(int);
@@ -29444,12 +29446,15 @@ package android.test.mock {
    method public android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo);
    method public android.content.res.Resources getResourcesForApplication(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
    method public android.content.pm.KeySet getSigningKeySet(java.lang.String);
    method public android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
    method public java.lang.String[] getSystemSharedLibraryNames();
    method public java.lang.CharSequence getText(java.lang.String, int, android.content.pm.ApplicationInfo);
    method public android.content.res.XmlResourceParser getXml(java.lang.String, int, android.content.pm.ApplicationInfo);
    method public boolean hasSystemFeature(java.lang.String);
    method public boolean isSafeMode();
    method public boolean isSignedBy(java.lang.String, android.content.pm.KeySet);
    method public boolean isSignedByExactly(java.lang.String, android.content.pm.KeySet);
    method public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
    method public java.util.List<android.content.pm.ProviderInfo> queryContentProviders(java.lang.String, int, int);
    method public java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(java.lang.String, int);
+4 −4
Original line number Diff line number Diff line
@@ -19,14 +19,14 @@ package android.telecomm;
/** Defines how numbers and names are displayed in caller id. */
public class CallPropertyPresentation {
    /** Property is displayed normally. */
    public static final int ALLOWED = 0;
    public static final int ALLOWED = 1;

    /** Property was blocked. */
    public static final int RESTRICTED = 1;
    public static final int RESTRICTED = 2;

    /** Presentation was not specified or is unknown. */
    public static final int UNKNOWN = 2;
    public static final int UNKNOWN = 3;

    /** Property should be displayed as a pay phone. */
    public static final int PAYPHONE = 3;
    public static final int PAYPHONE = 4;
}
+21 −21
Original line number Diff line number Diff line
@@ -30,11 +30,11 @@ public final class ConnectionRequest implements Parcelable {
    // TODO: Token to limit recursive invocations
    // TODO: Consider upgrading "mHandle" to ordered list of handles, indicating a set of phone
    //         numbers that would satisfy the client's needs, in order of preference
    private final PhoneAccount mAccount;
    private final String mCallId;
    private final Uri mHandle;
    private final int mHandlePresentation;
    private final Bundle mExtras;
    private final PhoneAccount mAccount;
    private final int mVideoState;

    /**
@@ -61,6 +61,15 @@ public final class ConnectionRequest implements Parcelable {
        mVideoState = videoState;
    }

    private ConnectionRequest(Parcel in) {
        mAccount = in.readParcelable(getClass().getClassLoader());
        mCallId = in.readString();
        mHandle = in.readParcelable(getClass().getClassLoader());
        mHandlePresentation = in.readInt();
        mExtras = in.readParcelable(getClass().getClassLoader());
        mVideoState = in.readInt();
    }

    /**
     * The account which should be used to place the call.
     */
@@ -109,19 +118,10 @@ public final class ConnectionRequest implements Parcelable {
                mExtras == null ? "" : mExtras);
    }

    public static final Parcelable.Creator<ConnectionRequest> CREATOR =
            new Parcelable.Creator<ConnectionRequest> () {
    public static final Creator<ConnectionRequest> CREATOR = new Creator<ConnectionRequest> () {
        @Override
        public ConnectionRequest createFromParcel(Parcel source) {
                    PhoneAccount account = (PhoneAccount) source.readParcelable(
                            getClass().getClassLoader());
                    String callId = source.readString();
                    Uri handle = (Uri) source.readParcelable(getClass().getClassLoader());
                    int presentation = source.readInt();
                    Bundle extras = (Bundle) source.readParcelable(getClass().getClassLoader());
                    int videoState = source.readInt();
                    return new ConnectionRequest(
                            account, callId, handle, presentation, extras, videoState);
            return new ConnectionRequest(source);
        }

        @Override
+80 −101
Original line number Diff line number Diff line
@@ -47,22 +47,21 @@ public abstract class ConnectionService extends Service {
    private static final Connection NULL_CONNECTION = new Connection() {};

    private static final int MSG_ADD_CALL_SERVICE_ADAPTER = 1;
    private static final int MSG_CALL = 2;
    private static final int MSG_CREATE_CONNECTION = 2;
    private static final int MSG_ABORT = 3;
    private static final int MSG_CREATE_INCOMING_CALL = 4;
    private static final int MSG_ANSWER = 5;
    private static final int MSG_REJECT = 6;
    private static final int MSG_DISCONNECT = 7;
    private static final int MSG_HOLD = 8;
    private static final int MSG_UNHOLD = 9;
    private static final int MSG_ON_AUDIO_STATE_CHANGED = 10;
    private static final int MSG_PLAY_DTMF_TONE = 11;
    private static final int MSG_STOP_DTMF_TONE = 12;
    private static final int MSG_CONFERENCE = 13;
    private static final int MSG_SPLIT_FROM_CONFERENCE = 14;
    private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 15;
    private static final int MSG_ON_POST_DIAL_CONTINUE = 16;
    private static final int MSG_ON_PHONE_ACCOUNT_CLICKED = 17;
    private static final int MSG_ANSWER = 4;
    private static final int MSG_REJECT = 5;
    private static final int MSG_DISCONNECT = 6;
    private static final int MSG_HOLD = 7;
    private static final int MSG_UNHOLD = 8;
    private static final int MSG_ON_AUDIO_STATE_CHANGED = 9;
    private static final int MSG_PLAY_DTMF_TONE = 10;
    private static final int MSG_STOP_DTMF_TONE = 11;
    private static final int MSG_CONFERENCE = 12;
    private static final int MSG_SPLIT_FROM_CONFERENCE = 13;
    private static final int MSG_SWAP_WITH_BACKGROUND_CALL = 14;
    private static final int MSG_ON_POST_DIAL_CONTINUE = 15;
    private static final int MSG_ON_PHONE_ACCOUNT_CLICKED = 16;

    private final Map<String, Connection> mConnectionById = new HashMap<>();
    private final Map<Connection, String> mIdByConnection = new HashMap<>();
@@ -74,11 +73,11 @@ public abstract class ConnectionService extends Service {
    private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();

    /**
     * A callback for providing the resuilt of creating a connection.
     * A callback for providing the result of creating a connection.
     */
    public interface OutgoingCallResponse<CONNECTION> {
    public interface CreateConnectionResponse<CONNECTION> {
        /**
         * Tells Telecomm that an attempt to place the specified outgoing call succeeded.
         * Tells Telecomm that an attempt to create the connection succeeded.
         *
         * @param request The original request.
         * @param connection The connection.
@@ -86,7 +85,8 @@ public abstract class ConnectionService extends Service {
        void onSuccess(ConnectionRequest request, CONNECTION connection);

        /**
         * Tells Telecomm that an attempt to place the specified outgoing call failed.
         * Tells Telecomm that an attempt to create the connection failed. Telecomm will try a
         * different service until a service cancels the process or completes it successfully.
         *
         * @param request The original request.
         * @param code An integer code indicating the reason for failure.
@@ -95,7 +95,8 @@ public abstract class ConnectionService extends Service {
        void onFailure(ConnectionRequest request, int code, String msg);

        /**
         * Tells Telecomm to cancel the call.
         * Tells Telecomm to cancel creating the connection. Telecomm will stop trying to create
         * the connection an no more services will be tried.
         *
         * @param request The original request.
         */
@@ -109,8 +110,9 @@ public abstract class ConnectionService extends Service {
        }

        @Override
        public void call(ConnectionRequest request) {
            mHandler.obtainMessage(MSG_CALL, request).sendToTarget();
        public void createConnection(ConnectionRequest request, boolean isIncoming) {
            mHandler.obtainMessage(
                    MSG_CREATE_CONNECTION, isIncoming ? 1 : 0, 0, request).sendToTarget();
        }

        @Override
@@ -118,11 +120,6 @@ public abstract class ConnectionService extends Service {
            mHandler.obtainMessage(MSG_ABORT, callId).sendToTarget();
        }

        @Override
        public void createIncomingCall(ConnectionRequest request) {
            mHandler.obtainMessage(MSG_CREATE_INCOMING_CALL, request).sendToTarget();
        }

        @Override
        public void answer(String callId) {
            mHandler.obtainMessage(MSG_ANSWER, callId).sendToTarget();
@@ -206,15 +203,12 @@ public abstract class ConnectionService extends Service {
                    mAdapter.addAdapter((IConnectionServiceAdapter) msg.obj);
                    onAdapterAttached();
                    break;
                case MSG_CALL:
                    call((ConnectionRequest) msg.obj);
                case MSG_CREATE_CONNECTION:
                    createConnection((ConnectionRequest) msg.obj, msg.arg1 == 1);
                    break;
                case MSG_ABORT:
                    abort((String) msg.obj);
                    break;
                case MSG_CREATE_INCOMING_CALL:
                    createIncomingCall((ConnectionRequest) msg.obj);
                    break;
                case MSG_ANSWER:
                    answer((String) msg.obj);
                    break;
@@ -394,29 +388,39 @@ public abstract class ConnectionService extends Service {
        return mBinder;
    }

    private void call(final ConnectionRequest originalRequest) {
    /**
     * This can be used by telecomm to either create a new outgoing call or attach to an existing
     * incoming call. In either case, telecomm will cycle through a set of services and call
     * createConnection util a connection service cancels the process or completes it successfully.
     */
    private void createConnection(ConnectionRequest originalRequest, boolean isIncoming) {
        Log.d(this, "call %s", originalRequest);
        onCreateConnections(
                originalRequest,
                new OutgoingCallResponse<Connection>() {
        CreateConnectionResponse response = new CreateConnectionResponse<Connection>() {
            @Override
            public void onSuccess(ConnectionRequest request, Connection connection) {
                        Log.d(this, "adapter handleSuccessfulOutgoingCall %s", request.getCallId());
                        mAdapter.handleSuccessfulOutgoingCall(request);
                Log.d(this, "adapter handleCreateConnectionSuccessful %s",
                        request.getCallId());
                mAdapter.handleCreateConnectionSuccessful(request);
                addConnection(request.getCallId(), connection);
            }

            @Override
            public void onFailure(ConnectionRequest request, int code, String msg) {
                        mAdapter.handleFailedOutgoingCall(request, code, msg);
                // Tell telecomm to try a different service.
                mAdapter.handleCreateConnectionFailed(request, code, msg);
            }

            @Override
            public void onCancel(ConnectionRequest request) {
                        mAdapter.cancelOutgoingCall(request);
                // Tell telecomm not to attempt any more services.
                mAdapter.handleCreateConnectionCancelled(request);
            }
        };
        if (isIncoming) {
            onCreateIncomingConnection(originalRequest, response);
        } else {
            onCreateOutgoingConnection(originalRequest, response);
        }
        );
    }

    private void abort(String callId) {
@@ -424,33 +428,6 @@ public abstract class ConnectionService extends Service {
        findConnectionForAction(callId, "abort").onAbort();
    }

    private void createIncomingCall(ConnectionRequest originalRequest) {
        Log.d(this, "createIncomingCall %s", originalRequest);
        onCreateIncomingConnection(
                originalRequest,
                new Response<ConnectionRequest, Connection>() {
                    @Override
                    public void onResult(ConnectionRequest request, Connection... result) {
                        if (result != null && result.length != 1) {
                            for (Connection c : result) {
                                c.onAbort();
                            }
                        } else {
                            addConnection(request.getCallId(), result[0]);
                            Log.d(this, "adapter notifyIncomingCall %s", request);
                            mAdapter.notifyIncomingCall(request);
                        }
                    }

                    @Override
                    public void onError(ConnectionRequest request, int code, String msg) {
                        Log.d(this, "adapter failed createIncomingCall %s %d %s",
                                request, code, msg);
                    }
                }
        );
    }

    private void answer(String callId) {
        Log.d(this, "answer %s", callId);
        findConnectionForAction(callId, "answer").onAnswer();
@@ -570,7 +547,7 @@ public abstract class ConnectionService extends Service {
                                    IConnectionService.Stub.asInterface(services.get(i)));
                        }
                        mAreAccountsInitialized = true;
                        Log.d(this, "remote call services found: " + services);
                        Log.d(this, "remote connection services found: " + services);
                        maybeRespondToAccountLookup();
                    }
                });
@@ -606,10 +583,16 @@ public abstract class ConnectionService extends Service {
        }
    }

    public final void createRemoteIncomingConnection(
            ConnectionRequest request,
            CreateConnectionResponse<RemoteConnection> response) {
        mRemoteConnectionManager.createRemoteConnection(request, response, true);
    }

    public final void createRemoteOutgoingConnection(
            ConnectionRequest request,
            OutgoingCallResponse<RemoteConnection> response) {
        mRemoteConnectionManager.createOutgoingConnection(request, response);
            CreateConnectionResponse<RemoteConnection> response) {
        mRemoteConnectionManager.createRemoteConnection(request, response, false);
    }

    /**
@@ -620,14 +603,25 @@ public abstract class ConnectionService extends Service {
    }

    /**
     * Create a Connection given a request.
     * Create a Connection given an incoming request. This is used to attach to existing incoming
     * calls.
     *
     * @param request Details about the incoming call.
     * @param callback A callback for providing the result.
     */
    protected void onCreateIncomingConnection(
            ConnectionRequest request,
            CreateConnectionResponse<Connection> callback) {}

    /**
     * Create a Connection given an outgoing request. This is used to initiate new outgoing calls.
     *
     * @param request Data encapsulating details of the desired Connection.
     * @param request Details about the outgoing call.
     * @param callback A callback for providing the result.
     */
    protected void onCreateConnections(
    protected void onCreateOutgoingConnection(
            ConnectionRequest request,
            OutgoingCallResponse<Connection> callback) {}
            CreateConnectionResponse<Connection> callback) {}

    /**
     * Returns a new or existing conference connection when the the user elects to convert the
@@ -644,21 +638,6 @@ public abstract class ConnectionService extends Service {
            Connection connection,
            Response<String, Connection> callback) {}

    /**
     * Create a Connection to match an incoming connection notification.
     *
     * IMPORTANT: If the incoming connection has a phone number (or other handle) that the user
     * is not supposed to be able to see (e.g. it is PRESENTATION_RESTRICTED), then a compliant
     * ConnectionService implementation MUST NOT reveal this phone number as part of the Intent
     * it sends to notify Telecomm of an incoming connection.
     *
     * @param request Data encapsulating details of the desired Connection.
     * @param callback A callback for providing the result.
     */
    protected void onCreateIncomingConnection(
            ConnectionRequest request,
            Response<ConnectionRequest, Connection> callback) {}

    /**
     * Notifies that a connection has been added to this connection service and sent to Telecomm.
     *
+6 −43
Original line number Diff line number Diff line
@@ -73,65 +73,28 @@ final class ConnectionServiceAdapter implements DeathRecipient {
        }
    }

    /**
     * Provides Telecomm with the details of an incoming call. An invocation of this method must
     * follow {@link ConnectionService#setIncomingCallId} and use the call ID specified therein.
     * Upon the invocation of this method, Telecomm will bring up the incoming-call interface where
     * the user can elect to answer or reject a call.
     *
     * @param request The connection request.
     */
    void notifyIncomingCall(ConnectionRequest request) {
    void handleCreateConnectionSuccessful(ConnectionRequest request) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.notifyIncomingCall(request);
                adapter.handleCreateConnectionSuccessful(request);
            } catch (RemoteException e) {
            }
        }
    }

    /**
     * Tells Telecomm that an attempt to place the specified outgoing call succeeded.
     *
     * @param request The originating request for a connection.
     */
    void handleSuccessfulOutgoingCall(ConnectionRequest request) {
    void handleCreateConnectionFailed(ConnectionRequest request, int errorCode, String errorMsg) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.handleSuccessfulOutgoingCall(request);
                adapter.handleCreateConnectionFailed(request, errorCode, errorMsg);
            } catch (RemoteException e) {
            }
        }
    }

    /**
     * Tells Telecomm that an attempt to place the specified outgoing call failed.
     *
     * @param request The originating request for a connection.
     * @param errorCode The error code associated with the failed call attempt.
     * @param errorMsg The error message associated with the failed call attempt.
     */
    void handleFailedOutgoingCall(
            ConnectionRequest request,
            int errorCode,
            String errorMsg) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.handleFailedOutgoingCall(request, errorCode, errorMsg);
            } catch (RemoteException e) {
            }
        }
    }

    /**
     * Tells Telecomm to cancel the call.
     *
     * @param request The originating request for a connection.
     */
    void cancelOutgoingCall(ConnectionRequest request) {
    void handleCreateConnectionCancelled(ConnectionRequest request) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.cancelOutgoingCall(request);
                adapter.handleCreateConnectionCancelled(request);
            } catch (RemoteException e) {
            }
        }
Loading