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

Commit 542e0ea8 authored by Ihab Awad's avatar Ihab Awad
Browse files

Publish new Telecomm API for Connection Services

Creates a new API for Connection Services providing phone connections to
the Android system. Supersedes CallService API, which will be gradually
replaced by this one.

Change-Id: Ie4b06c1b0843a777c5b8ee9c5dd12b9d9f990980
parent c9ee304c
Loading
Loading
Loading
Loading
+89 −0
Original line number Diff line number Diff line
@@ -26599,6 +26599,83 @@ package android.telecomm {
    enum_constant public static final android.telecomm.CallState RINGING;
  }
  public abstract class Connection {
    ctor protected Connection();
    method public final android.telecomm.CallAudioState getCallAudioState();
    method public final android.net.Uri getHandle();
    method protected void onAbort();
    method protected void onAnswer();
    method protected void onDisconnect();
    method protected void onHold();
    method protected void onPlayDtmfTone(char);
    method protected void onReject();
    method protected void onSetAudioState(android.telecomm.CallAudioState);
    method protected void onSetSignal(android.os.Bundle);
    method protected void onStopDtmfTone();
    method protected void onUnhold();
    method protected void setActive();
    method public void setAudioState(android.telecomm.CallAudioState);
    method protected void setDialing();
    method protected void setDisconnected(int, java.lang.String);
    method protected void setHandle(android.net.Uri);
    method protected void setOnHold();
    method protected void setRinging();
    method public static java.lang.String stateToString(int);
  }
  public static abstract interface Connection.Listener {
    method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
    method public abstract void onDestroyed(android.telecomm.Connection);
    method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
    method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
    method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
    method public abstract void onStateChanged(android.telecomm.Connection, int);
  }
  public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
    ctor public Connection.ListenerBase();
    method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
    method public void onDestroyed(android.telecomm.Connection);
    method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
    method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
    method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
    method public void onStateChanged(android.telecomm.Connection, int);
  }
  public final class Connection.State {
    field public static final int ACTIVE = 3; // 0x3
    field public static final int DIALING = 2; // 0x2
    field public static final int DISCONNECTED = 5; // 0x5
    field public static final int HOLDING = 4; // 0x4
    field public static final int NEW = 0; // 0x0
    field public static final int RINGING = 1; // 0x1
  }
  public final class ConnectionRequest {
    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
    method public android.os.Bundle getExtras();
    method public android.net.Uri getHandle();
  }
  public abstract class ConnectionService extends android.telecomm.CallService {
    ctor public ConnectionService();
    method public final void abort(java.lang.String);
    method public final void answer(java.lang.String);
    method public final void call(android.telecomm.CallInfo);
    method public final void disconnect(java.lang.String);
    method public final void hold(java.lang.String);
    method public final void isCompatibleWith(android.telecomm.CallInfo);
    method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
    method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
    method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
    method public final void playDtmfTone(java.lang.String, char);
    method public final void reject(java.lang.String);
    method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
    method public final void stopDtmfTone(java.lang.String);
    method public final void unhold(java.lang.String);
  }
  public class GatewayInfo implements android.os.Parcelable {
    method public int describeContents();
    method public android.net.Uri getGatewayHandle();
@@ -26650,6 +26727,18 @@ package android.telecomm {
    method protected abstract void updateCall(android.telecomm.InCallCall);
  }
  public abstract interface Response {
    method public abstract void onError(IN, java.lang.String);
    method public abstract void onResult(IN, OUT...);
  }
  public class Subscription implements android.os.Parcelable {
    ctor public Subscription();
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
  public final class TelecommConstants {
    ctor public TelecommConstants();
    field public static final java.lang.String ACTION_CALL_SERVICE;
+412 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telecomm;

import android.net.Uri;
import android.os.Bundle;
import android.util.Log;

import java.util.HashSet;
import java.util.Set;

/**
 * Represents a connection to a remote endpoint that carries voice traffic.
 */
public abstract class Connection {

    private static String TAG = Connection.class.getSimpleName();

    public interface Listener {
        void onStateChanged(Connection c, int state);
        void onAudioStateChanged(Connection c, CallAudioState state);
        void onHandleChanged(Connection c, Uri newHandle);
        void onSignalChanged(Connection c, Bundle details);
        void onDisconnected(Connection c, int cause, String message);
        void onDestroyed(Connection c);
    }

    public static class ListenerBase implements Listener {
        /** {@inheritDoc} */
        @Override
        public void onStateChanged(Connection c, int state) {}

        /** {@inheritDoc} */
         @Override
        public void onAudioStateChanged(Connection c, CallAudioState state) {}

        /** {@inheritDoc} */
        @Override
        public void onHandleChanged(Connection c, Uri newHandle) {}

        /** {@inheritDoc} */
        @Override
        public void onSignalChanged(Connection c, Bundle details) {}

        /** {@inheritDoc} */
        @Override
        public void onDisconnected(Connection c, int cause, String message) {}

        /** {@inheritDoc} */
        @Override
        public void onDestroyed(Connection c) {}
    }

    public final class State {
        private State() {}

        public static final int NEW = 0;
        public static final int RINGING = 1;
        public static final int DIALING = 2;
        public static final int ACTIVE = 3;
        public static final int HOLDING = 4;
        public static final int DISCONNECTED = 5;
    }

    private final Set<Listener> mListeners = new HashSet<>();
    private int mState = State.NEW;
    private CallAudioState mCallAudioState;
    private Uri mHandle;

    /**
     * Create a new Connection.
     */
    protected Connection() {}

    /**
     * @return The handle (e.g., phone number) to which this Connection
     *         is currently communicating.
     */
    public final Uri getHandle() {
        return mHandle;
    }

    /**
     * @return The state of this Connection.
     *
     * @hide
     */
    public final int getState() {
        return mState;
    }

    /**
     * @return The audio state of the call, describing how its audio is currently
     *         being routed by the system. This is {@code null} if this Connection
     *         does not directly know about its audio state.
     */
    public final CallAudioState getCallAudioState() {
        return mCallAudioState;
    }

    /**
     * Assign a listener to be notified of state changes.
     *
     * @param l A listener.
     * @return This Connection.
     *
     * @hide
     */
    public final Connection addConnectionListener(Listener l) {
        mListeners.add(l);
        return this;
    }

    /**
     * Remove a previously assigned listener that was being notified of state changes.
     *
     * @param l A Listener.
     * @return This Connection.
     *
     * @hide
     */
    public final Connection removeConnectionListener(Listener l) {
        mListeners.remove(l);
        return this;
    }

    /**
     * Play a DTMF tone in this Connection.
     *
     * @param c A DTMF character.
     *
     * @hide
     */
    public final void playDtmfTone(char c) {
        Log.d(TAG, "playDtmfTone " + c);
        onPlayDtmfTone(c);
    }

    /**
     * Stop any DTMF tones which may be playing in this Connection.
     *
     * @hide
     */
    public final void stopDtmfTone() {
        Log.d(TAG, "stopDtmfTone");
        onStopDtmfTone();
    }

    /**
     * Disconnect this Connection. If and when the Connection can comply with
     * this request, it will transition to the {@link State#DISCONNECTED}
     * state and notify its listeners.
     *
     * @hide
     */
    public final void disconnect() {
        Log.d(TAG, "disconnect");
        onDisconnect();
    }

    /**
     * Abort this Connection. The Connection will immediately transition to
     * the {@link State#DISCONNECTED} state, and send no notifications of this
     * or any other future events.
     *
     * @hide
     */
    public final void abort() {
        Log.d(TAG, "abort");
        onAbort();
    }

    /**
     * Place this Connection on hold. If and when the Connection can comply with
     * this request, it will transition to the {@link State#HOLDING}
     * state and notify its listeners.
     *
     * @hide
     */
    public final void hold() {
        Log.d(TAG, "hold");
        onHold();
    }

    /**
     * Un-hold this Connection. If and when the Connection can comply with
     * this request, it will transition to the {@link State#ACTIVE}
     * state and notify its listeners.
     *
     * @hide
     */
    public final void unhold() {
        Log.d(TAG, "unhold");
        onUnhold();
    }

    /**
     * Accept a {@link State#RINGING} Connection. If and when the Connection
     * can comply with this request, it will transition to the {@link State#ACTIVE}
     * state and notify its listeners.
     *
     * @hide
     */
    public final void answer() {
        Log.d(TAG, "answer");
        if (mState == State.RINGING) {
            onAnswer();
        }
    }

    /**
     * Reject a {@link State#RINGING} Connection. If and when the Connection
     * can comply with this request, it will transition to the {@link State#ACTIVE}
     * state and notify its listeners.
     *
     * @hide
     */
    public final void reject() {
        Log.d(TAG, "reject");
        if (mState == State.RINGING) {
            onReject();
        }
    }

    /**
     * Inform this Connection that the state of its audio output has been changed externally.
     *
     * @param state The new audio state.
     */
    public void setAudioState(CallAudioState state) {
        Log.d(TAG, "setAudioState " + state);
        onSetAudioState(state);
    }

    /**
     * @param state An integer value from {@link State}.
     * @return A string representation of the value.
     */
    public static String stateToString(int state) {
        switch (state) {
            case State.NEW:
                return "NEW";
            case State.RINGING:
                return "RINGING";
            case State.DIALING:
                return "DIALING";
            case State.ACTIVE:
                return "ACTIVE";
            case State.HOLDING:
                return "HOLDING";
            case State.DISCONNECTED:
                return "DISCONNECTED";
            default:
                Log.wtf(TAG, "Unknown state " + state);
                return "UNKNOWN";
        }
    }

    /**
     * Sets the value of the {@link #getHandle()} property and notifies listeners.
     *
     * @param handle The new handle.
     */
    protected void setHandle(Uri handle) {
        Log.d(TAG, "setHandle " + handle);
        // TODO: Enforce super called
        mHandle = handle;
        for (Listener l : mListeners) {
            l.onHandleChanged(this, handle);
        }
    }

    /**
     * Sets state to active (e.g., an ongoing call where two or more parties can actively
     * communicate).
     */
    protected void setActive() {
        setState(State.ACTIVE);
    }

    /**
     * Sets state to ringing (e.g., an inbound ringing call).
     */
    protected void setRinging() {
        setState(State.RINGING);
    }

    /**
     * Sets state to dialing (e.g., dialing an outbound call).
     */
    protected void setDialing() {
        setState(State.DIALING);
    }

    /**
     * Sets state to be on hold.
     */
    protected void setOnHold() {
        setState(State.HOLDING);
    }

    /**
     * Sets state to disconnected. This will first notify listeners with an
     * {@link Listener#onStateChanged(Connection, int)} event, then will fire an
     * {@link Listener#onDisconnected(Connection, int, String)} event with additional
     * details.
     *
     * @param cause The reason for the disconnection, any of
     *         {@link android.telephony.DisconnectCause}.
     * @param message Optional call-service-provided message about the disconnect.
     */
    protected void setDisconnected(int cause, String message) {
        setState(State.DISCONNECTED);
        Log.d(TAG, "Disconnected with cause " + cause + " message " + message);
        for (Listener l : mListeners) {
            l.onDisconnected(this, cause, message);
        }
    }

    /**
     * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
     * has a new value.
     *
     * @param state The new call audio state.
     */
    protected void onSetAudioState(CallAudioState state) {
        // TODO: Enforce super called
        this.mCallAudioState = state;
        for (Listener l : mListeners) {
            l.onAudioStateChanged(this, state);
        }
    }

    /**
     * Notifies this Connection and listeners of a change in the current signal levels
     * for the underlying data transport.
     *
     * @param details A {@link android.os.Bundle} containing details of the current level.
     */
    protected void onSetSignal(Bundle details) {
        // TODO: Enforce super called
        for (Listener l : mListeners) {
            l.onSignalChanged(this, details);
        }
    }

    /**
     * Notifies this Connection of a request to play a DTMF tone.
     *
     * @param c A DTMF character.
     */
    protected void onPlayDtmfTone(char c) {}

    /**
     * Notifies this Connection of a request to stop any currently playing DTMF tones.
     */
    protected void onStopDtmfTone() {}

    /**
     * Notifies this Connection of a request to disconnect.
     */
    protected void onDisconnect() {}

    /**
     * Notifies this Connection of a request to abort.
     */
    protected void onAbort() {}

    /**
     * Notifies this Connection of a request to hold.
     */
    protected void onHold() {}

    /**
     * Notifies this Connection of a request to exit a hold state.
     */
    protected void onUnhold() {}

    /**
     * Notifies this Connection, which is in {@link State#RINGING}, of
     * a request to accept.
     */
    protected void onAnswer() {}

    /**
     * Notifies this Connection, which is in {@link State#RINGING}, of
     * a request to reject.
     */
    protected void onReject() {}

    private void setState(int state) {
        Log.d(TAG, "setState: " + stateToString(state));
        this.mState = state;
        for (Listener l : mListeners) {
            l.onStateChanged(this, state);
        }
    }
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telecomm;

import android.os.Bundle;
import android.net.Uri;

/**
 * Simple data container encapsulating a request to some entity to
 * create a new {@link Connection}.
 */
public final class ConnectionRequest {

    // 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 Uri mHandle;
    private final Bundle mExtras;

    public ConnectionRequest(Uri handle, Bundle extras) {
        mHandle = handle; mExtras = extras;
    }

    /**
     * The handle (e.g., phone number) to which the {@link Connection} is to connect.
     */
    public Uri getHandle() { return mHandle; }

    /**
     * Application-specific extra data. Used for passing back information from an incoming
     * call {@code Intent}, and for any proprietary extensions arranged between a client
     * and servant {@code ConnectionService} which agree on a vocabulary for such data.
     */
    public Bundle getExtras() { return mExtras; }

    public String toString() {
        return String.format("PhoneConnectionRequest %s %s",
                mHandle == null
                        ? Uri.EMPTY
                        : ConnectionService.toLogSafePhoneNumber(mHandle.toString()),
                mExtras == null ? "" : mExtras);
    }
}
+345 −0

File added.

Preview size limit exceeded, changes collapsed.

+39 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telecomm;

/**
 * Used to inform a client of asynchronously returned results.
 */
public interface Response<IN, OUT> {

    /**
     * Provide a set of results.
     *
     * @param request The original request.
     * @param result The results.
     */
    void onResult(IN request, OUT... result);

    /**
     * Indicates the inability to provide results.
     *
     * @param request The original request.
     * @param reason The reason for the failure.
     */
    void onError(IN request, String reason);
}
Loading