diff options
| author | 2017-01-19 18:29:54 +0000 | |
|---|---|---|
| committer | 2017-01-19 18:29:54 +0000 | |
| commit | 2155be0218cf9676ac531f0524a705f38941cc15 (patch) | |
| tree | 85e651b5d5d87e268a94eeef66f94d92d30f3d24 | |
| parent | 6b662722f01beac91c74862b521c9d5d5bfc5092 (diff) | |
| parent | 3a7253a09d1223796bd41b2a6308ace92c504ca2 (diff) | |
Merge "Adding self-managed connection service APIs."
am: 3a7253a09d
Change-Id: I5d7aa094d71e40bc2ce8e6d051c757a82d9c6083
| -rw-r--r-- | api/current.txt | 9 | ||||
| -rw-r--r-- | api/system-current.txt | 9 | ||||
| -rw-r--r-- | api/test-current.txt | 9 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 10 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 8 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/Connection.java | 49 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/ConnectionRequest.java | 27 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/ConnectionService.java | 82 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/ConnectionServiceAdapter.java | 17 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/ConnectionServiceAdapterServant.java | 22 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/PhoneAccount.java | 26 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/RemoteConnectionService.java | 9 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/TelecomManager.java | 105 | ||||
| -rw-r--r-- | telecomm/java/android/telecom/package-info.java | 59 | ||||
| -rw-r--r-- | telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl | 2 | ||||
| -rw-r--r-- | telecomm/java/com/android/internal/telecom/ITelecomService.aidl | 10 |
16 files changed, 425 insertions, 28 deletions
diff --git a/api/current.txt b/api/current.txt index 783944c11d52..64469f168b90 100644 --- a/api/current.txt +++ b/api/current.txt @@ -80,6 +80,7 @@ package android { field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; + field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS"; @@ -36452,6 +36453,7 @@ package android.telecom { method public void onReject(); method public void onReject(java.lang.String); method public void onSeparate(); + method public void onShowIncomingCallUi(); method public void onStateChanged(int); method public void onStopDtmfTone(); method public void onUnhold(); @@ -36463,6 +36465,7 @@ package android.telecom { method public final void setActive(); method public final void setAddress(android.net.Uri, int); method public final void setAudioModeIsVoip(boolean); + method public final void setAudioRoute(int); method public final void setCallerDisplayName(java.lang.String, int); method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>); @@ -36511,6 +36514,7 @@ package android.telecom { field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER"; field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20 field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10 + field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_DIALING = 3; // 0x3 field public static final int STATE_DISCONNECTED = 6; // 0x6 @@ -36577,7 +36581,9 @@ package android.telecom { method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest); method public void onRemoteConferenceAdded(android.telecom.RemoteConference); method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection); field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService"; @@ -36690,6 +36696,7 @@ package android.telecom { field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40 field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 + field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 @@ -36871,6 +36878,8 @@ package android.telecom { method public boolean handleMmi(java.lang.String); method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); method public boolean isInCall(); + method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); + method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); diff --git a/api/system-current.txt b/api/system-current.txt index 5b5e70126b29..eb75f7161084 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -135,6 +135,7 @@ package android { field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES"; field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; + field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; @@ -39422,6 +39423,7 @@ package android.telecom { method public void onReject(); method public void onReject(java.lang.String); method public void onSeparate(); + method public void onShowIncomingCallUi(); method public void onStateChanged(int); method public void onStopDtmfTone(); method public void onUnhold(); @@ -39433,6 +39435,7 @@ package android.telecom { method public final void setActive(); method public final void setAddress(android.net.Uri, int); method public final void setAudioModeIsVoip(boolean); + method public final void setAudioRoute(int); method public final void setCallerDisplayName(java.lang.String, int); method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>); @@ -39481,6 +39484,7 @@ package android.telecom { field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER"; field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20 field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10 + field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_DIALING = 3; // 0x3 field public static final int STATE_DISCONNECTED = 6; // 0x6 @@ -39547,7 +39551,9 @@ package android.telecom { method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest); method public void onRemoteConferenceAdded(android.telecom.RemoteConference); method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection); field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService"; @@ -39784,6 +39790,7 @@ package android.telecom { field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_MULTI_USER = 32; // 0x20 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 + field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 @@ -40022,6 +40029,8 @@ package android.telecom { method public boolean handleMmi(java.lang.String); method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); method public boolean isInCall(); + method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); + method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle); method public boolean isRinging(); method public boolean isTtySupported(); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); diff --git a/api/test-current.txt b/api/test-current.txt index 9b6795f3cfbf..a709b2294cd4 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -80,6 +80,7 @@ package android { field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES"; field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; + field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS"; @@ -36534,6 +36535,7 @@ package android.telecom { method public void onReject(); method public void onReject(java.lang.String); method public void onSeparate(); + method public void onShowIncomingCallUi(); method public void onStateChanged(int); method public void onStopDtmfTone(); method public void onUnhold(); @@ -36545,6 +36547,7 @@ package android.telecom { method public final void setActive(); method public final void setAddress(android.net.Uri, int); method public final void setAudioModeIsVoip(boolean); + method public final void setAudioRoute(int); method public final void setCallerDisplayName(java.lang.String, int); method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>); @@ -36593,6 +36596,7 @@ package android.telecom { field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER"; field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20 field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10 + field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_DIALING = 3; // 0x3 field public static final int STATE_DISCONNECTED = 6; // 0x6 @@ -36659,7 +36663,9 @@ package android.telecom { method public final android.os.IBinder onBind(android.content.Intent); method public void onConference(android.telecom.Connection, android.telecom.Connection); method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateIncomingConnectionFailed(android.telecom.ConnectionRequest); method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onCreateOutgoingConnectionFailed(android.telecom.ConnectionRequest); method public void onRemoteConferenceAdded(android.telecom.RemoteConference); method public void onRemoteExistingConnectionAdded(android.telecom.RemoteConnection); field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService"; @@ -36772,6 +36778,7 @@ package android.telecom { field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40 field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 + field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800 field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8 @@ -36953,6 +36960,8 @@ package android.telecom { method public boolean handleMmi(java.lang.String); method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle); method public boolean isInCall(); + method public boolean isIncomingCallPermitted(android.telecom.PhoneAccountHandle); + method public boolean isOutgoingCallPermitted(android.telecom.PhoneAccountHandle); method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String); method public void placeCall(android.net.Uri, android.os.Bundle); method public void registerPhoneAccount(android.telecom.PhoneAccount); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 048214a1dc0f..790b0f6e817f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -778,6 +778,16 @@ android:description="@string/permdesc_callPhone" android:protectionLevel="dangerous" /> + <!-- Allows an application to manage its own calls, but rely on the system to route focus to the + currently active call. + <p>Protection level: dangerous + --> + <permission android:name="android.permission.MANAGE_OWN_CALLS" + android:permissionGroup="android.permission-group.PHONE" + android:label="@string/permlab_manageOwnCalls" + android:description="@string/permdesc_manageOwnCalls" + android:protectionLevel="dangerous" /> + <!-- Allows an application to access the IMS call service: making and modifying a call <p>Protection level: signature|privileged diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 38137f8c95a4..426d2ebecab0 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1056,6 +1056,14 @@ phone number and device IDs, whether a call is active, and the remote number connected by a call.</string> + <!-- Title of an application permission. When granted the user is giving access to a third + party app to route its calls through the system. --> + <string name="permlab_manageOwnCalls">route calls through the system</string> + <!-- Description of an application permission. When granted the user is giving access to a + third party app to route its calls through the system. --> + <string name="permdesc_manageOwnCalls">Allows the app to route its calls through the system in + order to improve the calling experience.</string> + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 15960c8af82d..560b616f6ca6 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -376,8 +376,16 @@ public abstract class Connection extends Conferenceable { */ public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6; + /** + * Set by the framework to indicate that the {@link Connection} originated from a self-managed + * {@link ConnectionService}. + * <p> + * See {@link PhoneAccount#CAPABILITY_SELF_MANAGED}. + */ + public static final int PROPERTY_SELF_MANAGED = 1<<7; + //********************************************************************************************** - // Next PROPERTY value: 1<<7 + // Next PROPERTY value: 1<<8 //********************************************************************************************** /** @@ -655,6 +663,10 @@ public abstract class Connection extends Conferenceable { builder.append("Properties:"); } + if (can(properties, PROPERTY_SELF_MANAGED)) { + builder.append(isLong ? " PROPERTY_SELF_MANAGED" : " self_mng"); + } + if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) { builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm"); } @@ -715,6 +727,7 @@ public abstract class Connection extends Conferenceable { public void onConnectionEvent(Connection c, String event, Bundle extras) {} /** @hide */ public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {} + public void onAudioRouteChanged(Connection c, int audioRoute) {} } /** @@ -2243,6 +2256,25 @@ public abstract class Connection extends Conferenceable { } /** + * Sets the audio route (speaker, bluetooth, etc...). When this request is honored, there will + * be change to the {@link #getCallAudioState()}. + * <p> + * Used by self-managed {@link ConnectionService}s which wish to change the audio route for a + * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.) + * <p> + * See also {@link InCallService#setAudioRoute(int)}. + * + * @param route The audio route to use (one of {@link CallAudioState#ROUTE_BLUETOOTH}, + * {@link CallAudioState#ROUTE_EARPIECE}, {@link CallAudioState#ROUTE_SPEAKER}, or + * {@link CallAudioState#ROUTE_WIRED_HEADSET}). + */ + public final void setAudioRoute(int route) { + for (Listener l : mListeners) { + l.onAudioRouteChanged(this, route); + } + } + + /** * Notifies this Connection that the {@link #getAudioState()} property has a new value. * * @param state The new connection audio state. @@ -2397,6 +2429,21 @@ public abstract class Connection extends Conferenceable { */ public void onExtrasChanged(Bundle extras) {} + /** + * Notifies this {@link Connection} that its {@link ConnectionService} is responsible for + * displaying its incoming call user interface for the {@link Connection}. + * <p> + * Will only be called for incoming calls added via a self-managed {@link ConnectionService} + * (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}), where the {@link ConnectionService} + * should show its own incoming call user interface. + * <p> + * Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a + * regular {@link ConnectionService}, the Telecom framework will display its own incoming call + * user interface to allow the user to choose whether to answer the new incoming call and + * disconnect other ongoing calls, or to reject the new incoming call. + */ + public void onShowIncomingCallUi() {} + static String toLogSafePhoneNumber(String number) { // For unknown number, log empty string. if (number == null) { diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java index aba38fe8a376..23434624bf87 100644 --- a/telecomm/java/android/telecom/ConnectionRequest.java +++ b/telecomm/java/android/telecom/ConnectionRequest.java @@ -33,6 +33,7 @@ public final class ConnectionRequest implements Parcelable { private final Bundle mExtras; private final int mVideoState; private final String mTelecomCallId; + private final boolean mShouldShowIncomingCallUi; /** * @param accountHandle The accountHandle which should be used to place the call. @@ -43,7 +44,7 @@ public final class ConnectionRequest implements Parcelable { PhoneAccountHandle accountHandle, Uri handle, Bundle extras) { - this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null); + this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false); } /** @@ -57,7 +58,7 @@ public final class ConnectionRequest implements Parcelable { Uri handle, Bundle extras, int videoState) { - this(accountHandle, handle, extras, videoState, null); + this(accountHandle, handle, extras, videoState, null, false); } /** @@ -66,6 +67,10 @@ public final class ConnectionRequest implements Parcelable { * @param extras Application-specific extra data. * @param videoState Determines the video state for the connection. * @param telecomCallId The telecom call ID. + * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be + * {@code true} if the {@link ConnectionService} should show its + * own incoming call UI for an incoming call. When + * {@code false}, Telecom shows the incoming call UI. * @hide */ public ConnectionRequest( @@ -73,12 +78,14 @@ public final class ConnectionRequest implements Parcelable { Uri handle, Bundle extras, int videoState, - String telecomCallId) { + String telecomCallId, + boolean shouldShowIncomingCallUi) { mAccountHandle = accountHandle; mAddress = handle; mExtras = extras; mVideoState = videoState; mTelecomCallId = telecomCallId; + mShouldShowIncomingCallUi = shouldShowIncomingCallUi; } private ConnectionRequest(Parcel in) { @@ -87,6 +94,7 @@ public final class ConnectionRequest implements Parcelable { mExtras = in.readParcelable(getClass().getClassLoader()); mVideoState = in.readInt(); mTelecomCallId = in.readString(); + mShouldShowIncomingCallUi = in.readInt() == 1; } /** @@ -129,6 +137,18 @@ public final class ConnectionRequest implements Parcelable { return mTelecomCallId; } + /** + * For a self-managed {@link ConnectionService}, indicates for an incoming call whether the + * {@link ConnectionService} should show its own incoming call UI for an incoming call. + * + * @return {@code true} if the {@link ConnectionService} should show its own incoming call UI. + * When {@code false}, Telecom shows the incoming call UI for the call. + * @hide + */ + public boolean shouldShowIncomingCallUi() { + return mShouldShowIncomingCallUi; + } + @Override public String toString() { return String.format("ConnectionRequest %s %s", @@ -165,5 +185,6 @@ public final class ConnectionRequest implements Parcelable { destination.writeParcelable(mExtras, 0); destination.writeInt(mVideoState); destination.writeString(mTelecomCallId); + destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0); } } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index b042d88528a5..ce3144bbeacf 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -42,10 +42,15 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** - * An abstract service that should be implemented by any apps which can make phone calls (VoIP or - * otherwise) and want those calls to be integrated into the built-in phone app. - * Once implemented, the {@code ConnectionService} needs two additional steps before it will be - * integrated into the phone app: + * An abstract service that should be implemented by any apps which either: + * <ol> + * <li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the + * built-in phone app. Referred to as a <b>system managed</b> {@link ConnectionService}.</li> + * <li>Are a standalone calling app and don't want their calls to be integrated into the + * built-in phone app. Referred to as a <b>self managed</b> {@link ConnectionService}.</li> + * </ol> + * Once implemented, the {@link ConnectionService} needs to take the following steps so that Telecom + * will bind to it: * <p> * 1. <i>Registration in AndroidManifest.xml</i> * <br/> @@ -63,16 +68,20 @@ import java.util.concurrent.ConcurrentHashMap; * <br/> * See {@link PhoneAccount} and {@link TelecomManager#registerPhoneAccount} for more information. * <p> - * Once registered and enabled by the user in the phone app settings, telecom will bind to a - * {@code ConnectionService} implementation when it wants that {@code ConnectionService} to place - * a call or the service has indicated that is has an incoming call through - * {@link TelecomManager#addNewIncomingCall}. The {@code ConnectionService} can then expect a call - * to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection} wherein it - * should provide a new instance of a {@link Connection} object. It is through this - * {@link Connection} object that telecom receives state updates and the {@code ConnectionService} + * System managed {@link ConnectionService}s must be enabled by the user in the phone app settings + * before Telecom will bind to them. Self-manged {@link ConnectionService}s must be granted the + * appropriate permission before Telecom will bind to them. + * <p> + * Once registered and enabled by the user in the phone app settings or granted permission, telecom + * will bind to a {@link ConnectionService} implementation when it wants that + * {@link ConnectionService} to place a call or the service has indicated that is has an incoming + * call through {@link TelecomManager#addNewIncomingCall}. The {@link ConnectionService} can then + * expect a call to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection} + * wherein it should provide a new instance of a {@link Connection} object. It is through this + * {@link Connection} object that telecom receives state updates and the {@link ConnectionService} * receives call-commands such as answer, reject, hold and disconnect. * <p> - * When there are no more live calls, telecom will unbind from the {@code ConnectionService}. + * When there are no more live calls, telecom will unbind from the {@link ConnectionService}. */ public abstract class ConnectionService extends Service { /** @@ -1054,6 +1063,7 @@ public abstract class ConnectionService extends Service { } } + @Override public void onExtrasRemoved(Connection c, List<String> keys) { String id = mIdByConnection.get(c); if (id != null) { @@ -1061,7 +1071,6 @@ public abstract class ConnectionService extends Service { } } - @Override public void onConnectionEvent(Connection connection, String event, Bundle extras) { String id = mIdByConnection.get(connection); @@ -1069,6 +1078,14 @@ public abstract class ConnectionService extends Service { mAdapter.onConnectionEvent(id, event, extras); } } + + @Override + public void onAudioRouteChanged(Connection c, int audioRoute) { + String id = mIdByConnection.get(c); + if (id != null) { + mAdapter.setAudioRoute(id, audioRoute); + } + } }; /** {@inheritDoc} */ @@ -1146,6 +1163,13 @@ public abstract class ConnectionService extends Service { connection.getDisconnectCause(), createIdList(connection.getConferenceables()), connection.getExtras())); + + if (isIncoming && request.shouldShowIncomingCallUi() && + (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) == + Connection.PROPERTY_SELF_MANAGED) { + // Tell ConnectionService to show its incoming call UX. + connection.onShowIncomingCallUi(); + } if (isUnknown) { triggerConferenceRecalculate(); } @@ -1587,6 +1611,38 @@ public abstract class ConnectionService extends Service { } /** + * Called by Telecom to inform the {@link ConnectionService} that its request to create a new + * incoming {@link Connection} was denied. + * <p> + * Used when a self-managed {@link ConnectionService} attempts to create a new incoming + * {@link Connection}, but Telecom has determined that the call cannot be allowed at this time. + * The {@link ConnectionService} is responsible for silently rejecting the new incoming + * {@link Connection}. + * <p> + * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information. + * + * @param request The incoming connection request. + */ + public void onCreateIncomingConnectionFailed(ConnectionRequest request) { + } + + /** + * Called by Telecom to inform the {@link ConnectionService} that its request to create a new + * outgoing {@link Connection} was denied. + * <p> + * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing + * {@link Connection}, but Telecom has determined that the call cannot be placed at this time. + * The {@link ConnectionService} is responisible for informing the user that the + * {@link Connection} cannot be made at this time. + * <p> + * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information. + * + * @param request The outgoing connection request. + */ + public void onCreateOutgoingConnectionFailed(ConnectionRequest request) { + } + + /** * Trigger recalculate functinality for conference calls. This is used when a Telephony * Connection is part of a conference controller but is not yet added to Connection * Service and hence cannot be added to the conference call. diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapter.java b/telecomm/java/android/telecom/ConnectionServiceAdapter.java index f3fada99c292..9542b73c68fb 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapter.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapter.java @@ -515,6 +515,23 @@ final class ConnectionServiceAdapter implements DeathRecipient { } /** + * Sets the audio route associated with a {@link Connection}. + * + * @param callId The unique ID of the call. + * @param audioRoute The new audio route (see {@code CallAudioState#ROUTE_*}). + */ + void setAudioRoute(String callId, int audioRoute) { + Log.v(this, "setAudioRoute: %s %s", callId, CallAudioState.audioRouteToString(audioRoute)); + for (IConnectionServiceAdapter adapter : mAdapters) { + try { + adapter.setAudioRoute(callId, audioRoute, Log.getExternalSession()); + } catch (RemoteException ignored) { + } + } + } + + + /** * Informs Telecom of a connection level event. * * @param callId The unique ID of the call. diff --git a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java index afe5e33bdaf2..cc437f9c7cd0 100644 --- a/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java +++ b/telecomm/java/android/telecom/ConnectionServiceAdapterServant.java @@ -67,6 +67,7 @@ final class ConnectionServiceAdapterServant { private static final int MSG_ON_CONNECTION_EVENT = 26; private static final int MSG_SET_CONNECTION_PROPERTIES = 27; private static final int MSG_SET_PULLING = 28; + private static final int MSG_SET_AUDIO_ROUTE = 29; private final IConnectionServiceAdapter mDelegate; @@ -289,6 +290,16 @@ final class ConnectionServiceAdapterServant { } break; } + case MSG_SET_AUDIO_ROUTE: { + SomeArgs args = (SomeArgs) msg.obj; + try { + mDelegate.setAudioRoute((String) args.arg1, args.argi1, + (Session.Info) args.arg2); + } finally { + args.recycle(); + } + break; + } } } }; @@ -507,6 +518,17 @@ final class ConnectionServiceAdapterServant { } @Override + public final void setAudioRoute(String connectionId, int audioRoute, + Session.Info sessionInfo) { + + SomeArgs args = SomeArgs.obtain(); + args.arg1 = connectionId; + args.argi1 = audioRoute; + args.arg2 = sessionInfo; + mHandler.obtainMessage(MSG_SET_AUDIO_ROUTE, args).sendToTarget(); + } + + @Override public final void onConnectionEvent(String connectionId, String event, Bundle extras, Session.Info sessionInfo) { SomeArgs args = SomeArgs.obtain(); diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index ca5448658b45..845a1033c123 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -189,6 +189,21 @@ public final class PhoneAccount implements Parcelable { public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400; /** + * Flag indicating that this {@link PhoneAccount} is responsible for managing its own + * {@link Connection}s. This type of {@link PhoneAccount} is ideal for use with standalone + * calling apps which do not wish to use the default phone app for {@link Connection} UX, + * but which want to leverage the call and audio routing capabilities of the Telecom framework. + * <p> + * When set, {@link Connection}s created by the self-managed {@link ConnectionService} will not + * be surfaced to implementations of the {@link InCallService} API. Thus it is the + * responsibility of a self-managed {@link ConnectionService} to provide a user interface for + * its {@link Connection}s. + * <p> + * Self-managed {@link Connection}s will, however, be displayed on connected Bluetooth devices. + */ + public static final int CAPABILITY_SELF_MANAGED = 0x800; + + /** * URI scheme for telephone number URIs. */ public static final String SCHEME_TEL = "tel"; @@ -692,6 +707,14 @@ public final class PhoneAccount implements Parcelable { mIsEnabled = isEnabled; } + /** + * @return {@code true} if the {@link PhoneAccount} is self-managed, {@code false} otherwise. + * @hide + */ + public boolean isSelfManaged() { + return (mCapabilities & CAPABILITY_SELF_MANAGED) == CAPABILITY_SELF_MANAGED; + } + // // Parcelable implementation // @@ -815,6 +838,9 @@ public final class PhoneAccount implements Parcelable { */ private String capabilitiesToString() { StringBuilder sb = new StringBuilder(); + if (hasCapabilities(CAPABILITY_SELF_MANAGED)) { + sb.append("SelfManaged "); + } if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) { sb.append("SuppVideo "); } diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java index 7321a274021c..fe14003bca68 100644 --- a/telecomm/java/android/telecom/RemoteConnectionService.java +++ b/telecomm/java/android/telecom/RemoteConnectionService.java @@ -368,6 +368,15 @@ final class RemoteConnectionService { } @Override + public void setAudioRoute(String callId, int audioRoute, Session.Info sessionInfo) { + if (hasConnection(callId)) { + // TODO(3pcalls): handle this for remote connections. + // Likely we don't want to do anything since it doesn't make sense for self-managed + // connections to go through a connection mgr. + } + } + + @Override public void onConnectionEvent(String callId, String event, Bundle extras, Session.Info sessionInfo) { if (mConnectionById.containsKey(callId)) { diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index f12886afa6e5..00e8f9f684c9 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -1202,17 +1202,25 @@ public class TelecomManager { /** * Registers a new incoming call. A {@link ConnectionService} should invoke this method when it - * has an incoming call. The specified {@link PhoneAccountHandle} must have been registered - * with {@link #registerPhoneAccount} and the user must have enabled the corresponding - * {@link PhoneAccount}. This can be checked using {@link #getPhoneAccount}. Once invoked, this - * method will cause the system to bind to the {@link ConnectionService} associated with the - * {@link PhoneAccountHandle} and request additional information about the call - * (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming + * has an incoming call. For managed {@link ConnectionService}s, the specified + * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and + * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using + * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have + * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call. + * <p> + * Once invoked, this method will cause the system to bind to the {@link ConnectionService} + * associated with the {@link PhoneAccountHandle} and request additional information about the + * call (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming * call UI. * <p> - * A {@link SecurityException} will be thrown if either the {@link PhoneAccountHandle} does not - * correspond to a registered {@link PhoneAccount} or the associated {@link PhoneAccount} is not - * currently enabled by the user. + * For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either + * the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or + * the associated {@link PhoneAccount} is not currently enabled by the user. + * <p> + * For a self-managed {@link ConnectionService}, a {@link SecurityException} will be thrown if + * the {@link PhoneAccount} has {@link PhoneAccount#CAPABILITY_SELF_MANAGED} and the calling app + * does not have {@link android.Manifest.permission#MANAGE_OWN_CALLS}. + * * @param phoneAccount A {@link PhoneAccountHandle} registered with * {@link #registerPhoneAccount}. * @param extras A bundle that will be passed through to @@ -1379,7 +1387,8 @@ public class TelecomManager { * method-caller is either the user selected default dialer app or preloaded system dialer * app, then emergency calls will also be allowed. * - * Requires permission: {@link android.Manifest.permission#CALL_PHONE} + * Placing a call via a managed {@link ConnectionService} requires permission: + * {@link android.Manifest.permission#CALL_PHONE} * * Usage example: * <pre> @@ -1396,11 +1405,20 @@ public class TelecomManager { * <li>{@link #EXTRA_START_CALL_WITH_SPEAKERPHONE}</li> * <li>{@link #EXTRA_START_CALL_WITH_VIDEO_STATE}</li> * </ul> + * <p> + * An app which implements the self-managed {@link ConnectionService} API uses + * {@link #placeCall(Uri, Bundle)} to inform Telecom of a new outgoing call. A self-managed + * {@link ConnectionService} must include {@link #EXTRA_PHONE_ACCOUNT_HANDLE} to specify its + * associated {@link android.telecom.PhoneAccountHandle}. + * + * Self-managed {@link ConnectionService}s require permission + * {@link android.Manifest.permission#MANAGE_OWN_CALLS}. * * @param address The address to make the call to. * @param extras Bundle of extras to use with the call. */ - @RequiresPermission(android.Manifest.permission.CALL_PHONE) + @RequiresPermission(anyOf = {android.Manifest.permission.CALL_PHONE, + android.Manifest.permission.MANAGE_OWN_CALLS}) public void placeCall(Uri address, Bundle extras) { ITelecomService service = getTelecomService(); if (service != null) { @@ -1476,6 +1494,71 @@ public class TelecomManager { return result; } + /** + * Determines whether Telecom would permit an incoming call to be added via the + * {@link #addNewIncomingCall(PhoneAccountHandle, Bundle)} API for the specified + * {@link PhoneAccountHandle}. + * <p> + * A {@link ConnectionService} may not add a call for the specified {@link PhoneAccountHandle} + * in the following situations: + * <ul> + * <li>{@link PhoneAccount} does not have property + * {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set (i.e. it is a managed + * {@link ConnectionService}), and the active or held call limit has + * been reached.</li> + * <li>There is an ongoing emergency call.</li> + * </ul> + * + * @param phoneAccountHandle The {@link PhoneAccountHandle} the call will be added for. + * @return {@code true} if telecom will permit an incoming call to be added, {@code false} + * otherwise. + */ + public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) { + ITelecomService service = getTelecomService(); + if (service != null) { + try { + return service.isIncomingCallPermitted(phoneAccountHandle); + } catch (RemoteException e) { + Log.e(TAG, "Error isIncomingCallPermitted", e); + } + } + return false; + } + + /** + * Determines whether Telecom would permit an outgoing call to be placed via the + * {@link #placeCall(Uri, Bundle)} API for the specified {@link PhoneAccountHandle}. + * <p> + * A {@link ConnectionService} may not place a call for the specified {@link PhoneAccountHandle} + * in the following situations: + * <ul> + * <li>{@link PhoneAccount} does not have property + * {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set (i.e. it is a managed + * {@link ConnectionService}), and the active, held or ringing call limit has + * been reached.</li> + * <li>{@link PhoneAccount} has property {@link PhoneAccount#CAPABILITY_SELF_MANAGED} set + * (i.e. it is a self-managed {@link ConnectionService} and there is an ongoing call in + * another {@link ConnectionService}.</li> + * <li>There is an ongoing emergency call.</li> + * </ul> + * + * @param phoneAccountHandle The {@link PhoneAccountHandle} the call will be added for. + * @return {@code true} if telecom will permit an outgoing call to be placed, {@code false} + * otherwise. + */ + public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) { + ITelecomService service = getTelecomService(); + if (service != null) { + try { + return service.isOutgoingCallPermitted(phoneAccountHandle); + } catch (RemoteException e) { + Log.e(TAG, "Error isOutgoingCallPermitted", e); + } + } + return false; + } + + private ITelecomService getTelecomService() { if (mTelecomServiceOverride != null) { return mTelecomServiceOverride; diff --git a/telecomm/java/android/telecom/package-info.java b/telecomm/java/android/telecom/package-info.java new file mode 100644 index 000000000000..a4140e5aa25d --- /dev/null +++ b/telecomm/java/android/telecom/package-info.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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 + */ + +/** + * The Android Telecom framework is responsible for managing calls on an Android device. This can + * include SIM-based calls using the {@code Telephony} framework, VOIP calls using SIP (e.g. the + * {@code SipConnectionService}), or via a third-party VOIP + * {@link android.telecom.ConnectionService}. Telecom acts as a switchboard, routing calls and + * audio focus between {@link android.telecom.Connection}s provided by + * {@link android.telecom.ConnectionService} implementations, and + * {@link android.telecom.InCallService} implementations which provide a user interface for calls. + * <p> + * Android supports the following calling use cases (with increasing level of complexity): + * <ul> + * <li>Implement the self-managed {@link android.telecom.ConnectionService} API - this is ideal + * for developers of standalone calling apps which do not wish to show their calls within the + * default phone app, and do not wish to have other calls shown in their user interface. Using + * a self-managed {@link android.telecom.ConnectionService} implementation within your + * standalone calling app helps you ensure that your app will interoperate not only with native + * telephony calling on the device, but also other standalone calling apps implementing this + * API. It also manages audio routing and focus for you.</li> + * <li>Implement the managed {@link android.telecom.ConnectionService} API - facilitates + * development of a calling solution that relies on the existing device phone application (see + * {@link android.telecom.TelecomManager#getDefaultDialerPackage()}) to provide the user + * interface for calls. An example might be a third party implementation of SIP calling, or a + * VOIP calling service. A {@link android.telecom.ConnectionService} alone provides only the + * means of connecting calls, but has no associated user interface.</li> + * <li>Implement the {@link android.telecom.InCallService} API - facilitates development of a + * replacement for the device's default Phone/Dialer app. The + * {@link android.telecom.InCallService} alone does not have any calling capability and consists + * of the user-interface side of calling only. An {@link android.telecom.InCallService} must + * handle all Calls the Telecom framework is aware of. It must not make assumptions about the + * nature of the calls (e.g. assuming calls are SIM-based telephony calls), and should not + * implement calling restrictions based on any one {@link android.telecom.ConnectionService} + * (e.g. it should not enforce Telephony restrictions for video calls).</li> + * <li>Implement both the {@link android.telecom.InCallService} and + * {@link android.telecom.ConnectionService} API - ideal if you wish to create your own + * {@link android.telecom.ConnectionService} based calling solution, complete with its own + * full user interface, while showing all other Android calls in the same user interface. Using + * this approach, you must still ensure that your {@link android.telecom.InCallService} makes + * no assumption about the source of the calls it displays. You must also ensure that your + * {@link android.telecom.ConnectionService} implementation can still function without the + * default phone app being set to your custom {@link android.telecom.InCallService}.</li> + * </ul> + */ +package android.telecom;
\ No newline at end of file diff --git a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl index 002c3bb24623..b58f8bc7a0aa 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionServiceAdapter.aidl @@ -102,6 +102,8 @@ oneway interface IConnectionServiceAdapter { void removeExtras(String callId, in List<String> keys, in Session.Info sessionInfo); + void setAudioRoute(String callId, int audioRoute, in Session.Info sessionInfo); + void onConnectionEvent(String callId, String event, in Bundle extras, in Session.Info sessionInfo); } diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 5c412e7afb0e..6ca0bc513463 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -249,4 +249,14 @@ interface ITelecomService { * @see TelecomServiceImpl#createManageBlockedNumbersIntent **/ Intent createManageBlockedNumbersIntent(); + + /** + * @see TelecomServiceImpl#isIncomingCallPermitted + */ + boolean isIncomingCallPermitted(in PhoneAccountHandle phoneAccountHandle); + + /** + * @see TelecomServiceImpl#isOutgoingCallPermitted + */ + boolean isOutgoingCallPermitted(in PhoneAccountHandle phoneAccountHandle); } |