Merge "Revert "gtbs: Add Generic Telephone Bearer Service support""
This commit is contained in:
@@ -3086,9 +3086,6 @@ public final class BluetoothAdapter {
|
|||||||
BluetoothCsipSetCoordinator csipSetCoordinator =
|
BluetoothCsipSetCoordinator csipSetCoordinator =
|
||||||
new BluetoothCsipSetCoordinator(context, listener, this);
|
new BluetoothCsipSetCoordinator(context, listener, this);
|
||||||
return true;
|
return true;
|
||||||
} else if (profile == BluetoothProfile.LE_CALL_CONTROL) {
|
|
||||||
BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener);
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3191,10 +3188,6 @@ public final class BluetoothAdapter {
|
|||||||
(BluetoothCsipSetCoordinator) proxy;
|
(BluetoothCsipSetCoordinator) proxy;
|
||||||
csipSetCoordinator.close();
|
csipSetCoordinator.close();
|
||||||
break;
|
break;
|
||||||
case BluetoothProfile.LE_CALL_CONTROL:
|
|
||||||
BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy;
|
|
||||||
tbs.close();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,285 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 HIMSA II K/S - www.himsa.com.
|
|
||||||
* Represented by EHIMA - www.ehima.com
|
|
||||||
*
|
|
||||||
* 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.bluetooth;
|
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.os.Parcel;
|
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.os.ParcelUuid;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Representation of Call
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public final class BluetoothLeCall implements Parcelable {
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@IntDef(prefix = "STATE_", value = {
|
|
||||||
STATE_INCOMING,
|
|
||||||
STATE_DIALING,
|
|
||||||
STATE_ALERTING,
|
|
||||||
STATE_ACTIVE,
|
|
||||||
STATE_LOCALLY_HELD,
|
|
||||||
STATE_REMOTELY_HELD,
|
|
||||||
STATE_LOCALLY_AND_REMOTELY_HELD
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface State {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote party is calling (incoming call).
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_INCOMING = 0x00;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The process to call the remote party has started but the remote party is not
|
|
||||||
* being alerted (outgoing call).
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_DIALING = 0x01;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote party is being alerted (outgoing call).
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_ALERTING = 0x02;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The call is in an active conversation.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_ACTIVE = 0x03;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The call is connected but held locally. “Locally Held” implies that either
|
|
||||||
* the server or the client can affect the state.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_LOCALLY_HELD = 0x04;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The call is connected but held remotely. “Remotely Held” means that the state
|
|
||||||
* is controlled by the remote party of a call.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_REMOTELY_HELD = 0x05;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The call is connected but held both locally and remotely.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int STATE_LOCALLY_AND_REMOTELY_HELD = 0x06;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the call direction is outgoing.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int FLAG_OUTGOING_CALL = 0x00000001;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the call URI and Friendly Name are withheld by server.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int FLAG_WITHHELD_BY_SERVER = 0x00000002;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the call URI and Friendly Name are withheld by network.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int FLAG_WITHHELD_BY_NETWORK = 0x00000004;
|
|
||||||
|
|
||||||
/** Unique UUID that identifies this call */
|
|
||||||
private UUID mUuid;
|
|
||||||
|
|
||||||
/** Remote Caller URI */
|
|
||||||
private String mUri;
|
|
||||||
|
|
||||||
/** Caller friendly name */
|
|
||||||
private String mFriendlyName;
|
|
||||||
|
|
||||||
/** Call state */
|
|
||||||
private @State int mState;
|
|
||||||
|
|
||||||
/** Call flags */
|
|
||||||
private int mCallFlags;
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
public BluetoothLeCall(@NonNull BluetoothLeCall that) {
|
|
||||||
mUuid = new UUID(that.getUuid().getMostSignificantBits(),
|
|
||||||
that.getUuid().getLeastSignificantBits());
|
|
||||||
mUri = that.mUri;
|
|
||||||
mFriendlyName = that.mFriendlyName;
|
|
||||||
mState = that.mState;
|
|
||||||
mCallFlags = that.mCallFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
public BluetoothLeCall(@NonNull UUID uuid, @NonNull String uri, @NonNull String friendlyName,
|
|
||||||
@State int state, int callFlags) {
|
|
||||||
mUuid = uuid;
|
|
||||||
mUri = uri;
|
|
||||||
mFriendlyName = friendlyName;
|
|
||||||
mState = state;
|
|
||||||
mCallFlags = callFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (o == null || getClass() != o.getClass())
|
|
||||||
return false;
|
|
||||||
BluetoothLeCall that = (BluetoothLeCall) o;
|
|
||||||
return mUuid.equals(that.mUuid) && mUri.equals(that.mUri)
|
|
||||||
&& mFriendlyName.equals(that.mFriendlyName) && mState == that.mState
|
|
||||||
&& mCallFlags == that.mCallFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(mUuid, mUri, mFriendlyName, mState, mCallFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this BluetoothLeCall.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Currently this is the UUID.
|
|
||||||
*
|
|
||||||
* @return string representation of this BluetoothLeCall
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return mUuid.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int describeContents() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
|
||||||
out.writeParcelable(new ParcelUuid(mUuid), 0);
|
|
||||||
out.writeString(mUri);
|
|
||||||
out.writeString(mFriendlyName);
|
|
||||||
out.writeInt(mState);
|
|
||||||
out.writeInt(mCallFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final @android.annotation.NonNull Parcelable.Creator<BluetoothLeCall> CREATOR =
|
|
||||||
new Parcelable.Creator<BluetoothLeCall>() {
|
|
||||||
public BluetoothLeCall createFromParcel(Parcel in) {
|
|
||||||
return new BluetoothLeCall(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BluetoothLeCall[] newArray(int size) {
|
|
||||||
return new BluetoothLeCall[size];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private BluetoothLeCall(Parcel in) {
|
|
||||||
mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
|
|
||||||
mUri = in.readString();
|
|
||||||
mFriendlyName = in.readString();
|
|
||||||
mState = in.readInt();
|
|
||||||
mCallFlags = in.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an UUID of this BluetoothLeCall.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An UUID is unique identifier of a BluetoothLeCall.
|
|
||||||
*
|
|
||||||
* @return UUID of this BluetoothLeCall
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public @NonNull UUID getUuid() {
|
|
||||||
return mUuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a URI of the remote party of this BluetoothLeCall.
|
|
||||||
*
|
|
||||||
* @return string representation of this BluetoothLeCall
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public @NonNull String getUri() {
|
|
||||||
return mUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a friendly name of the call.
|
|
||||||
*
|
|
||||||
* @return friendly name representation of this BluetoothLeCall
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public @NonNull String getFriendlyName() {
|
|
||||||
return mFriendlyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the call state.
|
|
||||||
*
|
|
||||||
* @return the state of this BluetoothLeCall
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public @State int getState() {
|
|
||||||
return mState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the call flags.
|
|
||||||
*
|
|
||||||
* @return call flags
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public int getCallFlags() {
|
|
||||||
return mCallFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the call direction is incoming.
|
|
||||||
*
|
|
||||||
* @return true if incoming call, false otherwise
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public boolean isIncomingCall() {
|
|
||||||
return (mCallFlags & FLAG_OUTGOING_CALL) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,911 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019 HIMSA II K/S - www.himsa.com.
|
|
||||||
* Represented by EHIMA - www.ehima.com
|
|
||||||
*
|
|
||||||
* 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.bluetooth;
|
|
||||||
|
|
||||||
import android.Manifest;
|
|
||||||
import android.annotation.IntDef;
|
|
||||||
import android.annotation.NonNull;
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.annotation.RequiresPermission;
|
|
||||||
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.os.ParcelUuid;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class provides the APIs to control the Call Control profile.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This class provides Bluetooth Telephone Bearer Service functionality,
|
|
||||||
* allowing applications to expose a GATT Service based interface to control the
|
|
||||||
* state of the calls by remote devices such as LE audio devices.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* BluetoothLeCallControl is a proxy object for controlling the Bluetooth Telephone Bearer
|
|
||||||
* Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
|
|
||||||
* BluetoothLeCallControl proxy object.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public final class BluetoothLeCallControl implements BluetoothProfile {
|
|
||||||
private static final String TAG = "BluetoothLeCallControl";
|
|
||||||
private static final boolean DBG = true;
|
|
||||||
private static final boolean VDBG = false;
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@IntDef(prefix = "RESULT_", value = {
|
|
||||||
RESULT_SUCCESS,
|
|
||||||
RESULT_ERROR_UNKNOWN_CALL_ID,
|
|
||||||
RESULT_ERROR_INVALID_URI,
|
|
||||||
RESULT_ERROR_APPLICATION
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface Result {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opcode write was successful.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int RESULT_SUCCESS = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unknown call Id has been used in the operation.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int RESULT_ERROR_UNKNOWN_CALL_ID = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URI provided in {@link Callback#onPlaceCallRequest} is invalid.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int RESULT_ERROR_INVALID_URI = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Application internal error.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int RESULT_ERROR_APPLICATION = 3;
|
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@IntDef(prefix = "TERMINATION_REASON_", value = {
|
|
||||||
TERMINATION_REASON_INVALID_URI,
|
|
||||||
TERMINATION_REASON_FAIL,
|
|
||||||
TERMINATION_REASON_REMOTE_HANGUP,
|
|
||||||
TERMINATION_REASON_SERVER_HANGUP,
|
|
||||||
TERMINATION_REASON_LINE_BUSY,
|
|
||||||
TERMINATION_REASON_NETWORK_CONGESTION,
|
|
||||||
TERMINATION_REASON_CLIENT_HANGUP,
|
|
||||||
TERMINATION_REASON_NO_SERVICE,
|
|
||||||
TERMINATION_REASON_NO_ANSWER
|
|
||||||
})
|
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
|
||||||
public @interface TerminationReason {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote Caller ID value used to place a call was formed improperly.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_INVALID_URI = 0x00;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call fail.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_FAIL = 0x01;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remote party ended call.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_REMOTE_HANGUP = 0x02;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call ended from the server.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_SERVER_HANGUP = 0x03;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Line busy.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_LINE_BUSY = 0x04;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Network congestion.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_NETWORK_CONGESTION = 0x05;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client terminated.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_CLIENT_HANGUP = 0x06;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No service.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_NO_SERVICE = 0x07;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* No answer.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int TERMINATION_REASON_NO_ANSWER = 0x08;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flag indicating support for hold/unhold call feature.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int CAPABILITY_HOLD_CALL = 0x00000001;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag indicating support for joining calls feature.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public static final int CAPABILITY_JOIN_CALLS = 0x00000002;
|
|
||||||
|
|
||||||
private static final int MESSAGE_TBS_SERVICE_CONNECTED = 102;
|
|
||||||
private static final int MESSAGE_TBS_SERVICE_DISCONNECTED = 103;
|
|
||||||
|
|
||||||
private static final int REG_TIMEOUT = 10000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The template class is used to call callback functions on events from the TBS
|
|
||||||
* server. Callback functions are wrapped in this class and registered to the
|
|
||||||
* Android system during app registration.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public abstract static class Callback {
|
|
||||||
|
|
||||||
private static final String TAG = "BluetoothLeCallControl.Callback";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a remote client requested to accept the call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callId The call Id requested to be accepted
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public abstract void onAcceptCall(int requestId, @NonNull UUID callId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote client has requested to terminate the call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callId The call Id requested to terminate
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public abstract void onTerminateCall(int requestId, @NonNull UUID callId);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote client has requested to hold the call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callId The call Id requested to be put on hold
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public void onHoldCall(int requestId, @NonNull UUID callId) {
|
|
||||||
Log.e(TAG, "onHoldCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote client has requested to unhold the call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callId The call Id requested to unhold
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public void onUnholdCall(int requestId, @NonNull UUID callId) {
|
|
||||||
Log.e(TAG, "onUnholdCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote client has requested to place a call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callId The Id to be assigned for the new call
|
|
||||||
* @param uri The caller URI requested
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public abstract void onPlaceCall(int requestId, @NonNull UUID callId, @NonNull String uri);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A remote client has requested to join the calls.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An application must call {@link BluetoothLeCallControl#requestResult} to complete the
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @param requestId The Id of the request
|
|
||||||
* @param callIds The call Id list requested to join
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
public void onJoinCalls(int requestId, @NonNull List<UUID> callIds) {
|
|
||||||
Log.e(TAG, "onJoinCalls: unimplemented, however CAPABILITY_JOIN_CALLS is set!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CallbackWrapper extends IBluetoothLeCallControlCallback.Stub {
|
|
||||||
|
|
||||||
private final Executor mExecutor;
|
|
||||||
private final Callback mCallback;
|
|
||||||
|
|
||||||
CallbackWrapper(Executor executor, Callback callback) {
|
|
||||||
mExecutor = executor;
|
|
||||||
mCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBearerRegistered(int ccid) {
|
|
||||||
synchronized (mServerIfLock) {
|
|
||||||
if (mCallback != null) {
|
|
||||||
mCcid = ccid;
|
|
||||||
mServerIfLock.notifyAll();
|
|
||||||
} else {
|
|
||||||
// registration timeout
|
|
||||||
Log.e(TAG, "onBearerRegistered: mCallback is null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAcceptCall(int requestId, ParcelUuid uuid) {
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onAcceptCall(requestId, uuid.getUuid()));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTerminateCall(int requestId, ParcelUuid uuid) {
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onTerminateCall(requestId, uuid.getUuid()));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHoldCall(int requestId, ParcelUuid uuid) {
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onHoldCall(requestId, uuid.getUuid()));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUnholdCall(int requestId, ParcelUuid uuid) {
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onUnholdCall(requestId, uuid.getUuid()));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlaceCall(int requestId, ParcelUuid uuid, String uri) {
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onPlaceCall(requestId, uuid.getUuid(), uri));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onJoinCalls(int requestId, List<ParcelUuid> parcelUuids) {
|
|
||||||
List<UUID> uuids = new ArrayList<>();
|
|
||||||
for (ParcelUuid parcelUuid : parcelUuids) {
|
|
||||||
uuids.add(parcelUuid.getUuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
final long identityToken = Binder.clearCallingIdentity();
|
|
||||||
try {
|
|
||||||
mExecutor.execute(() -> mCallback.onJoinCalls(requestId, uuids));
|
|
||||||
} finally {
|
|
||||||
Binder.restoreCallingIdentity(identityToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private ServiceListener mServiceListener;
|
|
||||||
private volatile IBluetoothLeCallControl mService;
|
|
||||||
private BluetoothAdapter mAdapter;
|
|
||||||
private int mCcid = 0;
|
|
||||||
private String mToken;
|
|
||||||
private Callback mCallback = null;
|
|
||||||
private Object mServerIfLock = new Object();
|
|
||||||
|
|
||||||
private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
|
|
||||||
new IBluetoothStateChangeCallback.Stub() {
|
|
||||||
public void onBluetoothStateChange(boolean up) {
|
|
||||||
if (DBG)
|
|
||||||
Log.d(TAG, "onBluetoothStateChange: up=" + up);
|
|
||||||
if (!up) {
|
|
||||||
doUnbind();
|
|
||||||
} else {
|
|
||||||
doBind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a BluetoothLeCallControl proxy object for interacting with the local Bluetooth
|
|
||||||
* telephone bearer service.
|
|
||||||
*/
|
|
||||||
/* package */ BluetoothLeCallControl(Context context, ServiceListener listener) {
|
|
||||||
mContext = context;
|
|
||||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
||||||
mServiceListener = listener;
|
|
||||||
|
|
||||||
IBluetoothManager mgr = mAdapter.getBluetoothManager();
|
|
||||||
if (mgr != null) {
|
|
||||||
try {
|
|
||||||
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doBind();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean doBind() {
|
|
||||||
synchronized (mConnection) {
|
|
||||||
if (mService == null) {
|
|
||||||
if (VDBG)
|
|
||||||
Log.d(TAG, "Binding service...");
|
|
||||||
try {
|
|
||||||
return mAdapter.getBluetoothManager().
|
|
||||||
bindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
|
|
||||||
mConnection);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Unable to bind TelephoneBearerService", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doUnbind() {
|
|
||||||
synchronized (mConnection) {
|
|
||||||
if (mService != null) {
|
|
||||||
if (VDBG)
|
|
||||||
Log.d(TAG, "Unbinding service...");
|
|
||||||
try {
|
|
||||||
mAdapter.getBluetoothManager().
|
|
||||||
unbindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
|
|
||||||
mConnection);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "Unable to unbind TelephoneBearerService", e);
|
|
||||||
} finally {
|
|
||||||
mService = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ void close() {
|
|
||||||
if (VDBG)
|
|
||||||
log("close()");
|
|
||||||
unregisterBearer();
|
|
||||||
|
|
||||||
IBluetoothManager mgr = mAdapter.getBluetoothManager();
|
|
||||||
if (mgr != null) {
|
|
||||||
try {
|
|
||||||
mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
|
|
||||||
} catch (RemoteException re) {
|
|
||||||
Log.e(TAG, "", re);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mServiceListener = null;
|
|
||||||
doUnbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IBluetoothLeCallControl getService() {
|
|
||||||
return mService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not supported
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getConnectionState(@Nullable BluetoothDevice device) {
|
|
||||||
throw new UnsupportedOperationException("not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not supported
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public @NonNull List<BluetoothDevice> getConnectedDevices() {
|
|
||||||
throw new UnsupportedOperationException("not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not supported
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
|
|
||||||
@NonNull int[] states) {
|
|
||||||
throw new UnsupportedOperationException("not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register Telephone Bearer exposing the interface that allows remote devices
|
|
||||||
* to track and control the call states.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This is an asynchronous call. The callback is used to notify success or
|
|
||||||
* failure if the function returns true.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
|
||||||
*
|
|
||||||
* <!-- The UCI is a String identifier of the telephone bearer as defined at
|
|
||||||
* https://www.bluetooth.com/specifications/assigned-numbers/uniform-caller-identifiers
|
|
||||||
* (login required). -->
|
|
||||||
*
|
|
||||||
* <!-- The examples of common URI schemes can be found in
|
|
||||||
* https://iana.org/assignments/uri-schemes/uri-schemes.xhtml -->
|
|
||||||
*
|
|
||||||
* <!-- The Technology is an integer value. The possible values are defined at
|
|
||||||
* https://www.bluetooth.com/specifications/assigned-numbers (login required).
|
|
||||||
* -->
|
|
||||||
*
|
|
||||||
* @param uci Bearer Unique Client Identifier
|
|
||||||
* @param uriSchemes URI Schemes supported list
|
|
||||||
* @param capabilities bearer capabilities
|
|
||||||
* @param provider Network provider name
|
|
||||||
* @param technology Network technology
|
|
||||||
* @param executor {@link Executor} object on which callback will be
|
|
||||||
* executed. The Executor object is required.
|
|
||||||
* @param callback {@link Callback} object to which callback messages will
|
|
||||||
* be sent. The Callback object is required.
|
|
||||||
* @return true on success, false otherwise
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@SuppressLint("ExecutorRegistration")
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public boolean registerBearer(@Nullable String uci,
|
|
||||||
@NonNull List<String> uriSchemes, int capabilities,
|
|
||||||
@NonNull String provider, int technology,
|
|
||||||
@NonNull Executor executor, @NonNull Callback callback) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "registerBearer");
|
|
||||||
}
|
|
||||||
if (callback == null) {
|
|
||||||
throw new IllegalArgumentException("null parameter: " + callback);
|
|
||||||
}
|
|
||||||
if (mCcid != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mToken = uci;
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
synchronized (mServerIfLock) {
|
|
||||||
if (mCallback != null) {
|
|
||||||
Log.e(TAG, "Bearer can be opened only once");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mCallback = callback;
|
|
||||||
try {
|
|
||||||
CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback);
|
|
||||||
service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities,
|
|
||||||
provider, technology);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
mCallback = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mServerIfLock.wait(REG_TIMEOUT);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Log.e(TAG, "" + e);
|
|
||||||
mCallback = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCcid == 0) {
|
|
||||||
mCallback = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregister Telephone Bearer Service and destroy all the associated data.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void unregisterBearer() {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "unregisterBearer");
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ccid = mCcid;
|
|
||||||
mCcid = 0;
|
|
||||||
mCallback = null;
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.unregisterBearer(mToken);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Content Control ID (CCID) value.
|
|
||||||
*
|
|
||||||
* @return ccid Content Control ID value
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public int getContentControlId() {
|
|
||||||
return mCcid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify about the newly added call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This shall be called as early as possible after the call has been added.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
|
||||||
*
|
|
||||||
* @param call Newly added call
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void onCallAdded(@NonNull BluetoothLeCall call) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "onCallAdded: call=" + call);
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.callAdded(mCcid, call);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify about the removed call.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This shall be called as early as possible after the call has been removed.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
|
||||||
*
|
|
||||||
* @param callId The Id of a call that has been removed
|
|
||||||
* @param reason Call termination reason
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "callRemoved: callId=" + callId);
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.callRemoved(mCcid, new ParcelUuid(callId), reason);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify the call state change
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This shall be called as early as possible after the state of the call has
|
|
||||||
* changed.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
|
||||||
*
|
|
||||||
* @param callId The call Id that state has been changed
|
|
||||||
* @param state Call state
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state);
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.callStateChanged(mCcid, new ParcelUuid(callId), state);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the current calls list
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This function must be invoked after registration if application has any
|
|
||||||
* calls.
|
|
||||||
*
|
|
||||||
* @param calls current calls list
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void currentCallsList(@NonNull List<BluetoothLeCall> calls) {
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.currentCallsList(mCcid, calls);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the network current status
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This function must be invoked on change of network state.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Requires {@link android.Manifest.permission#BLUETOOTH} permission.
|
|
||||||
*
|
|
||||||
* <!-- The Technology is an integer value. The possible values are defined at
|
|
||||||
* https://www.bluetooth.com/specifications/assigned-numbers (login required).
|
|
||||||
* -->
|
|
||||||
*
|
|
||||||
* @param provider Network provider name
|
|
||||||
* @param technology Network technology
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void networkStateChanged(@NonNull String provider, int technology) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology);
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.networkStateChanged(mCcid, provider, technology);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (service == null) {
|
|
||||||
Log.w(TAG, "Proxy not attached to service");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a response to a call control request to a remote device.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This function must be invoked in when a request is received by one of these
|
|
||||||
* callback methods:
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>{@link Callback#onAcceptCall}
|
|
||||||
* <li>{@link Callback#onTerminateCall}
|
|
||||||
* <li>{@link Callback#onHoldCall}
|
|
||||||
* <li>{@link Callback#onUnholdCall}
|
|
||||||
* <li>{@link Callback#onPlaceCall}
|
|
||||||
* <li>{@link Callback#onJoinCalls}
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param requestId The ID of the request that was received with the callback
|
|
||||||
* @param result The result of the request to be sent to the remote devices
|
|
||||||
*/
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
public void requestResult(int requestId, @Result int result) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result);
|
|
||||||
}
|
|
||||||
if (mCcid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final IBluetoothLeCallControl service = getService();
|
|
||||||
if (service != null) {
|
|
||||||
try {
|
|
||||||
service.requestResult(mCcid, requestId, result);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
|
|
||||||
private static boolean isValidDevice(@Nullable BluetoothDevice device) {
|
|
||||||
return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void log(String msg) {
|
|
||||||
Log.d(TAG, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final IBluetoothProfileServiceConnection mConnection =
|
|
||||||
new IBluetoothProfileServiceConnection.Stub() {
|
|
||||||
@Override
|
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "Proxy object connected");
|
|
||||||
}
|
|
||||||
mService = IBluetoothLeCallControl.Stub.asInterface(Binder.allowBlocking(service));
|
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_CONNECTED));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServiceDisconnected(ComponentName className) {
|
|
||||||
if (DBG) {
|
|
||||||
Log.d(TAG, "Proxy object disconnected");
|
|
||||||
}
|
|
||||||
doUnbind();
|
|
||||||
mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_DISCONNECTED));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
|
|
||||||
@Override
|
|
||||||
public void handleMessage(Message msg) {
|
|
||||||
switch (msg.what) {
|
|
||||||
case MESSAGE_TBS_SERVICE_CONNECTED: {
|
|
||||||
if (mServiceListener != null) {
|
|
||||||
mServiceListener.onServiceConnected(BluetoothProfile.LE_CALL_CONTROL,
|
|
||||||
BluetoothLeCallControl.this);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MESSAGE_TBS_SERVICE_DISCONNECTED: {
|
|
||||||
if (mServiceListener != null) {
|
|
||||||
mServiceListener.onServiceDisconnected(BluetoothProfile.LE_CALL_CONTROL);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -239,20 +239,13 @@ public interface BluetoothProfile {
|
|||||||
*/
|
*/
|
||||||
int LE_AUDIO_BROADCAST = 26;
|
int LE_AUDIO_BROADCAST = 26;
|
||||||
|
|
||||||
/**
|
|
||||||
* @hide
|
|
||||||
* Telephone Bearer Service from Call Control Profile
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int LE_CALL_CONTROL = 27;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max profile ID. This value should be updated whenever a new profile is added to match
|
* Max profile ID. This value should be updated whenever a new profile is added to match
|
||||||
* the largest value assigned to a profile.
|
* the largest value assigned to a profile.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
int MAX_PROFILE_ID = 27;
|
int MAX_PROFILE_ID = 26;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default priority for devices that we try to auto-connect to and
|
* Default priority for devices that we try to auto-connect to and
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ import android.bluetooth.IBluetoothManager;
|
|||||||
import android.bluetooth.IBluetoothManagerCallback;
|
import android.bluetooth.IBluetoothManagerCallback;
|
||||||
import android.bluetooth.IBluetoothProfileServiceConnection;
|
import android.bluetooth.IBluetoothProfileServiceConnection;
|
||||||
import android.bluetooth.IBluetoothStateChangeCallback;
|
import android.bluetooth.IBluetoothStateChangeCallback;
|
||||||
import android.bluetooth.IBluetoothLeCallControl;
|
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.AttributionSource;
|
import android.content.AttributionSource;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@@ -1329,15 +1328,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
|
|||||||
+ bluetoothProfile);
|
+ bluetoothProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent;
|
if (bluetoothProfile != BluetoothProfile.HEADSET) {
|
||||||
if (bluetoothProfile == BluetoothProfile.HEADSET) {
|
|
||||||
intent = new Intent(IBluetoothHeadset.class.getName());
|
|
||||||
} else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) {
|
|
||||||
intent = new Intent(IBluetoothLeCallControl.class.getName());
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent(IBluetoothHeadset.class.getName());
|
||||||
psc = new ProfileServiceConnections(intent);
|
psc = new ProfileServiceConnections(intent);
|
||||||
if (!psc.bindService()) {
|
if (!psc.bindService()) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user