summaryrefslogtreecommitdiffstats
path: root/telecomm/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'telecomm/java/android')
-rw-r--r--telecomm/java/android/telecomm/CallAudioState.aidl19
-rw-r--r--telecomm/java/android/telecomm/CallAudioState.java160
-rw-r--r--telecomm/java/android/telecomm/CallCapabilities.java50
-rw-r--r--telecomm/java/android/telecomm/CallInfo.aidl19
-rw-r--r--telecomm/java/android/telecomm/CallInfo.java186
-rw-r--r--telecomm/java/android/telecomm/CallNumberPresentation.java32
-rw-r--r--telecomm/java/android/telecomm/CallService.java362
-rw-r--r--telecomm/java/android/telecomm/CallServiceAdapter.java160
-rw-r--r--telecomm/java/android/telecomm/CallServiceDescriptor.aidl19
-rw-r--r--telecomm/java/android/telecomm/CallServiceDescriptor.java232
-rw-r--r--telecomm/java/android/telecomm/CallServiceLookupResponse.java51
-rw-r--r--telecomm/java/android/telecomm/CallServiceProvider.java109
-rw-r--r--telecomm/java/android/telecomm/CallServiceSelector.java152
-rw-r--r--telecomm/java/android/telecomm/CallServiceSelectorAdapter.java84
-rw-r--r--telecomm/java/android/telecomm/CallState.java96
-rw-r--r--telecomm/java/android/telecomm/GatewayInfo.aidl19
-rw-r--r--telecomm/java/android/telecomm/GatewayInfo.java106
-rw-r--r--telecomm/java/android/telecomm/InCallAdapter.java199
-rw-r--r--telecomm/java/android/telecomm/InCallCall.aidl19
-rw-r--r--telecomm/java/android/telecomm/InCallCall.java159
-rw-r--r--telecomm/java/android/telecomm/InCallService.java209
-rw-r--r--telecomm/java/android/telecomm/TelecommConstants.java97
22 files changed, 2539 insertions, 0 deletions
diff --git a/telecomm/java/android/telecomm/CallAudioState.aidl b/telecomm/java/android/telecomm/CallAudioState.aidl
new file mode 100644
index 0000000..ae64567
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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;
+
+parcelable CallAudioState;
diff --git a/telecomm/java/android/telecomm/CallAudioState.java b/telecomm/java/android/telecomm/CallAudioState.java
new file mode 100644
index 0000000..d9a0090
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallAudioState.java
@@ -0,0 +1,160 @@
+/*
+ * 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.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ * Encapsulates all audio states during a call.
+ */
+public final class CallAudioState implements Parcelable {
+ /** Direct the audio stream through the device's earpiece. */
+ public static int ROUTE_EARPIECE = 0x00000001;
+
+ /** Direct the audio stream through Bluetooth. */
+ public static int ROUTE_BLUETOOTH = 0x00000002;
+
+ /** Direct the audio stream through a wired headset. */
+ public static int ROUTE_WIRED_HEADSET = 0x00000004;
+
+ /** Direct the audio stream through the device's spakerphone. */
+ public static int ROUTE_SPEAKER = 0x00000008;
+
+ /**
+ * Direct the audio stream through the device's earpiece or wired headset if one is
+ * connected.
+ */
+ public static int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
+
+ /** Bit mask of all possible audio routes. */
+ public static int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
+ ROUTE_SPEAKER;
+
+ /** True if the call is muted, false otherwise. */
+ public final boolean isMuted;
+
+ /** The route to use for the audio stream. */
+ public final int route;
+
+ /** Bit vector of all routes supported by this call. */
+ public final int supportedRouteMask;
+
+ /** @hide */
+ public CallAudioState(boolean isMuted, int route, int supportedRouteMask) {
+ this.isMuted = isMuted;
+ this.route = route;
+ this.supportedRouteMask = supportedRouteMask;
+ }
+
+ /** @hide */
+ public CallAudioState(CallAudioState state) {
+ isMuted = state.isMuted;
+ route = state.route;
+ supportedRouteMask = state.supportedRouteMask;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CallAudioState)) {
+ return false;
+ }
+ CallAudioState state = (CallAudioState) obj;
+ return isMuted == state.isMuted && route == state.route &&
+ supportedRouteMask == state.supportedRouteMask;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US,
+ "[CallAudioState isMuted: %b, route; %s, supportedRouteMask: %s]",
+ isMuted, audioRouteToString(route), audioRouteToString(supportedRouteMask));
+ }
+
+ /** @hide */
+ public static String audioRouteToString(int route) {
+ if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
+ return "UNKNOWN";
+ }
+
+ StringBuffer buffer = new StringBuffer();
+ if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
+ listAppend(buffer, "EARPIECE");
+ }
+ if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
+ listAppend(buffer, "BLUETOOTH");
+ }
+ if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
+ listAppend(buffer, "WIRED_HEADSET");
+ }
+ if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
+ listAppend(buffer, "SPEAKER");
+ }
+
+ return buffer.toString();
+ }
+
+ private static void listAppend(StringBuffer buffer, String str) {
+ if (buffer.length() > 0) {
+ buffer.append(", ");
+ }
+ buffer.append(str);
+ }
+
+ /**
+ * Responsible for creating CallAudioState objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallAudioState> CREATOR =
+ new Parcelable.Creator<CallAudioState> () {
+
+ @Override
+ public CallAudioState createFromParcel(Parcel source) {
+ boolean isMuted = source.readByte() == 0 ? false : true;
+ int route = source.readInt();
+ int supportedRouteMask = source.readInt();
+ return new CallAudioState(isMuted, route, supportedRouteMask);
+ }
+
+ @Override
+ public CallAudioState[] newArray(int size) {
+ return new CallAudioState[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes CallAudioState object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeByte((byte) (isMuted ? 1 : 0));
+ destination.writeInt(route);
+ destination.writeInt(supportedRouteMask);
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallCapabilities.java b/telecomm/java/android/telecomm/CallCapabilities.java
new file mode 100644
index 0000000..b2b33a3
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallCapabilities.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 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;
+
+/** Defines actions a call currently supports. */
+public class CallCapabilities {
+ /** Call can currently be put on hold or unheld. */
+ public static final int HOLD = 0x00000001;
+
+ /** Call supports the hold feature. */
+ public static final int SUPPORT_HOLD = 0x00000002;
+
+ /** Call can currently be merged. */
+ public static final int MERGE_CALLS = 0x00000004;
+
+ /* Call can currently be swapped with another call. */
+ public static final int SWAP_CALLS = 0x00000008;
+
+ /* Call currently supports adding another call to this one. */
+ public static final int ADD_CALL = 0x00000010;
+
+ /* Call supports responding via text option. */
+ public static final int RESPOND_VIA_TEXT = 0x00000020;
+
+ /* Call can be muted. */
+ public static final int MUTE = 0x00000040;
+
+ /* Call supports generic conference mode. */
+ public static final int GENERIC_CONFERENCE = 0x00000080;
+
+ /* Call currently supports switch between connections. */
+ public static final int CONNECTION_HANDOFF = 0x00000100;
+
+ public static final int ALL = HOLD | SUPPORT_HOLD | MERGE_CALLS | SWAP_CALLS | ADD_CALL
+ | RESPOND_VIA_TEXT | MUTE | GENERIC_CONFERENCE | CONNECTION_HANDOFF;
+}
diff --git a/telecomm/java/android/telecomm/CallInfo.aidl b/telecomm/java/android/telecomm/CallInfo.aidl
new file mode 100644
index 0000000..bc5ef96
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2013, 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;
+
+parcelable CallInfo;
diff --git a/telecomm/java/android/telecomm/CallInfo.java b/telecomm/java/android/telecomm/CallInfo.java
new file mode 100644
index 0000000..cb7f2dc
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallInfo.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2013, 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.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+
+/**
+ * A parcelable holder class of Call information data. This class is intended for transfering call
+ * information from Telecomm to call services and thus is read-only.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallInfo implements Parcelable {
+
+ /**
+ * Unique identifier for the call.
+ */
+ private final String mId;
+
+ /**
+ * The state of the call.
+ */
+ private final CallState mState;
+
+ /**
+ * Endpoint to which the call is connected.
+ * This could be the dialed value for outgoing calls or the caller id of incoming calls.
+ */
+ private final Uri mHandle;
+
+ /**
+ * Gateway information for the call.
+ */
+ private final GatewayInfo mGatewayInfo;
+
+ /**
+ * Additional information that can be persisted. For example, extra handoff information can
+ * attached to a call using {@link CallServiceSelectorAdapter#setHandoffInfo(String,Uri,Bundle).
+ */
+ private final Bundle mExtras;
+
+ /** The descriptor for the call service currently routing this call. */
+ private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+
+ public CallInfo(String id, CallState state, Uri handle) {
+ this(id, state, handle, null, Bundle.EMPTY, null);
+ }
+
+ /**
+ * Persists handle of the other party of this call.
+ *
+ * @param id The unique ID of the call.
+ * @param state The state of the call.
+ * @param handle The handle to the other party in this call.
+ * @param gatewayInfo Gateway information pertaining to this call.
+ * @param extras Additional information that can be persisted.
+ * @param currentCallServiceDescriptor The descriptor for the call service currently routing
+ * this call.
+ *
+ * @hide
+ */
+ public CallInfo(
+ String id,
+ CallState state,
+ Uri handle,
+ GatewayInfo gatewayInfo,
+ Bundle extras,
+ CallServiceDescriptor currentCallServiceDescriptor) {
+ mId = id;
+ mState = state;
+ mHandle = handle;
+ mGatewayInfo = gatewayInfo;
+ mExtras = extras;
+ mCurrentCallServiceDescriptor = currentCallServiceDescriptor;
+ }
+
+ public String getId() {
+ return mId;
+ }
+
+ public CallState getState() {
+ return mState;
+ }
+
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /**
+ * @return The actual handle this call is associated with. This is used by call services to
+ * correctly indicate in their UI what handle the user is actually calling, and by other
+ * telecomm components that require the user-dialed handle to function.
+ */
+ public Uri getOriginalHandle() {
+ if (mGatewayInfo != null) {
+ return mGatewayInfo.getOriginalHandle();
+ }
+ return getHandle();
+ }
+
+ public GatewayInfo getGatewayInfo() {
+ return mGatewayInfo;
+ }
+
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+ return mCurrentCallServiceDescriptor;
+ }
+
+ /**
+ * Responsible for creating CallInfo objects for deserialized Parcels.
+ */
+ public static final Parcelable.Creator<CallInfo> CREATOR = new Parcelable.Creator<CallInfo> () {
+ @Override
+ public CallInfo createFromParcel(Parcel source) {
+ String id = source.readString();
+ CallState state = CallState.valueOf(source.readString());
+ Uri handle = Uri.CREATOR.createFromParcel(source);
+
+ boolean gatewayInfoPresent = source.readByte() != 0;
+ GatewayInfo gatewayInfo = null;
+ if (gatewayInfoPresent) {
+ gatewayInfo = GatewayInfo.CREATOR.createFromParcel(source);
+ }
+
+ ClassLoader classLoader = CallInfo.class.getClassLoader();
+ Bundle extras = source.readParcelable(classLoader);
+ CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+ return new CallInfo(id, state, handle, gatewayInfo, extras, descriptor);
+ }
+
+ @Override
+ public CallInfo[] newArray(int size) {
+ return new CallInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Writes CallInfo object into a serializeable Parcel.
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mId);
+ destination.writeString(mState.name());
+ mHandle.writeToParcel(destination, 0);
+
+ if (mGatewayInfo != null) {
+ destination.writeByte((byte) 1);
+ mGatewayInfo.writeToParcel(destination, 0);
+ } else {
+ destination.writeByte((byte) 0);
+ }
+
+ destination.writeParcelable(mExtras, 0);
+ destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallNumberPresentation.java b/telecomm/java/android/telecomm/CallNumberPresentation.java
new file mode 100644
index 0000000..6cd22f8
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallNumberPresentation.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 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;
+
+/** Defines how numbers are displayed in caller id. */
+public enum CallNumberPresentation {
+ /** Number is displayed normally. */
+ ALLOWED,
+
+ /** Number was blocked. */
+ RESTRICTED,
+
+ /** Presentation was not specified or is unknown. */
+ UNKNOWN,
+
+ /** Number should be displayed as a pay phone. */
+ PAYPHONE
+}
diff --git a/telecomm/java/android/telecomm/CallService.java b/telecomm/java/android/telecomm/CallService.java
new file mode 100644
index 0000000..51f10c1
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallService.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2013 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.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallService;
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Base implementation of CallService which can be used to provide calls for the system
+ * in-call UI. CallService is a one-way service from the framework's CallsManager to any app
+ * that would like to provide calls managed by the default system in-call user interface.
+ * When the service is bound by the framework, CallsManager will call setCallServiceAdapter
+ * which will provide CallService with an instance of {@link CallServiceAdapter} to be used
+ * for communicating back to CallsManager. Subsequently, more specific methods of the service
+ * will be called to perform various call actions including making an outgoing call and
+ * disconnected existing calls.
+ * TODO(santoscordon): Needs more about AndroidManifest.xml service registrations before
+ * we can unhide this API.
+ *
+ * Most public methods of this function are backed by a one-way AIDL interface which precludes
+ * synchronous responses. As a result, most responses are handled by (or have TODOs to handle)
+ * response objects instead of return values.
+ * TODO(santoscordon): Improve paragraph above once the final design is in place.
+ */
+public abstract class CallService extends Service {
+
+ private static final int MSG_SET_CALL_SERVICE_ADAPTER = 1;
+ private static final int MSG_IS_COMPATIBLE_WITH = 2;
+ private static final int MSG_CALL = 3;
+ private static final int MSG_ABORT = 4;
+ private static final int MSG_SET_INCOMING_CALL_ID = 5;
+ private static final int MSG_ANSWER = 6;
+ private static final int MSG_REJECT = 7;
+ private static final int MSG_DISCONNECT = 8;
+ private static final int MSG_HOLD = 9;
+ private static final int MSG_UNHOLD = 10;
+ private static final int MSG_ON_AUDIO_STATE_CHANGED = 11;
+ private static final int MSG_PLAY_DTMF_TONE = 12;
+ private static final int MSG_STOP_DTMF_TONE = 13;
+
+ /**
+ * Default Handler used to consolidate binder method calls onto a single thread.
+ */
+ private final class CallServiceMessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALL_SERVICE_ADAPTER:
+ mAdapter = new CallServiceAdapter((ICallServiceAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_IS_COMPATIBLE_WITH:
+ isCompatibleWith((CallInfo) msg.obj);
+ break;
+ case MSG_CALL:
+ call((CallInfo) msg.obj);
+ break;
+ case MSG_ABORT:
+ abort((String) msg.obj);
+ break;
+ case MSG_SET_INCOMING_CALL_ID: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ Bundle extras = (Bundle) args.arg2;
+ setIncomingCallId(callId, extras);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_ANSWER:
+ answer((String) msg.obj);
+ break;
+ case MSG_REJECT:
+ reject((String) msg.obj);
+ break;
+ case MSG_DISCONNECT:
+ disconnect((String) msg.obj);
+ break;
+ case MSG_HOLD:
+ hold((String) msg.obj);
+ break;
+ case MSG_UNHOLD:
+ unhold((String) msg.obj);
+ break;
+ case MSG_ON_AUDIO_STATE_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ CallAudioState audioState = (CallAudioState) args.arg2;
+ onAudioStateChanged(callId, audioState);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_PLAY_DTMF_TONE:
+ playDtmfTone((String) msg.obj, (char) msg.arg1);
+ break;
+ case MSG_STOP_DTMF_TONE:
+ stopDtmfTone((String) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Default ICallService implementation provided to CallsManager via {@link #onBind}.
+ */
+ private final class CallServiceBinder extends ICallService.Stub {
+ @Override
+ public void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
+ mMessageHandler.obtainMessage(MSG_SET_CALL_SERVICE_ADAPTER, callServiceAdapter)
+ .sendToTarget();
+ }
+
+ @Override
+ public void isCompatibleWith(CallInfo callInfo) {
+ mMessageHandler.obtainMessage(MSG_IS_COMPATIBLE_WITH, callInfo).sendToTarget();
+ }
+
+ @Override
+ public void call(CallInfo callInfo) {
+ mMessageHandler.obtainMessage(MSG_CALL, callInfo).sendToTarget();
+ }
+
+ @Override
+ public void abort(String callId) {
+ mMessageHandler.obtainMessage(MSG_ABORT, callId).sendToTarget();
+ }
+
+ @Override
+ public void setIncomingCallId(String callId, Bundle extras) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = extras;
+ mMessageHandler.obtainMessage(MSG_SET_INCOMING_CALL_ID, args).sendToTarget();
+ }
+
+ @Override
+ public void answer(String callId) {
+ mMessageHandler.obtainMessage(MSG_ANSWER, callId).sendToTarget();
+ }
+
+ @Override
+ public void reject(String callId) {
+ mMessageHandler.obtainMessage(MSG_REJECT, callId).sendToTarget();
+ }
+
+ @Override
+ public void disconnect(String callId) {
+ mMessageHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
+ }
+
+ @Override
+ public void hold(String callId) {
+ mMessageHandler.obtainMessage(MSG_HOLD, callId).sendToTarget();
+ }
+
+ @Override
+ public void unhold(String callId) {
+ mMessageHandler.obtainMessage(MSG_UNHOLD, callId).sendToTarget();
+ }
+
+ @Override
+ public void playDtmfTone(String callId, char digit) {
+ mMessageHandler.obtainMessage(MSG_PLAY_DTMF_TONE, digit, 0, callId).sendToTarget();
+ }
+
+ @Override
+ public void stopDtmfTone(String callId) {
+ mMessageHandler.obtainMessage(MSG_STOP_DTMF_TONE, callId).sendToTarget();
+ }
+
+ @Override
+ public void onAudioStateChanged(String callId, CallAudioState audioState) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = audioState;
+ mMessageHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, args).sendToTarget();
+ }
+ }
+
+ /**
+ * Message handler for consolidating binder callbacks onto a single thread.
+ * See {@link CallServiceMessageHandler}.
+ */
+ private final CallServiceMessageHandler mMessageHandler = new CallServiceMessageHandler();
+
+ /**
+ * Default binder implementation of {@link ICallService} interface.
+ */
+ private final CallServiceBinder mBinder = new CallServiceBinder();
+
+ private CallServiceAdapter mAdapter = null;
+
+ /** {@inheritDoc} */
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return getBinder();
+ }
+
+ /**
+ * Returns binder object which can be used across IPC methods.
+ */
+ public final IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * @return The attached {@link CallServiceAdapter} if the service is bound, null otherwise.
+ */
+ protected final CallServiceAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link CallService} has been attached to a
+ * {@link CallServiceAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this call service.
+ */
+ protected void onAdapterAttached(CallServiceAdapter adapter) {
+ }
+
+ /**
+ * Determines if the CallService can place the specified call. Response is sent via
+ * {@link CallServiceAdapter#setIsCompatibleWith}. When responding, the correct call ID must be
+ * specified. Only used in the context of outgoing calls and call switching (handoff).
+ *
+ * @param callInfo The details of the relevant call.
+ */
+ public abstract void isCompatibleWith(CallInfo callInfo);
+
+ /**
+ * Attempts to call the relevant party using the specified call's handle, be it a phone number,
+ * SIP address, or some other kind of user ID. Note that the set of handle types is
+ * dynamically extensible since call providers should be able to implement arbitrary
+ * handle-calling systems. See {@link #isCompatibleWith}. It is expected that the
+ * call service respond via {@link CallServiceAdapter#handleSuccessfulOutgoingCall(String)}
+ * if it can successfully make the call. Only used in the context of outgoing calls.
+ *
+ * @param callInfo The details of the relevant call.
+ */
+ public abstract void call(CallInfo callInfo);
+
+ /**
+ * Aborts the outgoing call attempt. Invoked in the unlikely event that Telecomm decides to
+ * abort an attempt to place a call. Only ever be invoked after {@link #call} invocations.
+ * After this is invoked, Telecomm does not expect any more updates about the call and will
+ * actively ignore any such update. This is different from {@link #disconnect} where Telecomm
+ * expects confirmation via CallServiceAdapter.markCallAsDisconnected.
+ *
+ * @param callId The identifier of the call to abort.
+ */
+ public abstract void abort(String callId);
+
+ /**
+ * Receives a new call ID to use with an incoming call. Invoked by Telecomm after it is notified
+ * that this call service has a pending incoming call, see
+ * {@link TelecommConstants#ACTION_INCOMING_CALL}. The call service must first give Telecomm
+ * additional information about the call through {@link CallServiceAdapter#notifyIncomingCall}.
+ * Following that, the call service can update the call at will using the specified call ID.
+ *
+ * If a {@link Bundle} was passed (via {@link TelecommConstants#EXTRA_INCOMING_CALL_EXTRAS}) in
+ * with the {@link TelecommConstants#ACTION_INCOMING_CALL} intent, <code>extras</code> will be
+ * populated with this {@link Bundle}. Otherwise, an empty Bundle will be returned.
+ *
+ * @param callId The ID of the call.
+ * @param extras The optional extras which were passed in with the intent, or an empty Bundle.
+ */
+ public abstract void setIncomingCallId(String callId, Bundle extras);
+
+ /**
+ * Answers a ringing call identified by callId. Telecomm invokes this method as a result of the
+ * user hitting the "answer" button in the incoming call screen.
+ *
+ * @param callId The ID of the call.
+ */
+ public abstract void answer(String callId);
+
+ /**
+ * Rejects a ringing call identified by callId. Telecomm invokes this method as a result of the
+ * user hitting the "reject" button in the incoming call screen.
+ *
+ * @param callId The ID of the call.
+ */
+ public abstract void reject(String callId);
+
+ /**
+ * Disconnects the specified call.
+ *
+ * @param callId The ID of the call to disconnect.
+ */
+ public abstract void disconnect(String callId);
+
+ /**
+ * Puts the specified call on hold.
+ *
+ * @param callId The ID of the call to put on hold.
+ */
+ public abstract void hold(String callId);
+
+ /**
+ * Removes the specified call from hold.
+ *
+ * @param callId The ID of the call to unhold.
+ */
+ public abstract void unhold(String callId);
+
+ /**
+ * Plays a dual-tone multi-frequency signaling (DTMF) tone in a call.
+ *
+ * @param callId The unique ID of the call in which the tone will be played.
+ * @param digit A character representing the DTMF digit for which to play the tone. This
+ * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+ */
+ public abstract void playDtmfTone(String callId, char digit);
+
+ /**
+ * Stops any dual-tone multi-frequency sinaling (DTMF) tone currently playing.
+ *
+ * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+ * currently playing, this method will do nothing.
+ *
+ * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+ */
+ public abstract void stopDtmfTone(String callId);
+
+ /**
+ * Called when the audio state changes.
+ *
+ * @param activeCallId The identifier of the call that was active during the state change.
+ * @param audioState The new {@link CallAudioState}.
+ */
+ public abstract void onAudioStateChanged(String activeCallId, CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceAdapter.java b/telecomm/java/android/telecomm/CallServiceAdapter.java
new file mode 100644
index 0000000..d5bb989
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceAdapter.java
@@ -0,0 +1,160 @@
+/*
+ * 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.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceAdapter;
+
+/**
+ * Provides methods for ICallService implementations to interact with the system phone app.
+ * TODO(santoscordon): Need final public-facing comments in this file.
+ */
+public final class CallServiceAdapter {
+ private final ICallServiceAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceAdapter(ICallServiceAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Receives confirmation of a call service's ability to place a call. This method is used in
+ * response to {@link CallService#isCompatibleWith}.
+ *
+ * @param callId The identifier of the call for which compatibility is being received. This ID
+ * should correspond to the ID given as part of the call information in
+ * {@link CallService#isCompatibleWith}.
+ * @param isCompatible True if the call service can place the call.
+ */
+ public void setIsCompatibleWith(String callId, boolean isCompatible) {
+ try {
+ mAdapter.setIsCompatibleWith(callId, isCompatible);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Provides Telecomm with the details of an incoming call. An invocation of this method must
+ * follow {@link CallService#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 callInfo The details of the relevant call.
+ */
+ public void notifyIncomingCall(CallInfo callInfo) {
+ try {
+ mAdapter.notifyIncomingCall(callInfo);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Tells Telecomm that an attempt to place the specified outgoing call succeeded.
+ * TODO(santoscordon): Consider adding a CallState parameter in case this outgoing call is
+ * somehow no longer in the DIALING state.
+ *
+ * @param callId The ID of the outgoing call.
+ */
+ public void handleSuccessfulOutgoingCall(String callId) {
+ try {
+ mAdapter.handleSuccessfulOutgoingCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Tells Telecomm that an attempt to place the specified outgoing call failed.
+ *
+ * @param callId The ID of the outgoing call.
+ * @param errorMessage The error associated with the failed call attempt.
+ */
+ public void handleFailedOutgoingCall(String callId, String errorMessage) {
+ try {
+ mAdapter.handleFailedOutgoingCall(callId, errorMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to active (e.g., an ongoing call where two parties can actively
+ * communicate).
+ *
+ * @param callId The unique ID of the call whose state is changing to active.
+ */
+ public void setActive(String callId) {
+ try {
+ mAdapter.setActive(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to ringing (e.g., an inbound ringing call).
+ *
+ * @param callId The unique ID of the call whose state is changing to ringing.
+ */
+ public void setRinging(String callId) {
+ try {
+ mAdapter.setRinging(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to dialing (e.g., dialing an outbound call).
+ *
+ * @param callId The unique ID of the call whose state is changing to dialing.
+ */
+ public void setDialing(String callId) {
+ try {
+ mAdapter.setDialing(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to disconnected.
+ *
+ * @param callId The unique ID of the call whose state is changing to disconnected.
+ * @param disconnectCause The reason for the disconnection, any of
+ * {@link android.telephony.DisconnectCause}.
+ * @param disconnectMessage Optional call-service-provided message about the disconnect.
+ */
+ public void setDisconnected(String callId, int disconnectCause, String disconnectMessage) {
+ try {
+ mAdapter.setDisconnected(callId, disconnectCause, disconnectMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets a call's state to be on hold.
+ *
+ * @param callId - The unique ID of the call whose state is changing to be on hold.
+ */
+ public void setOnHold(String callId) {
+ try {
+ mAdapter.setOnHold(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+
+}
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.aidl b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
new file mode 100644
index 0000000..f517c73
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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;
+
+parcelable CallServiceDescriptor;
diff --git a/telecomm/java/android/telecomm/CallServiceDescriptor.java b/telecomm/java/android/telecomm/CallServiceDescriptor.java
new file mode 100644
index 0000000..dec3791
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceDescriptor.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 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.content.ComponentName;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.UUID;
+
+/**
+ * An immutable object containing information about a given {@link CallService}. Instances are
+ * created using the enclosed {@link Builder}.
+ */
+public final class CallServiceDescriptor implements Parcelable {
+ private static final String TAG = CallServiceDescriptor.class.getSimpleName();
+
+ /**
+ * A placeholder value indicating an invalid network type.
+ * @hide
+ */
+ private static final int FLAG_INVALID = 0;
+
+ /**
+ * Indicates that the device must be connected to a Wi-Fi network in order for the backing
+ * {@link CallService} to be used.
+ */
+ public static final int FLAG_WIFI = 0x01;
+
+ /**
+ * Indicates that the device must be connected to a cellular PSTN network in order for the
+ * backing {@link CallService} to be used.
+ */
+ public static final int FLAG_PSTN = 0x02;
+
+ /**
+ * Indicates that the device must be connected to a cellular data network in order for the
+ * backing {@link CallService} to be used.
+ */
+ public static final int FLAG_MOBILE = 0x04;
+
+ /**
+ * Represents all of the defined FLAG_ constants so validity can be easily checked.
+ * @hide
+ */
+ public static final int FLAG_ALL = FLAG_WIFI | FLAG_PSTN | FLAG_MOBILE;
+
+ /**
+ * A unique ID used to identify a given instance.
+ */
+ private final String mCallServiceId;
+
+ /**
+ * The {@link ComponentName} of the {@link CallService} implementation which this is describing.
+ */
+ private final ComponentName mComponentName;
+
+ /**
+ * The type of connection that the {@link CallService} requires; will be one of the FLAG_*
+ * constants defined in this class.
+ */
+ private final int mNetworkType;
+
+ private CallServiceDescriptor(
+ String callServiceId,
+ ComponentName componentName,
+ int networkType) {
+
+ mCallServiceId = callServiceId;
+ mComponentName = componentName;
+ mNetworkType = networkType;
+ }
+
+ /**
+ * @return The ID used to identify this {@link CallService}.
+ */
+ public String getCallServiceId() {
+ return mCallServiceId;
+ }
+
+ /**
+ * @return The {@link ComponentName} of the {@link CallService}.
+ */
+ public ComponentName getServiceComponent() {
+ return mComponentName;
+ }
+
+ /**
+ * @return The network type required by the {@link CallService} to place a call.
+ */
+ public int getNetworkType() {
+ return mNetworkType;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof CallServiceDescriptor)) {
+ return false;
+ }
+ CallServiceDescriptor descriptor = (CallServiceDescriptor) obj;
+ return mCallServiceId.equals(descriptor.mCallServiceId) &&
+ mComponentName.equals(descriptor.mComponentName) &&
+ mNetworkType == descriptor.mNetworkType;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US, "[%s, component: %s]",
+ CallServiceDescriptor.class.getSimpleName(),
+ mComponentName == null ? "null" : mComponentName.flattenToShortString());
+ }
+
+ /**
+ * @param context {@link Context} to use for the construction of the {@link Builder}.
+ * @return A new {@link Builder} instance.
+ */
+ public static Builder newBuilder(Context context) {
+ return new Builder(context);
+ }
+
+ /**
+ * Creates {@link CallServiceDescriptor} instances. Builders should be created with the
+ * {@link CallServiceDescriptor#newBuilder(Context)} method.
+ */
+ public static class Builder {
+ /** The {@link Context} to use to verify {@link ComponentName} ownership. */
+ private Context mContext;
+
+ /** The {@link ComponentName} pointing to the backing {@link CallService}. */
+ private ComponentName mComponentName;
+
+ /** The required network type that the {@link CallService} needs. */
+ private int mNetworkType = FLAG_INVALID;
+
+ private Builder(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Set which {@link CallService} this {@link CallServiceDescriptor} is describing.
+ *
+ * @param callServiceClass The {@link CallService} class
+ * @return This {@link Builder} for method chaining.
+ */
+ public Builder setCallService(Class<? extends CallService> callServiceClass) {
+ mComponentName = new ComponentName(mContext, callServiceClass);
+ return this;
+ }
+
+ /**
+ * Which network type the backing {@link CallService} requires. This must be one of the
+ * {@link CallServiceDescriptor}.TYPE_* fields.
+ *
+ * @param networkType Which network type the backing {@link CallService} requires.
+ * @return This {@link Builder} for method chaining.
+ */
+ public Builder setNetworkType(int networkType) {
+ mNetworkType = networkType;
+ return this;
+ }
+
+ /**
+ * @return A constructed {@link CallServiceDescriptor} object.
+ */
+ public CallServiceDescriptor build() {
+ // STOPSHIP: Verify validity of ComponentName (permissions, intents, etc)
+
+ // Make sure that they passed in a valid network flag combination
+ if (mNetworkType == FLAG_INVALID || ((mNetworkType & FLAG_ALL) == 0)) {
+
+ Log.wtf(TAG, "Invalid network type for " + mComponentName);
+ // Revert them back to TYPE_INVALID so it won't be considered.
+ mNetworkType = FLAG_INVALID;
+ }
+
+ // TODO: Should we use a sha1 of the ComponentName? Would prevent duplicates.
+ return new CallServiceDescriptor(
+ UUID.randomUUID().toString(), mComponentName, mNetworkType);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mCallServiceId);
+ dest.writeParcelable(mComponentName, 0);
+ dest.writeInt(mNetworkType);
+ }
+
+ public static final Creator<CallServiceDescriptor> CREATOR =
+ new Creator<CallServiceDescriptor>() {
+ @Override
+ public CallServiceDescriptor createFromParcel(Parcel source) {
+ String id = source.readString();
+ ComponentName componentName = source.readParcelable(
+ CallServiceDescriptor.class.getClassLoader());
+ int networkType = source.readInt();
+
+ return new CallServiceDescriptor(id, componentName, networkType);
+ }
+
+ @Override
+ public CallServiceDescriptor[] newArray(int size) {
+ return new CallServiceDescriptor[size];
+ }
+ };
+}
diff --git a/telecomm/java/android/telecomm/CallServiceLookupResponse.java b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
new file mode 100644
index 0000000..dd35a24
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceLookupResponse.java
@@ -0,0 +1,51 @@
+/*
+ * 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.RemoteException;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+
+import java.util.List;
+
+/**
+ * Used by {@link CallServiceProvider} to return a list of {@link CallServiceDescriptor}s.
+ */
+public final class CallServiceLookupResponse {
+ private final ICallServiceLookupResponse mResponse;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceLookupResponse(ICallServiceLookupResponse response) {
+ mResponse = response;
+ }
+
+ /**
+ * Passes the sorted list of preferred {@link CallServiceDescriptor}s back to Telecomm. Used
+ * in the context of attempting to place a pending outgoing call.
+ *
+ * @param callServiceDescriptors The set of call-service descriptors from
+ * {@link CallServiceProvider}.
+ */
+ public void setCallServiceDescriptors(List<CallServiceDescriptor> callServiceDescriptors) {
+ try {
+ mResponse.setCallServiceDescriptors(callServiceDescriptors);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallServiceProvider.java b/telecomm/java/android/telecomm/CallServiceProvider.java
new file mode 100644
index 0000000..c50334a
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceProvider.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 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.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.android.internal.telecomm.ICallServiceLookupResponse;
+import com.android.internal.telecomm.ICallServiceProvider;
+
+/**
+ * Base implementation of a call service provider which extends {@link Service}. This class
+ * should be extended by an app that wants to supply phone calls to be handled and managed by
+ * the device's in-call interface. All method-calls from the framework to the call service provider
+ * are passed through to the main thread for before executing the overriden methods of
+ * CallServiceProvider.
+ *
+ * TODO(santoscordon): Improve paragraph above once the final design is in place. Needs more
+ * about how this can be used.
+ */
+public abstract class CallServiceProvider extends Service {
+
+ /**
+ * Default Handler used to consolidate binder method calls onto a single thread.
+ */
+ private final class CallServiceProviderMessageHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_LOOKUP_CALL_SERVICES:
+ CallServiceLookupResponse response =
+ new CallServiceLookupResponse((ICallServiceLookupResponse) msg.obj);
+ lookupCallServices(response);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Default ICallServiceProvider implementation provided to CallsManager via {@link #onBind}.
+ */
+ private final class CallServiceProviderWrapper extends ICallServiceProvider.Stub {
+ /** {@inheritDoc} */
+ @Override
+ public void lookupCallServices(ICallServiceLookupResponse callServiceLookupResponse) {
+ Message message = mMessageHandler.obtainMessage(
+ MSG_LOOKUP_CALL_SERVICES, callServiceLookupResponse);
+ message.sendToTarget();
+ }
+ }
+
+ // Only used internally by this class.
+ // Binder method calls on this service can occur on multiple threads. These messages are used
+ // in conjunction with {@link #mMessageHandler} to ensure that all callbacks are handled on a
+ // single thread. Keeping it on a single thread allows CallService implementations to avoid
+ // needing multi-threaded code in their own callback routines.
+ private static final int MSG_LOOKUP_CALL_SERVICES = 1;
+
+ /**
+ * Message handler for consolidating binder callbacks onto a single thread.
+ * See {@link CallServiceProviderMessageHandler}.
+ */
+ private final CallServiceProviderMessageHandler mMessageHandler;
+
+ /**
+ * Default binder implementation of {@link ICallServiceProvider} interface.
+ */
+ private final CallServiceProviderWrapper mBinder;
+
+ /**
+ * Protected constructor called only by subclasses creates the binder interface and
+ * single-threaded message handler.
+ */
+ protected CallServiceProvider() {
+ mMessageHandler = new CallServiceProviderMessageHandler();
+ mBinder = new CallServiceProviderWrapper();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Initiates the process to retrieve the list of {@link CallServiceDescriptor}s implemented by
+ * this provider.
+ *
+ * @param response The response object through which the list of call services is sent.
+ */
+ public abstract void lookupCallServices(CallServiceLookupResponse response);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelector.java b/telecomm/java/android/telecomm/CallServiceSelector.java
new file mode 100644
index 0000000..c9c6ff6
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelector.java
@@ -0,0 +1,152 @@
+/*
+ * 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.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.ICallServiceSelector;
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Allows for the organization of {@link CallService}s for outbound calls. Given a call and list of
+ * {@link CallService} IDs, order the list in terms of priority and return it using
+ * {@link #select(CallInfo, List)}.
+ */
+public abstract class CallServiceSelector extends Service {
+ private static final int MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER = 0;
+ private static final int MSG_SELECT = 1;
+
+ private final HashMap<String, CallInfo> mCalls = new HashMap<String, CallInfo>();
+
+ /** Handler to move client-bound method calls to the main thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER:
+ mAdapter = new CallServiceSelectorAdapter(
+ (ICallServiceSelectorAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_SELECT:
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ select((CallInfo) args.arg1, (List<CallServiceDescriptor>) args.arg2);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ }
+ };
+
+ /** Manages the binder calls so that the implementor does not need to deal with it. */
+ private final class CallServiceSelectorBinder extends ICallServiceSelector.Stub {
+ @Override
+ public void setCallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+ mHandler.obtainMessage(MSG_SET_CALL_SERVICE_SELECTOR_ADAPTER, adapter)
+ .sendToTarget();
+ }
+
+ @Override
+ public void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callInfo;
+ args.arg2 = descriptors;
+ mHandler.obtainMessage(MSG_SELECT, args).sendToTarget();
+ }
+
+ @Override
+ public void onCallUpdated(CallInfo callInfo) {
+ mCalls.put(callInfo.getId(), callInfo);
+ }
+
+ @Override
+ public void onCallRemoved(String callId) {
+ mCalls.remove(callId);
+ }
+ }
+
+ private final CallServiceSelectorBinder mBinder;
+
+ private CallServiceSelectorAdapter mAdapter = null;
+
+ protected CallServiceSelector() {
+ mBinder = new CallServiceSelectorBinder();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * Returns a list of all calls managed by this selector.
+ */
+ protected final Collection<CallInfo> getCalls() {
+ return Collections.unmodifiableCollection(mCalls.values());
+ }
+
+ /**
+ * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+ */
+ protected final CallServiceSelectorAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Cancel the outgoing call. Any subsequent calls to {@link #select(CallInfo, List)} will be
+ * ignored.
+ *
+ * @param callInfo The call to canceled.
+ */
+ protected final void cancelOutgoingCall(CallInfo callInfo) {
+ getAdapter().cancelOutgoingCall(callInfo.getId());
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link CallServiceSelector} has been attached
+ * to a {@link CallServiceSelectorAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this call service selector.
+ */
+ protected void onAdapterAttached(CallServiceSelectorAdapter adapter) {
+ }
+
+ /**
+ * Given a list of {@link CallServiceDescriptor}s, order them into a prioritized list and return
+ * them through
+ * {@link CallServiceSelectorAdapter#setSelectedCallServices(String,List)}.
+ *
+ * @param callInfo The call being placed using the {@link CallService}s.
+ * @param descriptors The descriptors of the available {@link CallService}s with which to place
+ * the call.
+ */
+ protected abstract void select(CallInfo callInfo, List<CallServiceDescriptor> descriptors);
+}
diff --git a/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
new file mode 100644
index 0000000..4d2e8aa
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallServiceSelectorAdapter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.os.RemoteException;
+import android.telecomm.CallServiceDescriptor;
+
+import com.android.internal.telecomm.ICallServiceSelectorAdapter;
+
+import java.util.List;
+
+/**
+ * Provides methods for ICallServiceSelector implementations to interact with Telecomm.
+ */
+public final class CallServiceSelectorAdapter {
+ private final ICallServiceSelectorAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public CallServiceSelectorAdapter(ICallServiceSelectorAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Records the sorted set of call services that are preferred by the corresponding
+ * call-service selector.
+ *
+ * @param callId The ID of the call to complete.
+ * @param selectedCallServiceDescriptors The prioritized list of preferred call-service
+ * descriptors to use for completing the call.
+ */
+ public void setSelectedCallServices(
+ String callId,
+ List<CallServiceDescriptor> selectedCallServiceDescriptors) {
+ try {
+ mAdapter.setSelectedCallServices(callId, selectedCallServiceDescriptors);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Cancels the specified outgoing call.
+ *
+ * @param callId The ID of the call to cancel.
+ */
+ public void cancelOutgoingCall(String callId) {
+ try {
+ mAdapter.cancelOutgoingCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Associates handoff information with an ongoing call. Calls can switch from one call service
+ * to another. Setting handle to a non-null value marks the call as switchable.
+ *
+ * @param callId The ID of the call to set handoff information for.
+ * @param handle The handle used to place the call when switching.
+ * @param extras Optional extra that's attached to the call.
+ */
+ public void setHandoffInfo(String callId, Uri handle, Bundle extras) {
+ try {
+ mAdapter.setHandoffInfo(callId, handle, extras);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/CallState.java b/telecomm/java/android/telecomm/CallState.java
new file mode 100644
index 0000000..152c202
--- /dev/null
+++ b/telecomm/java/android/telecomm/CallState.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 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;
+
+/**
+ * Defines call-state constants of the different states in which a call can exist. Although states
+ * have the notion of normal transitions, due to the volatile nature of telephony systems, code
+ * that uses these states should be resilient to unexpected state changes outside of what is
+ * considered traditional.
+ */
+public enum CallState {
+ /**
+ * Indicates that a call is new and not connected. This is used as the default state internally
+ * within Telecomm and should not be used between Telecomm and call services. Call services are
+ * not expected to ever interact with NEW calls, but {@link InCallService}s will see calls in
+ * this state.
+ */
+ NEW,
+
+ /**
+ * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+ * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+ * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+ * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+ */
+ DIALING,
+
+ /**
+ * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+ * or doing nothing with the call. This state is usually associated with some type of audible
+ * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+ * otherwise.
+ */
+ RINGING,
+
+ /**
+ * Indicates that the call is active but in a "post-dial" state where Telecomm is now sending
+ * some dual-tone multi-frequency signaling (DTMF) tones appended to the dialed number. Normal
+ * transitions are to {@link #POST_DIAL_WAIT} when the post-dial string requires user
+ * confirmation to proceed, {@link #ACTIVE} when the post-dial tones are completed, or
+ * {@link #DISCONNECTED}.
+ */
+ POST_DIAL,
+
+ /**
+ * Indicates that the call was in the {@link #POST_DIAL} state but is now waiting for user
+ * confirmation before the remaining digits can be sent. Normal transitions are to
+ * {@link #POST_DIAL} when the user asks Telecomm to proceed with the post-dial sequence.
+ */
+ POST_DIAL_WAIT,
+
+ /**
+ * Indicates that a call is currently connected to another party and a communication channel is
+ * open between them. The normal transition to this state is by the user answering a
+ * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+ */
+ ACTIVE,
+
+ /**
+ * Indicates that the call is currently on hold. In this state, the call is not terminated
+ * but no communication is allowed until the call is no longer on hold. The typical transition
+ * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+ * an action, such as clicking the hold button.
+ */
+ ON_HOLD,
+
+ /**
+ * Indicates that a call is currently disconnected. All states can transition to this state
+ * by the call service giving notice that the connection has been severed. When the user
+ * explicitly ends a call, it will not transition to this state until the call service confirms
+ * the disconnection or communication was lost to the call service currently responsible for
+ * this call (e.g., call service crashes).
+ */
+ DISCONNECTED,
+
+ /**
+ * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+ * time of writing) but cancelled before it was successfully connected.
+ * @hide
+ */
+ ABORTED;
+}
diff --git a/telecomm/java/android/telecomm/GatewayInfo.aidl b/telecomm/java/android/telecomm/GatewayInfo.aidl
new file mode 100644
index 0000000..d59e9b4
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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;
+
+parcelable GatewayInfo;
diff --git a/telecomm/java/android/telecomm/GatewayInfo.java b/telecomm/java/android/telecomm/GatewayInfo.java
new file mode 100644
index 0000000..b95e6b6
--- /dev/null
+++ b/telecomm/java/android/telecomm/GatewayInfo.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * When calls are made, they may contain gateway information for services which route phone calls
+ * through their own service/numbers. The data consists of a number to call and the package name of
+ * the service. This data is used in two ways:
+ * <ol>
+ * <li> Call the appropriate routing number
+ * <li> Display information about how the call is being routed to the user
+ * </ol>
+ */
+public class GatewayInfo implements Parcelable {
+
+ private final String mGatewayProviderPackageName;
+ private final Uri mGatewayHandle;
+ private final Uri mOriginalHandle;
+
+ /** @hide */
+ public GatewayInfo(String packageName, Uri gatewayUri, Uri originalHandle) {
+ mGatewayProviderPackageName = packageName;
+ mGatewayHandle = gatewayUri;
+ mOriginalHandle = originalHandle;
+ }
+
+ /**
+ * Package name of the gateway provider service. used to place the call with.
+ */
+ public String getGatewayProviderPackageName() {
+ return mGatewayProviderPackageName;
+ }
+
+ /**
+ * Gateway provider handle to use when actually placing the call.
+ */
+ public Uri getGatewayHandle() {
+ return mGatewayHandle;
+ }
+
+ /**
+ * The actual call handle that the user is trying to connect to via the gateway.
+ */
+ public Uri getOriginalHandle() {
+ return mOriginalHandle;
+ }
+
+ public boolean isEmpty() {
+ return TextUtils.isEmpty(mGatewayProviderPackageName) || mGatewayHandle == null;
+ }
+
+ /** Implement the Parcelable interface */
+ public static final Parcelable.Creator<GatewayInfo> CREATOR =
+ new Parcelable.Creator<GatewayInfo> () {
+
+ @Override
+ public GatewayInfo createFromParcel(Parcel source) {
+ String gatewayPackageName = source.readString();
+ Uri gatewayUri = Uri.CREATOR.createFromParcel(source);
+ Uri originalHandle = Uri.CREATOR.createFromParcel(source);
+ return new GatewayInfo(gatewayPackageName, gatewayUri, originalHandle);
+ }
+
+ @Override
+ public GatewayInfo[] newArray(int size) {
+ return new GatewayInfo[size];
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mGatewayProviderPackageName);
+ mGatewayHandle.writeToParcel(destination, 0);
+ mOriginalHandle.writeToParcel(destination, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallAdapter.java b/telecomm/java/android/telecomm/InCallAdapter.java
new file mode 100644
index 0000000..e41d3f6
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallAdapter.java
@@ -0,0 +1,199 @@
+/*
+ * 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.RemoteException;
+
+import com.android.internal.telecomm.IInCallAdapter;
+
+/**
+ * Receives commands from {@link InCallService} implementations which should be executed by
+ * Telecomm. When Telecomm binds to a {@link InCallService}, an instance of this class is given to
+ * the in-call service through which it can manipulate live (active, dialing, ringing) calls. When
+ * the in-call service is notified of new calls ({@link InCallService#addCall}), it can use the
+ * given call IDs to execute commands such as {@link #answerCall} for incoming calls or
+ * {@link #disconnectCall} for active calls the user would like to end. Some commands are only
+ * appropriate for calls in certain states; please consult each method for such limitations.
+ * TODO(santoscordon): Needs more/better comments once the API is finalized.
+ * TODO(santoscordon): Specify the adapter will stop functioning when there are no more calls.
+ */
+public final class InCallAdapter {
+ private final IInCallAdapter mAdapter;
+
+ /**
+ * {@hide}
+ */
+ public InCallAdapter(IInCallAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Instructs Telecomm to answer the specified call.
+ *
+ * @param callId The identifier of the call to answer.
+ */
+ public void answerCall(String callId) {
+ try {
+ mAdapter.answerCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to reject the specified call.
+ * TODO(santoscordon): Add reject-with-text-message parameter when that feature
+ * is ported over.
+ *
+ * @param callId The identifier of the call to reject.
+ */
+ public void rejectCall(String callId) {
+ try {
+ mAdapter.rejectCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to disconnect the specified call.
+ *
+ * @param callId The identifier of the call to disconnect.
+ */
+ public void disconnectCall(String callId) {
+ try {
+ mAdapter.disconnectCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to put the specified call on hold.
+ *
+ * @param callId The identifier of the call to put on hold.
+ */
+ public void holdCall(String callId) {
+ try {
+ mAdapter.holdCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to release the specified call from hold.
+ *
+ * @param callId The identifier of the call to release from hold.
+ */
+ public void unholdCall(String callId) {
+ try {
+ mAdapter.unholdCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Mute the microphone.
+ *
+ * @param shouldMute True if the microphone should be muted.
+ */
+ public void mute(boolean shouldMute) {
+ try {
+ mAdapter.mute(shouldMute);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sets the audio route (speaker, bluetooth, etc...). See {@link CallAudioState}.
+ *
+ * @param route The audio route to use.
+ */
+ public void setAudioRoute(int route) {
+ try {
+ mAdapter.setAudioRoute(route);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to play a dual-tone multi-frequency signaling (DTMF) tone in a call.
+ *
+ * Any other currently playing DTMF tone in the specified call is immediately stopped.
+ *
+ * @param callId The unique ID of the call in which the tone will be played.
+ * @param digit A character representing the DTMF digit for which to play the tone. This
+ * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
+ */
+ public void playDtmfTone(String callId, char digit) {
+ try {
+ mAdapter.playDtmfTone(callId, digit);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to stop any dual-tone multi-frequency signaling (DTMF) tone currently
+ * playing.
+ *
+ * DTMF tones are played by calling {@link #playDtmfTone(String,char)}. If no DTMF tone is
+ * currently playing, this method will do nothing.
+ *
+ * @param callId The unique ID of the call in which any currently playing tone will be stopped.
+ */
+ public void stopDtmfTone(String callId) {
+ try {
+ mAdapter.stopDtmfTone(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to continue playing a post-dial DTMF string.
+ *
+ * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
+ * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
+ * While these tones are playing, Telecomm will notify the {@link InCallService} that the call
+ * is in the {@link InCallService#setPostDial(String,String)} state.
+ *
+ * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_PAUSE} symbol, Telecomm
+ * will temporarily pause playing the tones for a pre-defined period of time.
+ *
+ * If the DTMF string contains a {@link TelecommConstants#DTMF_CHARACTER_WAIT} symbol, Telecomm
+ * will pause playing the tones and notify the {@link InCallService} that the call is in the
+ * {@link InCallService#setPostDialWait(String,String)} state. When the user decides to continue
+ * the postdial sequence, the {@link InCallService} should invoke the
+ * {@link #postDialContinue(String)} method.
+ *
+ * @param callId The unique ID of the call for which postdial string playing should continue.
+ */
+ public void postDialContinue(String callId) {
+ try {
+ mAdapter.postDialContinue(callId);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Instructs Telecomm to handoff the call to another call service.
+ *
+ * @param callId The identifier of the call to handoff.
+ */
+ public void handoffCall(String callId) {
+ try {
+ mAdapter.handoffCall(callId);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallCall.aidl b/telecomm/java/android/telecomm/InCallCall.aidl
new file mode 100644
index 0000000..be2cdf8
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 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;
+
+parcelable InCallCall;
diff --git a/telecomm/java/android/telecomm/InCallCall.java b/telecomm/java/android/telecomm/InCallCall.java
new file mode 100644
index 0000000..c3b2ae7
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallCall.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 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.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.DisconnectCause;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * Information about a call that is used between InCallService and Telecomm.
+ */
+public final class InCallCall implements Parcelable {
+ private final String mId;
+ private final CallState mState;
+ private final int mDisconnectCause;
+ private final int mCapabilities;
+ private final long mConnectTimeMillis;
+ private final Uri mHandle;
+ private final GatewayInfo mGatewayInfo;
+ private final CallServiceDescriptor mCurrentCallServiceDescriptor;
+ private final CallServiceDescriptor mHandoffCallServiceDescriptor;
+
+ /** @hide */
+ public InCallCall(
+ String id,
+ CallState state,
+ int disconnectCause,
+ int capabilities,
+ long connectTimeMillis,
+ Uri handle,
+ GatewayInfo gatewayInfo,
+ CallServiceDescriptor descriptor,
+ CallServiceDescriptor handoffDescriptor) {
+ mId = id;
+ mState = state;
+ mDisconnectCause = disconnectCause;
+ mCapabilities = capabilities;
+ mConnectTimeMillis = connectTimeMillis;
+ mHandle = handle;
+ mGatewayInfo = gatewayInfo;
+ mCurrentCallServiceDescriptor = descriptor;
+ mHandoffCallServiceDescriptor = handoffDescriptor;
+ }
+
+ /** The unique ID of the call. */
+ public String getId() {
+ return mId;
+ }
+
+ /** The current state of the call. */
+ public CallState getState() {
+ return mState;
+ }
+
+ /**
+ * Reason for disconnection, values are defined in {@link DisconnectCause}. Valid when call
+ * state is {@link CallState#DISCONNECTED}.
+ */
+ public int getDisconnectCause() {
+ return mDisconnectCause;
+ }
+
+ // Bit mask of actions a call supports, values are defined in {@link CallCapabilities}.
+ public int getCapabilities() {
+ return mCapabilities;
+ }
+
+ /** The time that the call switched to the active state. */
+ public long getConnectTimeMillis() {
+ return mConnectTimeMillis;
+ }
+
+ /** The endpoint to which the call is connected. */
+ public Uri getHandle() {
+ return mHandle;
+ }
+
+ /** Gateway information for the call. */
+ public GatewayInfo getGatewayInfo() {
+ return mGatewayInfo;
+ }
+
+ /** The descriptor for the call service currently routing this call. */
+ public CallServiceDescriptor getCurrentCallServiceDescriptor() {
+ return mCurrentCallServiceDescriptor;
+ }
+
+ /**
+ * The descriptor for the call service that this call is being switched to, null if handoff is
+ * not in progress.
+ */
+ public CallServiceDescriptor getHandoffCallServiceDescriptor() {
+ return mHandoffCallServiceDescriptor;
+ }
+
+ /** Responsible for creating InCallCall objects for deserialized Parcels. */
+ public static final Parcelable.Creator<InCallCall> CREATOR =
+ new Parcelable.Creator<InCallCall> () {
+ @Override
+ public InCallCall createFromParcel(Parcel source) {
+ String id = source.readString();
+ CallState state = CallState.valueOf(source.readString());
+ int disconnectCause = source.readInt();
+ int capabilities = source.readInt();
+ long connectTimeMillis = source.readLong();
+ ClassLoader classLoader = InCallCall.class.getClassLoader();
+ Uri handle = source.readParcelable(classLoader);
+ GatewayInfo gatewayInfo = source.readParcelable(classLoader);
+ CallServiceDescriptor descriptor = source.readParcelable(classLoader);
+ CallServiceDescriptor handoffDescriptor = source.readParcelable(classLoader);
+ return new InCallCall(id, state, disconnectCause, capabilities, connectTimeMillis,
+ handle, gatewayInfo, descriptor, handoffDescriptor);
+ }
+
+ @Override
+ public InCallCall[] newArray(int size) {
+ return new InCallCall[size];
+ }
+ };
+
+ /** {@inheritDoc} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Writes InCallCall object into a Parcel. */
+ @Override
+ public void writeToParcel(Parcel destination, int flags) {
+ destination.writeString(mId);
+ destination.writeString(mState.name());
+ destination.writeInt(mDisconnectCause);
+ destination.writeInt(mCapabilities);
+ destination.writeLong(mConnectTimeMillis);
+ destination.writeParcelable(mHandle, 0);
+ destination.writeParcelable(mGatewayInfo, 0);
+ destination.writeParcelable(mCurrentCallServiceDescriptor, 0);
+ destination.writeParcelable(mHandoffCallServiceDescriptor, 0);
+ }
+}
diff --git a/telecomm/java/android/telecomm/InCallService.java b/telecomm/java/android/telecomm/InCallService.java
new file mode 100644
index 0000000..63b2020
--- /dev/null
+++ b/telecomm/java/android/telecomm/InCallService.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2013 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.app.Service;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecomm.IInCallAdapter;
+import com.android.internal.telecomm.IInCallService;
+
+/**
+ * This service is implemented by any app that wishes to provide the user-interface for managing
+ * phone calls. Telecomm binds to this service while there exists a live (active or incoming)
+ * call, and uses it to notify the in-call app of any live and and recently disconnected calls.
+ * TODO(santoscordon): Needs more/better description of lifecycle once the interface is better
+ * defined.
+ * TODO(santoscordon): What happens if two or more apps on a given device implement this interface?
+ */
+public abstract class InCallService extends Service {
+ private static final int MSG_SET_IN_CALL_ADAPTER = 1;
+ private static final int MSG_ADD_CALL = 2;
+ private static final int MSG_UPDATE_CALL = 3;
+ private static final int MSG_SET_POST_DIAL = 4;
+ private static final int MSG_SET_POST_DIAL_WAIT = 5;
+ private static final int MSG_ON_AUDIO_STATE_CHANGED = 6;
+
+ /** Default Handler used to consolidate binder method calls onto a single thread. */
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_IN_CALL_ADAPTER:
+ mAdapter = new InCallAdapter((IInCallAdapter) msg.obj);
+ onAdapterAttached(mAdapter);
+ break;
+ case MSG_ADD_CALL:
+ addCall((InCallCall) msg.obj);
+ break;
+ case MSG_UPDATE_CALL:
+ updateCall((InCallCall) msg.obj);
+ break;
+ case MSG_SET_POST_DIAL: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String remaining = (String) args.arg2;
+ setPostDial(callId, remaining);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_POST_DIAL_WAIT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ String callId = (String) args.arg1;
+ String remaining = (String) args.arg2;
+ setPostDialWait(callId, remaining);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_ON_AUDIO_STATE_CHANGED:
+ onAudioStateChanged((CallAudioState) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ /** Manages the binder calls so that the implementor does not need to deal with it. */
+ private final class InCallServiceBinder extends IInCallService.Stub {
+ /** {@inheritDoc} */
+ @Override
+ public void setInCallAdapter(IInCallAdapter inCallAdapter) {
+ mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void addCall(InCallCall call) {
+ mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void updateCall(InCallCall call) {
+ mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget();
+ }
+
+ @Override
+ public void setPostDial(String callId, String remaining) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = remaining;
+ mHandler.obtainMessage(MSG_SET_POST_DIAL, args).sendToTarget();
+ }
+
+ @Override
+ public void setPostDialWait(String callId, String remaining) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = callId;
+ args.arg2 = remaining;
+ mHandler.obtainMessage(MSG_SET_POST_DIAL_WAIT, args).sendToTarget();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onAudioStateChanged(CallAudioState audioState) {
+ mHandler.obtainMessage(MSG_ON_AUDIO_STATE_CHANGED, audioState).sendToTarget();
+ }
+ }
+
+ private final InCallServiceBinder mBinder;
+
+ private InCallAdapter mAdapter;
+
+ protected InCallService() {
+ mBinder = new InCallServiceBinder();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ /**
+ * @return The attached {@link CallServiceSelectorAdapter} if attached, or null otherwise.
+ */
+ protected final InCallAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Lifecycle callback which is called when this {@link InCallService} has been attached
+ * to a {@link InCallAdapter}, indicating {@link #getAdapter()} is now safe to use.
+ *
+ * @param adapter The adapter now attached to this in-call service.
+ */
+ protected void onAdapterAttached(InCallAdapter adapter) {
+ }
+
+ /**
+ * Indicates to the in-call app that a new call has been created and an appropriate
+ * user-interface should be built and shown to notify the user.
+ *
+ * @param call Information about the new call.
+ */
+ protected abstract void addCall(InCallCall call);
+
+ /**
+ * Call when information about a call has changed.
+ *
+ * @param call Information about the new call.
+ */
+ protected abstract void updateCall(InCallCall call);
+
+ /**
+ * Indicates to the in-call app that the specified call is active but in a "post-dial" state
+ * where Telecomm is now sending some dual-tone multi-frequency signaling (DTMF) tones appended
+ * to the dialed number. Normal transitions are to {@link #setPostDialWait(String,String)} when
+ * the post-dial string requires user confirmation to proceed, and {@link CallState#ACTIVE} when
+ * the post-dial tones are completed.
+ *
+ * @param callId The identifier of the call changing state.
+ * @param remaining The remaining postdial string to be dialed.
+ */
+ protected abstract void setPostDial(String callId, String remaining);
+
+ /**
+ * Indicates to the in-call app that the specified call was in the
+ * {@link #setPostDial(String,String)} state but is now waiting for user confirmation before the
+ * remaining digits can be sent. Normal transitions are to {@link #setPostDial(String,String)}
+ * when the user asks Telecomm to proceed with the post-dial sequence and the in-call app
+ * informs Telecomm of this by invoking {@link InCallAdapter#postDialContinue(String)}.
+ *
+ * @param callId The identifier of the call changing state.
+ * @param remaining The remaining postdial string to be dialed.
+ */
+ protected abstract void setPostDialWait(String callId, String remaining);
+
+ /**
+ * Called when the audio state changes.
+ *
+ * @param audioState The new {@link CallAudioState}.
+ */
+ protected abstract void onAudioStateChanged(CallAudioState audioState);
+}
diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java
new file mode 100644
index 0000000..8300c92
--- /dev/null
+++ b/telecomm/java/android/telecomm/TelecommConstants.java
@@ -0,0 +1,97 @@
+/*
+ * 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.telephony.TelephonyManager;
+
+/**
+ * Defines constants for use with the Telecomm system.
+ */
+public final class TelecommConstants {
+ /**
+ * <p>Activity action: Starts the UI for handing an incoming call. This intent starts the
+ * in-call UI by notifying the Telecomm system that an incoming call exists for a specific call
+ * service (see {@link android.telecomm.CallService}). Telecomm reads the Intent extras to find
+ * and bind to the appropriate {@link android.telecomm.CallService} which Telecomm will
+ * ultimately use to control and get information about the call.</p>
+ *
+ * <p>Input: get*Extra field {@link #EXTRA_CALL_SERVICE_DESCRIPTOR} contains the component name
+ * of the {@link android.telecomm.CallService} that Telecomm should bind to. Telecomm will then
+ * ask the call service for more information about the call prior to showing any UI.
+ *
+ * TODO(santoscordon): Needs permissions.
+ * TODO(santoscordon): Consider moving this into a simple method call on a system service.
+ */
+ public static final String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
+
+ /**
+ * The service action used to bind to {@link CallServiceProvider} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE_PROVIDER = CallServiceProvider.class.getName();
+
+ /**
+ * The service action used to bind to {@link CallService} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE = CallService.class.getName();
+
+ /**
+ * The service action used to bind to {@link CallServiceSelector} implementations.
+ */
+ public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName();
+
+ /**
+ * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that
+ * describes the call service to use for the incoming call.
+ */
+ public static final String EXTRA_CALL_SERVICE_DESCRIPTOR =
+ "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
+
+ /**
+ * Optional extra for {@link #ACTION_INCOMING_CALL} containing a {@link Bundle} which contains
+ * metadata about the call. This {@link Bundle} will be returned to the {@link CallService} as
+ * part of {@link CallService#setIncomingCallId(String,Bundle)}.
+ */
+ public static final String EXTRA_INCOMING_CALL_EXTRAS =
+ "android.intent.extra.INCOMING_CALL_EXTRAS";
+
+ /**
+ * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+ * disconnect code.
+ */
+ public static final String EXTRA_CALL_DISCONNECT_CAUSE =
+ "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
+
+ /**
+ * Optional extra for {@link TelephonyManager#ACTION_PHONE_STATE_CHANGED} containing the
+ * disconnect message.
+ */
+ public static final String EXTRA_CALL_DISCONNECT_MESSAGE =
+ "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
+
+ /**
+ * The dual tone multi-frequency signaling character sent to indicate the dialing system should
+ * pause for a predefined period.
+ */
+ public static final char DTMF_CHARACTER_PAUSE = ',';
+
+ /**
+ * The dual-tone multi-frequency signaling character sent to indicate the dialing system should
+ * wait for user confirmation before proceeding.
+ */
+ public static final char DTMF_CHARACTER_WAIT = ';';
+}