Merge "Platform Telecom Transactional APIs"
This commit is contained in:
committed by
Android (Google) Code Review
commit
4d814d3cc6
@@ -41038,6 +41038,32 @@ package android.telecom {
|
||||
field public static final int RTT_MODE_VCO = 3; // 0x3
|
||||
}
|
||||
|
||||
public final class CallAttributes implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method @NonNull public android.net.Uri getAddress();
|
||||
method public int getCallCapabilities();
|
||||
method public int getCallType();
|
||||
method public int getDirection();
|
||||
method @NonNull public CharSequence getDisplayName();
|
||||
method @NonNull public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
|
||||
method public void writeToParcel(@Nullable android.os.Parcel, int);
|
||||
field public static final int AUDIO_CALL = 1; // 0x1
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.CallAttributes> CREATOR;
|
||||
field public static final int DIRECTION_INCOMING = 1; // 0x1
|
||||
field public static final int DIRECTION_OUTGOING = 2; // 0x2
|
||||
field public static final int SUPPORTS_SET_INACTIVE = 2; // 0x2
|
||||
field public static final int SUPPORTS_STREAM = 4; // 0x4
|
||||
field public static final int SUPPORTS_TRANSFER = 8; // 0x8
|
||||
field public static final int VIDEO_CALL = 2; // 0x2
|
||||
}
|
||||
|
||||
public static final class CallAttributes.Builder {
|
||||
ctor public CallAttributes.Builder(@NonNull android.telecom.PhoneAccountHandle, int, @NonNull CharSequence, @NonNull android.net.Uri);
|
||||
method @NonNull public android.telecom.CallAttributes build();
|
||||
method @NonNull public android.telecom.CallAttributes.Builder setCallCapabilities(int);
|
||||
method @NonNull public android.telecom.CallAttributes.Builder setCallType(int);
|
||||
}
|
||||
|
||||
public final class CallAudioState implements android.os.Parcelable {
|
||||
ctor public CallAudioState(boolean, int, int);
|
||||
method public static String audioRouteToString(int);
|
||||
@@ -41056,6 +41082,15 @@ package android.telecom {
|
||||
field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
|
||||
}
|
||||
|
||||
public final class CallControl implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method public void disconnect(@NonNull android.telecom.DisconnectCause, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
|
||||
method @NonNull public android.os.ParcelUuid getCallId();
|
||||
method public void rejectCall(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
|
||||
method public void setActive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
|
||||
method public void setInactive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
|
||||
}
|
||||
|
||||
public final class CallEndpoint implements android.os.Parcelable {
|
||||
ctor public CallEndpoint(@NonNull CharSequence, int, @NonNull android.os.ParcelUuid);
|
||||
method public int describeContents();
|
||||
@@ -41086,6 +41121,30 @@ package android.telecom {
|
||||
field public static final int ERROR_UNSPECIFIED = 4; // 0x4
|
||||
}
|
||||
|
||||
public interface CallEventCallback {
|
||||
method public void onAnswer(int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
|
||||
method public void onCallAudioStateChanged(@NonNull android.telecom.CallAudioState);
|
||||
method public void onDisconnect(@NonNull java.util.function.Consumer<java.lang.Boolean>);
|
||||
method public void onReject(@NonNull java.util.function.Consumer<java.lang.Boolean>);
|
||||
method public void onSetActive(@NonNull java.util.function.Consumer<java.lang.Boolean>);
|
||||
method public void onSetInactive(@NonNull java.util.function.Consumer<java.lang.Boolean>);
|
||||
}
|
||||
|
||||
public final class CallException extends java.lang.RuntimeException implements android.os.Parcelable {
|
||||
ctor public CallException(@Nullable String);
|
||||
ctor public CallException(@Nullable String, int);
|
||||
method public int describeContents();
|
||||
method public int getCode();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field public static final int CODE_CALL_CANNOT_BE_SET_TO_ACTIVE = 4; // 0x4
|
||||
field public static final int CODE_CALL_IS_NOT_BEING_TRACKED = 3; // 0x3
|
||||
field public static final int CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME = 5; // 0x5
|
||||
field public static final int CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL = 2; // 0x2
|
||||
field public static final int CODE_ERROR_UNKNOWN = 1; // 0x1
|
||||
field public static final int CODE_OPERATION_TIMED_OUT = 6; // 0x6
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.CallException> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class CallRedirectionService extends android.app.Service {
|
||||
ctor public CallRedirectionService();
|
||||
method public final void cancelCall();
|
||||
@@ -41595,6 +41654,7 @@ package android.telecom {
|
||||
field public static final int CAPABILITY_RTT = 4096; // 0x1000
|
||||
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_TRANSACTIONAL_OPERATIONS = 262144; // 0x40000
|
||||
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
|
||||
field public static final int CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS = 65536; // 0x10000
|
||||
field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
|
||||
@@ -41787,6 +41847,7 @@ package android.telecom {
|
||||
method public void acceptHandover(android.net.Uri, int, android.telecom.PhoneAccountHandle);
|
||||
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
|
||||
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
|
||||
method @RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS) public void addCall(@NonNull android.telecom.CallAttributes, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telecom.CallControl,android.telecom.CallException>, @NonNull android.telecom.CallEventCallback);
|
||||
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
|
||||
method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
|
||||
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
|
||||
|
||||
22
telecomm/java/android/telecom/CallAttributes.aidl
Normal file
22
telecomm/java/android/telecom/CallAttributes.aidl
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2022, 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.telecom;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable CallAttributes;
|
||||
344
telecomm/java/android/telecom/CallAttributes.java
Normal file
344
telecomm/java/android/telecom/CallAttributes.java
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.telecom;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* CallAttributes represents a set of properties that define a new Call. Apps should build an
|
||||
* instance of this class and use {@link TelecomManager#addCall} to start a new call with Telecom.
|
||||
*
|
||||
* <p>
|
||||
* Apps should first register a {@link PhoneAccount} via {@link TelecomManager#registerPhoneAccount}
|
||||
* and use the same {@link PhoneAccountHandle} registered with Telecom when creating an
|
||||
* instance of CallAttributes.
|
||||
*/
|
||||
public final class CallAttributes implements Parcelable {
|
||||
|
||||
/** PhoneAccountHandle associated with the App managing calls **/
|
||||
private final PhoneAccountHandle mPhoneAccountHandle;
|
||||
|
||||
/** Display name of the person on the other end of the call **/
|
||||
private final CharSequence mDisplayName;
|
||||
|
||||
/** Address of the call. Note, this can be extended to a meeting link **/
|
||||
private final Uri mAddress;
|
||||
|
||||
/** The direction (Outgoing/Incoming) of the new Call **/
|
||||
@Direction private final int mDirection;
|
||||
|
||||
/** Information related to data being transmitted (voice, video, etc. ) **/
|
||||
@CallType private final int mCallType;
|
||||
|
||||
/** Allows a package to opt into capabilities on the telecom side, on a per-call basis **/
|
||||
@CallCapability private final int mCallCapabilities;
|
||||
|
||||
/** @hide **/
|
||||
public static final String CALL_CAPABILITIES_KEY = "TelecomCapabilities";
|
||||
|
||||
private CallAttributes(@NonNull PhoneAccountHandle phoneAccountHandle,
|
||||
@NonNull CharSequence displayName,
|
||||
@NonNull Uri address,
|
||||
int direction,
|
||||
int callType,
|
||||
int callCapabilities) {
|
||||
mPhoneAccountHandle = phoneAccountHandle;
|
||||
mDisplayName = displayName;
|
||||
mAddress = address;
|
||||
mDirection = direction;
|
||||
mCallType = callType;
|
||||
mCallCapabilities = callCapabilities;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {DIRECTION_INCOMING, DIRECTION_OUTGOING})
|
||||
public @interface Direction {
|
||||
}
|
||||
/**
|
||||
* Indicates that the call is an incoming call.
|
||||
*/
|
||||
public static final int DIRECTION_INCOMING = 1;
|
||||
/**
|
||||
* Indicates that the call is an outgoing call.
|
||||
*/
|
||||
public static final int DIRECTION_OUTGOING = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {AUDIO_CALL, VIDEO_CALL})
|
||||
public @interface CallType {
|
||||
}
|
||||
/**
|
||||
* Used when answering or dialing a call to indicate that the call does not have a video
|
||||
* component
|
||||
*/
|
||||
public static final int AUDIO_CALL = 1;
|
||||
/**
|
||||
* Indicates video transmission is supported
|
||||
*/
|
||||
public static final int VIDEO_CALL = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {SUPPORTS_SET_INACTIVE, SUPPORTS_STREAM, SUPPORTS_TRANSFER}, flag = true)
|
||||
public @interface CallCapability {
|
||||
}
|
||||
/**
|
||||
* The call being created can be set to inactive (traditionally referred to as hold). This
|
||||
* means that once a new call goes active, if the active call needs to be held in order to
|
||||
* place or receive an incoming call, the active call will be placed on hold. otherwise, the
|
||||
* active call may be disconnected.
|
||||
*/
|
||||
public static final int SUPPORTS_SET_INACTIVE = 1 << 1;
|
||||
/**
|
||||
* The call can be streamed from a root device to another device to continue the call without
|
||||
* completely transferring it.
|
||||
*/
|
||||
public static final int SUPPORTS_STREAM = 1 << 2;
|
||||
/**
|
||||
* The call can be completely transferred from one endpoint to another
|
||||
*/
|
||||
public static final int SUPPORTS_TRANSFER = 1 << 3;
|
||||
|
||||
/**
|
||||
* Build an instance of {@link CallAttributes}. In order to build a valid instance, a
|
||||
* {@link PhoneAccountHandle}, call {@link Direction}, display name, and {@link Uri} address
|
||||
* are required.
|
||||
*
|
||||
* <p>
|
||||
* Note: Pass in the same {@link PhoneAccountHandle} that was used to register a
|
||||
* {@link PhoneAccount} with Telecom. see {@link TelecomManager#registerPhoneAccount}
|
||||
*/
|
||||
public static final class Builder {
|
||||
// required and final fields
|
||||
private final PhoneAccountHandle mPhoneAccountHandle;
|
||||
@Direction private final int mDirection;
|
||||
private final CharSequence mDisplayName;
|
||||
private final Uri mAddress;
|
||||
// optional fields
|
||||
@CallType private int mCallType = CallAttributes.AUDIO_CALL;
|
||||
@CallCapability private int mCallCapabilities = SUPPORTS_SET_INACTIVE;
|
||||
|
||||
/**
|
||||
* Constructor for the CallAttributes.Builder class
|
||||
*
|
||||
* @param phoneAccountHandle that belongs to package registered with Telecom
|
||||
* @param callDirection of the new call that will be added to Telecom
|
||||
* @param displayName of the caller for incoming calls or initiating user for outgoing calls
|
||||
* @param address of the caller for incoming calls or destination for outgoing calls
|
||||
*/
|
||||
public Builder(@NonNull PhoneAccountHandle phoneAccountHandle,
|
||||
@Direction int callDirection, @NonNull CharSequence displayName,
|
||||
@NonNull Uri address) {
|
||||
if (!isInRange(DIRECTION_INCOMING, DIRECTION_OUTGOING, callDirection)) {
|
||||
throw new IllegalArgumentException(TextUtils.formatSimple("CallDirection=[%d] is"
|
||||
+ " invalid. CallDirections value should be within [%d, %d]",
|
||||
callDirection, DIRECTION_INCOMING, DIRECTION_OUTGOING));
|
||||
}
|
||||
Objects.requireNonNull(phoneAccountHandle);
|
||||
Objects.requireNonNull(displayName);
|
||||
Objects.requireNonNull(address);
|
||||
mPhoneAccountHandle = phoneAccountHandle;
|
||||
mDirection = callDirection;
|
||||
mDisplayName = displayName;
|
||||
mAddress = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callType see {@link CallType} for valid arguments
|
||||
* @return Builder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCallType(@CallType int callType) {
|
||||
if (!isInRange(AUDIO_CALL, VIDEO_CALL, callType)) {
|
||||
throw new IllegalArgumentException(TextUtils.formatSimple("CallType=[%d] is"
|
||||
+ " invalid. CallTypes value should be within [%d, %d]",
|
||||
callType, AUDIO_CALL, VIDEO_CALL));
|
||||
}
|
||||
mCallType = callType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callCapabilities see {@link CallCapability} for valid arguments
|
||||
* @return Builder
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCallCapabilities(@CallCapability int callCapabilities) {
|
||||
mCallCapabilities = callCapabilities;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance of {@link CallAttributes} based on the last values passed to the
|
||||
* setters or default values.
|
||||
*
|
||||
* @return an instance of {@link CallAttributes}
|
||||
*/
|
||||
@NonNull
|
||||
public CallAttributes build() {
|
||||
return new CallAttributes(mPhoneAccountHandle, mDisplayName, mAddress, mDirection,
|
||||
mCallType, mCallCapabilities);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
private boolean isInRange(int floor, int ceiling, int value) {
|
||||
return value >= floor && value <= ceiling;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link PhoneAccountHandle} that should be registered to Telecom to allow calls. The
|
||||
* {@link PhoneAccountHandle} should be registered before creating a CallAttributes instance.
|
||||
*
|
||||
* @return the {@link PhoneAccountHandle} for this package that allows this call to be created
|
||||
*/
|
||||
@NonNull public PhoneAccountHandle getPhoneAccountHandle() {
|
||||
return mPhoneAccountHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return display name of the incoming caller or the person being called for an outgoing call
|
||||
*/
|
||||
@NonNull public CharSequence getDisplayName() {
|
||||
return mDisplayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return address of the incoming caller
|
||||
* or the address of the person being called for an outgoing call
|
||||
*/
|
||||
@NonNull public Uri getAddress() {
|
||||
return mAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the direction of the new call.
|
||||
*/
|
||||
public @Direction int getDirection() {
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Information related to data being transmitted (voice, video, etc. )
|
||||
*/
|
||||
public @CallType int getCallType() {
|
||||
return mCallType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The allowed capabilities of the new call
|
||||
*/
|
||||
public @CallCapability int getCallCapabilities() {
|
||||
return mCallCapabilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@Nullable Parcel dest, int flags) {
|
||||
dest.writeParcelable(mPhoneAccountHandle, flags);
|
||||
dest.writeCharSequence(mDisplayName);
|
||||
dest.writeParcelable(mAddress, flags);
|
||||
dest.writeInt(mDirection);
|
||||
dest.writeInt(mCallType);
|
||||
dest.writeInt(mCallCapabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for creating CallAttribute objects for deserialized Parcels.
|
||||
*/
|
||||
public static final @android.annotation.NonNull
|
||||
Parcelable.Creator<CallAttributes> CREATOR =
|
||||
new Parcelable.Creator<>() {
|
||||
@Override
|
||||
public CallAttributes createFromParcel(Parcel source) {
|
||||
return new CallAttributes(source.readParcelable(getClass().getClassLoader(),
|
||||
android.telecom.PhoneAccountHandle.class),
|
||||
source.readCharSequence(),
|
||||
source.readParcelable(getClass().getClassLoader(),
|
||||
android.net.Uri.class),
|
||||
source.readInt(),
|
||||
source.readInt(),
|
||||
source.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallAttributes[] newArray(int size) {
|
||||
return new CallAttributes[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("{ CallAttributes: [phoneAccountHandle: ")
|
||||
.append(mPhoneAccountHandle) /* PhoneAccountHandle#toString handles PII */
|
||||
.append("], [contactName: ")
|
||||
.append(Log.pii(mDisplayName))
|
||||
.append("], [address=")
|
||||
.append(Log.pii(mAddress))
|
||||
.append("], [direction=")
|
||||
.append(mDirection)
|
||||
.append("], [callType=")
|
||||
.append(mCallType)
|
||||
.append("], [mCallCapabilities=")
|
||||
.append(mCallCapabilities)
|
||||
.append("] }");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != this.getClass()) {
|
||||
return false;
|
||||
}
|
||||
CallAttributes that = (CallAttributes) obj;
|
||||
return this.mDirection == that.mDirection
|
||||
&& this.mCallType == that.mCallType
|
||||
&& this.mCallCapabilities == that.mCallCapabilities
|
||||
&& Objects.equals(this.mPhoneAccountHandle, that.mPhoneAccountHandle)
|
||||
&& Objects.equals(this.mAddress, that.mAddress)
|
||||
&& Objects.equals(this.mDisplayName, that.mDisplayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mPhoneAccountHandle, mAddress, mDisplayName,
|
||||
mDirection, mCallType, mCallCapabilities);
|
||||
}
|
||||
}
|
||||
22
telecomm/java/android/telecom/CallControl.aidl
Normal file
22
telecomm/java/android/telecom/CallControl.aidl
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2022, 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.telecom;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable CallControl;
|
||||
250
telecomm/java/android/telecom/CallControl.java
Normal file
250
telecomm/java/android/telecom/CallControl.java
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.telecom;
|
||||
|
||||
import static android.telecom.CallException.TRANSACTION_EXCEPTION_KEY;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
|
||||
import com.android.internal.telecom.ClientTransactionalServiceRepository;
|
||||
import com.android.internal.telecom.ICallControl;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* CallControl provides client side control of a call. Each Call will get an individual CallControl
|
||||
* instance in which the client can alter the state of the associated call.
|
||||
*
|
||||
* <p>
|
||||
* Each method is Transactional meaning that it can succeed or fail. If a transaction succeeds,
|
||||
* the {@link OutcomeReceiver#onResult} will be called by Telecom. Otherwise, the
|
||||
* {@link OutcomeReceiver#onError} is called and provides a {@link CallException} that details why
|
||||
* the operation failed.
|
||||
*/
|
||||
public final class CallControl implements AutoCloseable {
|
||||
private static final String TAG = CallControl.class.getSimpleName();
|
||||
private static final String INTERFACE_ERROR_MSG = "Call Control is not available";
|
||||
private final String mCallId;
|
||||
private final ICallControl mServerInterface;
|
||||
private final PhoneAccountHandle mPhoneAccountHandle;
|
||||
private final ClientTransactionalServiceRepository mRepository;
|
||||
|
||||
/** @hide */
|
||||
public CallControl(@NonNull String callId, @Nullable ICallControl serverInterface,
|
||||
@NonNull ClientTransactionalServiceRepository repository,
|
||||
@NonNull PhoneAccountHandle pah) {
|
||||
mCallId = callId;
|
||||
mServerInterface = serverInterface;
|
||||
mRepository = repository;
|
||||
mPhoneAccountHandle = pah;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the callId Telecom assigned to this CallControl object which should be attached to
|
||||
* an individual call.
|
||||
*/
|
||||
@NonNull
|
||||
public ParcelUuid getCallId() {
|
||||
return ParcelUuid.fromString(mCallId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Telecom set the call state to active.
|
||||
*
|
||||
* @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
|
||||
* will be called on.
|
||||
* @param callback that will be completed on the Telecom side that details success or failure
|
||||
* of the requested operation.
|
||||
*
|
||||
* {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
|
||||
* switched the call state to active
|
||||
*
|
||||
* {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
|
||||
* the call state to active. A {@link CallException} will be passed
|
||||
* that details why the operation failed.
|
||||
*/
|
||||
public void setActive(@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<Void, CallException> callback) {
|
||||
if (mServerInterface != null) {
|
||||
try {
|
||||
mServerInterface.setActive(mCallId,
|
||||
new CallControlResultReceiver("setActive", executor, callback));
|
||||
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(INTERFACE_ERROR_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Telecom set the call state to inactive. This the same as hold for two call endpoints
|
||||
* but can be extended to setting a meeting to inactive.
|
||||
*
|
||||
* @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
|
||||
* will be called on.
|
||||
* @param callback that will be completed on the Telecom side that details success or failure
|
||||
* of the requested operation.
|
||||
*
|
||||
* {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
|
||||
* switched the call state to inactive
|
||||
*
|
||||
* {@link OutcomeReceiver#onError} will be called if Telecom has failed to set
|
||||
* the call state to inactive. A {@link CallException} will be passed
|
||||
* that details why the operation failed.
|
||||
*/
|
||||
public void setInactive(@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<Void, CallException> callback) {
|
||||
if (mServerInterface != null) {
|
||||
try {
|
||||
mServerInterface.setInactive(mCallId,
|
||||
new CallControlResultReceiver("setInactive", executor, callback));
|
||||
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(INTERFACE_ERROR_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Telecom set the call state to disconnect.
|
||||
*
|
||||
* @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
|
||||
* will be called on.
|
||||
* @param callback that will be completed on the Telecom side that details success or failure
|
||||
* of the requested operation.
|
||||
*
|
||||
* {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
|
||||
* disconnected the call.
|
||||
*
|
||||
* {@link OutcomeReceiver#onError} will be called if Telecom has failed to
|
||||
* disconnect the call. A {@link CallException} will be passed
|
||||
* that details why the operation failed.
|
||||
*/
|
||||
public void disconnect(@NonNull DisconnectCause disconnectCause,
|
||||
@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<Void, CallException> callback) {
|
||||
if (mServerInterface != null) {
|
||||
try {
|
||||
mServerInterface.disconnect(mCallId, disconnectCause,
|
||||
new CallControlResultReceiver("disconnect", executor, callback));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(INTERFACE_ERROR_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request Telecom reject the incoming call.
|
||||
*
|
||||
* @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
|
||||
* will be called on.
|
||||
* @param callback that will be completed on the Telecom side that details success or failure
|
||||
* of the requested operation.
|
||||
*
|
||||
* {@link OutcomeReceiver#onResult} will be called if Telecom has successfully
|
||||
* rejected the incoming call.
|
||||
*
|
||||
* {@link OutcomeReceiver#onError} will be called if Telecom has failed to
|
||||
* reject the incoming call. A {@link CallException} will be passed
|
||||
* that details why the operation failed.
|
||||
*/
|
||||
public void rejectCall(@CallbackExecutor @NonNull Executor executor,
|
||||
@NonNull OutcomeReceiver<Void, CallException> callback) {
|
||||
if (mServerInterface != null) {
|
||||
try {
|
||||
mServerInterface.rejectCall(mCallId,
|
||||
new CallControlResultReceiver("rejectCall", executor, callback));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(INTERFACE_ERROR_MSG);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should be called after
|
||||
* {@link CallControl#disconnect(DisconnectCause, Executor, OutcomeReceiver)} or
|
||||
* {@link CallControl#rejectCall(Executor, OutcomeReceiver)}
|
||||
* to destroy all references of this object and avoid memory leaks.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
mRepository.removeCallFromServiceWrapper(mPhoneAccountHandle, mCallId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since {@link OutcomeReceiver}s cannot be passed via AIDL, a ResultReceiver (which can) must
|
||||
* wrap the Clients {@link OutcomeReceiver} passed in and await for the Telecom Server side
|
||||
* response in {@link ResultReceiver#onReceiveResult(int, Bundle)}.
|
||||
* @hide */
|
||||
private class CallControlResultReceiver extends ResultReceiver {
|
||||
private final String mCallingMethod;
|
||||
private final Executor mExecutor;
|
||||
private final OutcomeReceiver<Void, CallException> mClientCallback;
|
||||
|
||||
CallControlResultReceiver(String method, Executor executor,
|
||||
OutcomeReceiver<Void, CallException> clientCallback) {
|
||||
super(null);
|
||||
mCallingMethod = method;
|
||||
mExecutor = executor;
|
||||
mClientCallback = clientCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
Log.d(CallControl.TAG, "%s: oRR: resultCode=[%s]", mCallingMethod, resultCode);
|
||||
super.onReceiveResult(resultCode, resultData);
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (resultCode == TelecomManager.TELECOM_TRANSACTION_SUCCESS) {
|
||||
mExecutor.execute(() -> mClientCallback.onResult(null));
|
||||
} else {
|
||||
mExecutor.execute(() ->
|
||||
mClientCallback.onError(getTransactionException(resultData)));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
private CallException getTransactionException(Bundle resultData) {
|
||||
String message = "unknown error";
|
||||
if (resultData != null && resultData.containsKey(TRANSACTION_EXCEPTION_KEY)) {
|
||||
return resultData.getParcelable(TRANSACTION_EXCEPTION_KEY,
|
||||
CallException.class);
|
||||
}
|
||||
return new CallException(message, CallException.CODE_ERROR_UNKNOWN);
|
||||
}
|
||||
}
|
||||
103
telecomm/java/android/telecom/CallEventCallback.java
Normal file
103
telecomm/java/android/telecom/CallEventCallback.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.telecom;
|
||||
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* CallEventCallback relays updates to a call from the Telecom framework.
|
||||
* This can include operations which the app must implement on a Call due to the presence of other
|
||||
* calls on the device, requests relayed from a Bluetooth device, or from another calling surface.
|
||||
*
|
||||
* <p>
|
||||
* CallEventCallbacks with {@link Consumer}s are transactional, meaning that a client must
|
||||
* complete the {@link Consumer} via {@link Consumer#accept(Object)} in order to complete the
|
||||
* CallEventCallback. If a CallEventCallback can be completed, the
|
||||
* {@link Consumer#accept(Object)} should be called with {@link Boolean#TRUE}. Otherwise,
|
||||
* {@link Consumer#accept(Object)} should be called with {@link Boolean#FALSE} to represent the
|
||||
* CallEventCallback cannot be completed on the client side.
|
||||
*
|
||||
* <p>
|
||||
* Note: Each CallEventCallback has a timeout of 5000 milliseconds. Failing to complete the
|
||||
* {@link Consumer} before the timeout will result in a failed transaction.
|
||||
*/
|
||||
public interface CallEventCallback {
|
||||
/**
|
||||
* Telecom is informing the client to set the call active
|
||||
*
|
||||
* @param wasCompleted The {@link Consumer} to be completed. If the client can set the call
|
||||
* active on their end, the {@link Consumer#accept(Object)} should be
|
||||
* called with {@link Boolean#TRUE}. Otherwise,
|
||||
* {@link Consumer#accept(Object)} should be called with
|
||||
* {@link Boolean#FALSE}.
|
||||
*/
|
||||
void onSetActive(@NonNull Consumer<Boolean> wasCompleted);
|
||||
|
||||
/**
|
||||
* Telecom is informing the client to set the call inactive. This is the same as holding a call
|
||||
* for two endpoints but can be extended to setting a meeting inactive.
|
||||
*
|
||||
* @param wasCompleted The {@link Consumer} to be completed. If the client can set the call
|
||||
* inactive on their end, the {@link Consumer#accept(Object)} should be
|
||||
* called with {@link Boolean#TRUE}. Otherwise,
|
||||
* {@link Consumer#accept(Object)} should be called with
|
||||
* {@link Boolean#FALSE}.
|
||||
*/
|
||||
void onSetInactive(@NonNull Consumer<Boolean> wasCompleted);
|
||||
|
||||
/**
|
||||
* Telecom is informing the client to answer an incoming call and set it to active.
|
||||
*
|
||||
* @param videoState see {@link android.telecom.CallAttributes.CallType} for valid states
|
||||
* @param wasCompleted The {@link Consumer} to be completed. If the client can answer the call
|
||||
* on their end, {@link Consumer#accept(Object)} should be called with
|
||||
* {@link Boolean#TRUE}. Otherwise, {@link Consumer#accept(Object)} should
|
||||
* be called with {@link Boolean#FALSE}.
|
||||
*/
|
||||
void onAnswer(@android.telecom.CallAttributes.CallType int videoState,
|
||||
@NonNull Consumer<Boolean> wasCompleted);
|
||||
|
||||
/**
|
||||
* Telecom is informing the client to reject the incoming call
|
||||
*
|
||||
* @param wasCompleted The {@link Consumer} to be completed. If the client can reject the
|
||||
* incoming call, {@link Consumer#accept(Object)} should be called with
|
||||
* {@link Boolean#TRUE}. Otherwise, {@link Consumer#accept(Object)}
|
||||
* should be called with {@link Boolean#FALSE}.
|
||||
*/
|
||||
void onReject(@NonNull Consumer<Boolean> wasCompleted);
|
||||
|
||||
/**
|
||||
* Telecom is informing the client to disconnect the call
|
||||
*
|
||||
* @param wasCompleted The {@link Consumer} to be completed. If the client can disconnect the
|
||||
* call on their end, {@link Consumer#accept(Object)} should be called with
|
||||
* {@link Boolean#TRUE}. Otherwise, {@link Consumer#accept(Object)}
|
||||
* should be called with {@link Boolean#FALSE}.
|
||||
*/
|
||||
void onDisconnect(@NonNull Consumer<Boolean> wasCompleted);
|
||||
|
||||
/**
|
||||
* update the client on the new {@link CallAudioState}
|
||||
*
|
||||
* @param callAudioState that is currently being used
|
||||
*/
|
||||
void onCallAudioStateChanged(@NonNull CallAudioState callAudioState);
|
||||
}
|
||||
22
telecomm/java/android/telecom/CallException.aidl
Normal file
22
telecomm/java/android/telecom/CallException.aidl
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2022, 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.telecom;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable CallException;
|
||||
160
telecomm/java/android/telecom/CallException.java
Normal file
160
telecomm/java/android/telecom/CallException.java
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.telecom;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* This class defines exceptions that can be thrown when using Telecom APIs with
|
||||
* {@link android.os.OutcomeReceiver}s. Most of these exceptions are thrown when changing a call
|
||||
* state with {@link CallControl}s or {@link CallEventCallback}s.
|
||||
*/
|
||||
public final class CallException extends RuntimeException implements Parcelable {
|
||||
/** @hide **/
|
||||
public static final String TRANSACTION_EXCEPTION_KEY = "TelecomTransactionalExceptionKey";
|
||||
|
||||
/**
|
||||
* The operation has failed due to an unknown or unspecified error.
|
||||
*/
|
||||
public static final int CODE_ERROR_UNKNOWN = 1;
|
||||
|
||||
/**
|
||||
* The operation has failed due to Telecom failing to hold the current active call for the
|
||||
* call attempting to become the new active call. The client should end the current active call
|
||||
* and re-try the failed operation.
|
||||
*/
|
||||
public static final int CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL = 2;
|
||||
|
||||
/**
|
||||
* The operation has failed because Telecom has already removed the call from the server side
|
||||
* and destroyed all the objects associated with it. The client should re-add the call.
|
||||
*/
|
||||
public static final int CODE_CALL_IS_NOT_BEING_TRACKED = 3;
|
||||
|
||||
/**
|
||||
* The operation has failed because Telecom cannot set the requested call as the current active
|
||||
* call. The client should end the current active call and re-try the operation.
|
||||
*/
|
||||
public static final int CODE_CALL_CANNOT_BE_SET_TO_ACTIVE = 4;
|
||||
|
||||
/**
|
||||
* The operation has failed because there is either no PhoneAccount registered with Telecom
|
||||
* for the given operation, or the limit of calls has been reached. The client should end the
|
||||
* current active call and re-try the failed operation.
|
||||
*/
|
||||
public static final int CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME = 5;
|
||||
|
||||
/**
|
||||
* The operation has failed because the operation failed to complete before the timeout
|
||||
*/
|
||||
public static final int CODE_OPERATION_TIMED_OUT = 6;
|
||||
|
||||
private int mCode = CODE_ERROR_UNKNOWN;
|
||||
private final String mMessage;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString8(mMessage);
|
||||
dest.writeInt(mCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for creating CallAttribute objects for deserialized Parcels.
|
||||
*/
|
||||
public static final @android.annotation.NonNull
|
||||
Parcelable.Creator<CallException> CREATOR = new Parcelable.Creator<>() {
|
||||
@Override
|
||||
public CallException createFromParcel(Parcel source) {
|
||||
return new CallException(source.readString8(), source.readInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CallException[] newArray(int size) {
|
||||
return new CallException[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = "CODE_ERROR_", value = {
|
||||
CODE_ERROR_UNKNOWN,
|
||||
CODE_CANNOT_HOLD_CURRENT_ACTIVE_CALL,
|
||||
CODE_CALL_IS_NOT_BEING_TRACKED,
|
||||
CODE_CALL_CANNOT_BE_SET_TO_ACTIVE,
|
||||
CODE_CALL_NOT_PERMITTED_AT_PRESENT_TIME,
|
||||
CODE_OPERATION_TIMED_OUT
|
||||
})
|
||||
public @interface CallErrorCode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a new CallException when only message can be specified.
|
||||
* {@code CODE_ERROR_UNKNOWN} will be default code returned when calling {@code getCode}
|
||||
*
|
||||
* @param message related to why the exception was created
|
||||
*/
|
||||
public CallException(@Nullable String message) {
|
||||
super(getMessage(message, CODE_ERROR_UNKNOWN));
|
||||
mMessage = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for a new CallException that has a defined error code in this class
|
||||
*
|
||||
* @param message related to why the exception was created
|
||||
* @param code defined above that caused this exception to be created
|
||||
*/
|
||||
public CallException(@Nullable String message, @CallErrorCode int code) {
|
||||
super(getMessage(message, code));
|
||||
mCode = code;
|
||||
mMessage = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return one of the error codes defined in this class that was passed into the constructor
|
||||
*/
|
||||
public @CallErrorCode int getCode() {
|
||||
return mCode;
|
||||
}
|
||||
|
||||
private static String getMessage(String message, int code) {
|
||||
StringBuilder builder;
|
||||
if (!TextUtils.isEmpty(message)) {
|
||||
builder = new StringBuilder(message);
|
||||
builder.append(" (code: ");
|
||||
builder.append(code);
|
||||
builder.append(")");
|
||||
return builder.toString();
|
||||
} else {
|
||||
return "code: " + code;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +418,26 @@ public final class PhoneAccount implements Parcelable {
|
||||
*/
|
||||
public static final int CAPABILITY_VOICE_CALLING_AVAILABLE = 0x20000;
|
||||
|
||||
/* NEXT CAPABILITY: 0x40000 */
|
||||
|
||||
/**
|
||||
* Flag indicating that this {@link PhoneAccount} supports the use TelecomManager APIs that
|
||||
* utilize {@link android.os.OutcomeReceiver}s or {@link java.util.function.Consumer}s.
|
||||
* Be aware, if this capability is set, {@link #CAPABILITY_SELF_MANAGED} will be amended by
|
||||
* Telecom when this {@link PhoneAccount} is registered via
|
||||
* {@link TelecomManager#registerPhoneAccount(PhoneAccount)}.
|
||||
*
|
||||
* <p>
|
||||
* {@link android.os.OutcomeReceiver}s and {@link java.util.function.Consumer}s represent
|
||||
* transactional operations because the operation can succeed or fail. An app wishing to use
|
||||
* transactional operations should define behavior for a successful and failed TelecomManager
|
||||
* API call.
|
||||
*
|
||||
* @see #CAPABILITY_SELF_MANAGED
|
||||
* @see #getCapabilities
|
||||
*/
|
||||
public static final int CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS = 0x40000;
|
||||
|
||||
/* NEXT CAPABILITY: [0x80000, 0x100000, 0x200000] */
|
||||
|
||||
/**
|
||||
* URI scheme for telephone number URIs.
|
||||
|
||||
@@ -18,6 +18,7 @@ import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
|
||||
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -38,6 +39,7 @@ import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -49,6 +51,8 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.telecom.ClientTransactionalServiceRepository;
|
||||
import com.android.internal.telecom.ClientTransactionalServiceWrapper;
|
||||
import com.android.internal.telecom.ITelecomService;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -1056,6 +1060,14 @@ public class TelecomManager {
|
||||
|
||||
private final ITelecomService mTelecomServiceOverride;
|
||||
|
||||
/** @hide **/
|
||||
private final ClientTransactionalServiceRepository mTransactionalServiceRepository =
|
||||
new ClientTransactionalServiceRepository();
|
||||
/** @hide **/
|
||||
public static final int TELECOM_TRANSACTION_SUCCESS = 0;
|
||||
/** @hide **/
|
||||
public static final String TRANSACTION_CALL_ID_KEY = "TelecomCallId";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -2639,6 +2651,92 @@ public class TelecomManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new call with the specified {@link CallAttributes} to the telecom service. This method
|
||||
* can be used to add both incoming and outgoing calls.
|
||||
*
|
||||
* <p>
|
||||
* The difference between this API call and {@link TelecomManager#placeCall(Uri, Bundle)} or
|
||||
* {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)} is that this API
|
||||
* will asynchronously provide an update on whether the new call was added successfully via
|
||||
* an {@link OutcomeReceiver}. Additionally, callbacks will run on the executor thread that was
|
||||
* passed in.
|
||||
*
|
||||
* <p>
|
||||
* Note: Only packages that register with
|
||||
* {@link PhoneAccount#CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS}
|
||||
* can utilize this API. {@link PhoneAccount}s that set the capabilities
|
||||
* {@link PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION},
|
||||
* {@link PhoneAccount#CAPABILITY_CALL_PROVIDER},
|
||||
* {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}
|
||||
* are not supported and will cause an exception to be thrown.
|
||||
*
|
||||
* <p>
|
||||
* Usage example:
|
||||
* <pre>
|
||||
*
|
||||
* // An app should first define their own construct of a Call that overrides all the
|
||||
* // {@link CallEventCallback}s
|
||||
* private class MyVoipCall implements CallEventCallback {
|
||||
* // override all the {@link CallEventCallback}s
|
||||
* }
|
||||
*
|
||||
* PhoneAccountHandle handle = new PhoneAccountHandle(
|
||||
* new ComponentName("com.example.voip.app",
|
||||
* "com.example.voip.app.NewCallActivity"), "123");
|
||||
*
|
||||
* CallAttributes callAttributes = new CallAttributes.Builder(handle,
|
||||
* CallAttributes.DIRECTION_OUTGOING,
|
||||
* "John Smith", Uri.fromParts("tel", "123", null))
|
||||
* .build();
|
||||
*
|
||||
* telecomManager.addCall(callAttributes, Runnable::run, new OutcomeReceiver() {
|
||||
* public void onResult(CallControl callControl) {
|
||||
* // The call has been added successfully
|
||||
* }
|
||||
* }, new MyVoipCall());
|
||||
* </pre>
|
||||
*
|
||||
* @param callAttributes attributes of the new call (incoming or outgoing, address, etc. )
|
||||
* @param executor thread to run background CallEventCallback updates on
|
||||
* @param pendingControl OutcomeReceiver that receives the result of addCall transaction
|
||||
* @param callEventCallback object that overrides CallEventCallback
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MANAGE_OWN_CALLS)
|
||||
@SuppressLint("SamShouldBeLast")
|
||||
public void addCall(@NonNull CallAttributes callAttributes,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull OutcomeReceiver<CallControl, CallException> pendingControl,
|
||||
@NonNull CallEventCallback callEventCallback) {
|
||||
Objects.requireNonNull(callAttributes);
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(pendingControl);
|
||||
Objects.requireNonNull(callEventCallback);
|
||||
|
||||
ITelecomService service = getTelecomService();
|
||||
if (service != null) {
|
||||
try {
|
||||
// create or add the new call to a service wrapper w/ the same phoneAccountHandle
|
||||
ClientTransactionalServiceWrapper transactionalServiceWrapper =
|
||||
mTransactionalServiceRepository.addNewCallForTransactionalServiceWrapper(
|
||||
callAttributes.getPhoneAccountHandle());
|
||||
|
||||
// couple all the args passed by the client
|
||||
String newCallId = transactionalServiceWrapper.trackCall(callAttributes, executor,
|
||||
pendingControl, callEventCallback);
|
||||
|
||||
// send args to server to process new call
|
||||
service.addCall(callAttributes, transactionalServiceWrapper.getCallEventCallback(),
|
||||
newCallId, mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException addCall: " + e);
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Telecom service is not present");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
|
||||
* @param intent The {@link Intent#ACTION_CALL} intent to handle.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.internal.telecom;
|
||||
|
||||
import android.telecom.PhoneAccountHandle;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ClientTransactionalServiceRepository {
|
||||
|
||||
private static final Map<PhoneAccountHandle, ClientTransactionalServiceWrapper> LOOKUP_TABLE =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* creates a new {@link ClientTransactionalServiceWrapper} if this is the first call being
|
||||
* tracked for a particular package Or adds a new call for an existing
|
||||
* {@link ClientTransactionalServiceWrapper}
|
||||
*
|
||||
* @param phoneAccountHandle for a particular package requesting to create a call
|
||||
* @return the {@link ClientTransactionalServiceWrapper} that is tied tot the PhoneAccountHandle
|
||||
*/
|
||||
public ClientTransactionalServiceWrapper addNewCallForTransactionalServiceWrapper(
|
||||
PhoneAccountHandle phoneAccountHandle) {
|
||||
|
||||
ClientTransactionalServiceWrapper service = null;
|
||||
if (!hasExistingServiceWrapper(phoneAccountHandle)) {
|
||||
service = new ClientTransactionalServiceWrapper(phoneAccountHandle, this);
|
||||
} else {
|
||||
service = getTransactionalServiceWrapper(phoneAccountHandle);
|
||||
}
|
||||
|
||||
LOOKUP_TABLE.put(phoneAccountHandle, service);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
private ClientTransactionalServiceWrapper getTransactionalServiceWrapper(
|
||||
PhoneAccountHandle pah) {
|
||||
return LOOKUP_TABLE.get(pah);
|
||||
}
|
||||
|
||||
private boolean hasExistingServiceWrapper(PhoneAccountHandle pah) {
|
||||
return LOOKUP_TABLE.containsKey(pah);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pah that is tied to a particular package with potential tracked calls
|
||||
* @return if the {@link ClientTransactionalServiceWrapper} was successfully removed
|
||||
*/
|
||||
public boolean removeServiceWrapper(PhoneAccountHandle pah) {
|
||||
if (!hasExistingServiceWrapper(pah)) {
|
||||
return false;
|
||||
}
|
||||
LOOKUP_TABLE.remove(pah);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pah that is tied to a particular package with potential tracked calls
|
||||
* @param callId of the TransactionalCall that you want to remove
|
||||
* @return if the call was successfully removed from the service wrapper
|
||||
*/
|
||||
public boolean removeCallFromServiceWrapper(PhoneAccountHandle pah, String callId) {
|
||||
if (!hasExistingServiceWrapper(pah)) {
|
||||
return false;
|
||||
}
|
||||
ClientTransactionalServiceWrapper service = LOOKUP_TABLE.get(pah);
|
||||
service.untrackCall(callId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.internal.telecom;
|
||||
|
||||
import static android.telecom.TelecomManager.TELECOM_TRANSACTION_SUCCESS;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.os.ResultReceiver;
|
||||
import android.telecom.CallAttributes;
|
||||
import android.telecom.CallAudioState;
|
||||
import android.telecom.CallControl;
|
||||
import android.telecom.CallEventCallback;
|
||||
import android.telecom.CallException;
|
||||
import android.telecom.PhoneAccountHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* wraps {@link CallEventCallback} and {@link CallControl} on a
|
||||
* per-{@link android.telecom.PhoneAccountHandle} basis to track ongoing calls.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class ClientTransactionalServiceWrapper {
|
||||
|
||||
private static final String TAG = ClientTransactionalServiceWrapper.class.getSimpleName();
|
||||
private final PhoneAccountHandle mPhoneAccountHandle;
|
||||
private final ClientTransactionalServiceRepository mRepository;
|
||||
private final ConcurrentHashMap<String, TransactionalCall> mCallIdToTransactionalCall =
|
||||
new ConcurrentHashMap<>();
|
||||
private static final String EXECUTOR_FAIL_MSG =
|
||||
"Telecom hit an exception while handling a CallEventCallback on an executor: ";
|
||||
|
||||
public ClientTransactionalServiceWrapper(PhoneAccountHandle handle,
|
||||
ClientTransactionalServiceRepository repo) {
|
||||
mPhoneAccountHandle = handle;
|
||||
mRepository = repo;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the given call from the class HashMap
|
||||
*
|
||||
* @param callId that is tied to TransactionalCall object
|
||||
*/
|
||||
public void untrackCall(String callId) {
|
||||
Log.i(TAG, TextUtils.formatSimple("removeCall: with id=[%s]", callId));
|
||||
if (mCallIdToTransactionalCall.containsKey(callId)) {
|
||||
// remove the call from the hashmap
|
||||
TransactionalCall call = mCallIdToTransactionalCall.remove(callId);
|
||||
// null out interface to avoid memory leaks
|
||||
CallControl control = call.getCallControl();
|
||||
if (control != null) {
|
||||
call.setCallControl(null);
|
||||
}
|
||||
}
|
||||
// possibly cleanup service wrapper if there are no more calls
|
||||
if (mCallIdToTransactionalCall.size() == 0) {
|
||||
mRepository.removeServiceWrapper(mPhoneAccountHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start tracking a newly created call for a particular package
|
||||
*
|
||||
* @param callAttributes of the new call
|
||||
* @param executor to run callbacks on
|
||||
* @param pendingControl that allows telecom to call into the client
|
||||
* @param callback that overrides the CallEventCallback
|
||||
* @return the callId of the newly created call
|
||||
*/
|
||||
public String trackCall(CallAttributes callAttributes, Executor executor,
|
||||
OutcomeReceiver<CallControl, CallException> pendingControl,
|
||||
CallEventCallback callback) {
|
||||
// generate a new id for this new call
|
||||
String newCallId = UUID.randomUUID().toString();
|
||||
|
||||
// couple the objects passed from the client side
|
||||
mCallIdToTransactionalCall.put(newCallId, new TransactionalCall(newCallId, callAttributes,
|
||||
executor, pendingControl, callback));
|
||||
|
||||
return newCallId;
|
||||
}
|
||||
|
||||
public ICallEventCallback getCallEventCallback() {
|
||||
return mCallEventCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumers that is to be completed by the client and the result relayed back to telecom server
|
||||
* side via a {@link ResultReceiver}. see com.android.server.telecom.TransactionalServiceWrapper
|
||||
* for how the response is handled.
|
||||
*/
|
||||
private class ReceiverWrapper implements Consumer<Boolean> {
|
||||
private final ResultReceiver mRepeaterReceiver;
|
||||
|
||||
ReceiverWrapper(ResultReceiver resultReceiver) {
|
||||
mRepeaterReceiver = resultReceiver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Boolean clientCompletedCallbackSuccessfully) {
|
||||
if (clientCompletedCallbackSuccessfully) {
|
||||
mRepeaterReceiver.send(TELECOM_TRANSACTION_SUCCESS, null);
|
||||
} else {
|
||||
mRepeaterReceiver.send(CallException.CODE_ERROR_UNKNOWN, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Consumer<Boolean> andThen(Consumer<? super Boolean> after) {
|
||||
return Consumer.super.andThen(after);
|
||||
}
|
||||
}
|
||||
|
||||
private final ICallEventCallback mCallEventCallback = new ICallEventCallback.Stub() {
|
||||
|
||||
private static final String ON_SET_ACTIVE = "onSetActive";
|
||||
private static final String ON_SET_INACTIVE = "onSetInactive";
|
||||
private static final String ON_ANSWER = "onAnswer";
|
||||
private static final String ON_REJECT = "onReject";
|
||||
private static final String ON_DISCONNECT = "onDisconnect";
|
||||
|
||||
private void handleCallEventCallback(String action, String callId, int code,
|
||||
ResultReceiver ackResultReceiver) {
|
||||
Log.i(TAG, TextUtils.formatSimple("hCEC: id=[%s], action=[%s]", callId, action));
|
||||
// lookup the callEventCallback associated with the particular call
|
||||
TransactionalCall call = mCallIdToTransactionalCall.get(callId);
|
||||
|
||||
if (call != null) {
|
||||
// Get the CallEventCallback interface
|
||||
CallEventCallback callback = call.getCallEventCallback();
|
||||
// Get Receiver to wait on client ack
|
||||
ReceiverWrapper outcomeReceiverWrapper = new ReceiverWrapper(ackResultReceiver);
|
||||
|
||||
// wait for the client to complete the CallEventCallback
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
call.getExecutor().execute(() -> {
|
||||
switch (action) {
|
||||
case ON_SET_ACTIVE:
|
||||
callback.onSetActive(outcomeReceiverWrapper);
|
||||
break;
|
||||
case ON_SET_INACTIVE:
|
||||
callback.onSetInactive(outcomeReceiverWrapper);
|
||||
break;
|
||||
case ON_REJECT:
|
||||
callback.onReject(outcomeReceiverWrapper);
|
||||
untrackCall(callId);
|
||||
break;
|
||||
case ON_DISCONNECT:
|
||||
callback.onDisconnect(outcomeReceiverWrapper);
|
||||
untrackCall(callId);
|
||||
break;
|
||||
case ON_ANSWER:
|
||||
callback.onAnswer(code, outcomeReceiverWrapper);
|
||||
break;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, EXECUTOR_FAIL_MSG + e);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddCallControl(String callId, int resultCode, ICallControl callControl,
|
||||
CallException transactionalException) {
|
||||
Log.i(TAG, TextUtils.formatSimple("oACC: id=[%s], code=[%d]", callId, resultCode));
|
||||
TransactionalCall call = mCallIdToTransactionalCall.get(callId);
|
||||
|
||||
if (call != null) {
|
||||
OutcomeReceiver<CallControl, CallException> pendingControl =
|
||||
call.getPendingControl();
|
||||
|
||||
if (resultCode == TELECOM_TRANSACTION_SUCCESS) {
|
||||
|
||||
// create the interface object that the client will interact with
|
||||
CallControl control = new CallControl(callId, callControl, mRepository,
|
||||
mPhoneAccountHandle);
|
||||
// give the client the object via the OR that was passed into addCall
|
||||
pendingControl.onResult(control);
|
||||
|
||||
// store for later reference
|
||||
call.setCallControl(control);
|
||||
} else {
|
||||
pendingControl.onError(transactionalException);
|
||||
mCallIdToTransactionalCall.remove(callId);
|
||||
}
|
||||
|
||||
} else {
|
||||
untrackCall(callId);
|
||||
Log.e(TAG, "oACC: TransactionalCall object not found for call w/ id=" + callId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetActive(String callId, ResultReceiver resultReceiver) {
|
||||
handleCallEventCallback(ON_SET_ACTIVE, callId, 0, resultReceiver);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSetInactive(String callId, ResultReceiver resultReceiver) {
|
||||
handleCallEventCallback(ON_SET_INACTIVE, callId, 0, resultReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnswer(String callId, int videoState, ResultReceiver resultReceiver) {
|
||||
handleCallEventCallback(ON_ANSWER, callId, videoState, resultReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(String callId, ResultReceiver resultReceiver) {
|
||||
handleCallEventCallback(ON_REJECT, callId, 0, resultReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(String callId, ResultReceiver resultReceiver) {
|
||||
handleCallEventCallback(ON_DISCONNECT, callId, 0, resultReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
|
||||
Log.i(TAG, TextUtils.formatSimple("onCallAudioStateChanged: callId=[%s]", callId));
|
||||
// lookup the callEventCallback associated with the particular call
|
||||
TransactionalCall call = mCallIdToTransactionalCall.get(callId);
|
||||
if (call != null) {
|
||||
CallEventCallback callback = call.getCallEventCallback();
|
||||
Executor executor = call.getExecutor();
|
||||
executor.execute(() -> {
|
||||
callback.onCallAudioStateChanged(callAudioState);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCallFromTransactionalServiceWrapper(String callId) {
|
||||
untrackCall(callId);
|
||||
}
|
||||
};
|
||||
}
|
||||
31
telecomm/java/com/android/internal/telecom/ICallControl.aidl
Normal file
31
telecomm/java/com/android/internal/telecom/ICallControl.aidl
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.internal.telecom;
|
||||
|
||||
import android.telecom.CallControl;
|
||||
import android.telecom.DisconnectCause;
|
||||
import android.os.ResultReceiver;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ICallControl {
|
||||
void setActive(String callId, in ResultReceiver callback);
|
||||
void setInactive(String callId, in ResultReceiver callback);
|
||||
void disconnect(String callId, in DisconnectCause disconnectCause, in ResultReceiver callback);
|
||||
void rejectCall(String callId, in ResultReceiver callback);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.internal.telecom;
|
||||
|
||||
import android.telecom.CallControl;
|
||||
import com.android.internal.telecom.ICallControl;
|
||||
import android.os.ResultReceiver;
|
||||
import android.telecom.CallAudioState;
|
||||
import android.telecom.CallException;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface ICallEventCallback {
|
||||
// publicly exposed. Client should override
|
||||
void onAddCallControl(String callId, int resultCode, in ICallControl callControl,
|
||||
in CallException exception);
|
||||
void onSetActive(String callId, in ResultReceiver callback);
|
||||
void onSetInactive(String callId, in ResultReceiver callback);
|
||||
void onAnswer(String callId, int videoState, in ResultReceiver callback);
|
||||
void onReject(String callId, in ResultReceiver callback);
|
||||
void onDisconnect(String callId, in ResultReceiver callback);
|
||||
void onCallAudioStateChanged(String callId, in CallAudioState callAudioState);
|
||||
// hidden methods that help with cleanup
|
||||
void removeCallFromTransactionalServiceWrapper(String callId);
|
||||
}
|
||||
@@ -25,6 +25,8 @@ import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.telecom.PhoneAccount;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.telecom.CallAttributes;
|
||||
import com.android.internal.telecom.ICallEventCallback;
|
||||
|
||||
/**
|
||||
* Interface used to interact with Telecom. Mostly this is used by TelephonyManager for passing
|
||||
@@ -391,4 +393,10 @@ interface ITelecomService {
|
||||
*/
|
||||
boolean isInSelfManagedCall(String packageName, in UserHandle userHandle,
|
||||
String callingPackage);
|
||||
|
||||
/**
|
||||
* @see TelecomServiceImpl#addCall
|
||||
*/
|
||||
void addCall(in CallAttributes callAttributes, in ICallEventCallback callback, String callId,
|
||||
String callingPackage);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 com.android.internal.telecom;
|
||||
|
||||
import android.os.OutcomeReceiver;
|
||||
import android.telecom.CallAttributes;
|
||||
import android.telecom.CallControl;
|
||||
import android.telecom.CallEventCallback;
|
||||
import android.telecom.CallException;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class TransactionalCall {
|
||||
|
||||
private final String mCallId;
|
||||
private final CallAttributes mCallAttributes;
|
||||
private final Executor mExecutor;
|
||||
private final OutcomeReceiver<CallControl, CallException> mPendingControl;
|
||||
private final CallEventCallback mCallEventCallback;
|
||||
private CallControl mCallControl;
|
||||
|
||||
public TransactionalCall(String callId, CallAttributes callAttributes,
|
||||
Executor executor, OutcomeReceiver<CallControl, CallException> pendingControl,
|
||||
CallEventCallback callEventCallback) {
|
||||
mCallId = callId;
|
||||
mCallAttributes = callAttributes;
|
||||
mExecutor = executor;
|
||||
mPendingControl = pendingControl;
|
||||
mCallEventCallback = callEventCallback;
|
||||
}
|
||||
|
||||
public void setCallControl(CallControl callControl) {
|
||||
mCallControl = callControl;
|
||||
}
|
||||
|
||||
public CallControl getCallControl() {
|
||||
return mCallControl;
|
||||
}
|
||||
|
||||
public String getCallId() {
|
||||
return mCallId;
|
||||
}
|
||||
|
||||
public CallAttributes getCallAttributes() {
|
||||
return mCallAttributes;
|
||||
}
|
||||
|
||||
public Executor getExecutor() {
|
||||
return mExecutor;
|
||||
}
|
||||
|
||||
public OutcomeReceiver<CallControl, CallException> getPendingControl() {
|
||||
return mPendingControl;
|
||||
}
|
||||
|
||||
public CallEventCallback getCallEventCallback() {
|
||||
return mCallEventCallback;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user