summaryrefslogtreecommitdiff
path: root/framework/java/android/bluetooth/BluetoothVolumeControl.java
diff options
context:
space:
mode:
authorƁukasz Rymanowski <lukasz.rymanowski@codecoup.pl>2021-01-26 06:39:08 +0000
committerJakub Pawlowski <jpawlowski@google.com>2021-06-14 15:18:05 +0000
commit1b3ac7733b50556d440ec8a5453645c074301c7b (patch)
tree0638793b219bdef08ff5bec3b939fff24a6b4563 /framework/java/android/bluetooth/BluetoothVolumeControl.java
parent0a67fabedbf8f985ba2c7b85591213a3f053590a (diff)
Bluetooth: add Volume Control Profile boilerpalate
This is very simple API to allow Android to connect VCP profile. Bug: 150670922 Test: compilation Sponsor: jpawlowski@ CTS-Coverage-Bug: 190833351 Change-Id: Ib20d967fcf6797077abf83b40b0eda526e5ab89d Merged-In: Ib20d967fcf6797077abf83b40b0eda526e5ab89d
Diffstat (limited to 'framework/java/android/bluetooth/BluetoothVolumeControl.java')
-rw-r--r--framework/java/android/bluetooth/BluetoothVolumeControl.java320
1 files changed, 320 insertions, 0 deletions
diff --git a/framework/java/android/bluetooth/BluetoothVolumeControl.java b/framework/java/android/bluetooth/BluetoothVolumeControl.java
new file mode 100644
index 0000000000..4eb28ad399
--- /dev/null
+++ b/framework/java/android/bluetooth/BluetoothVolumeControl.java
@@ -0,0 +1,320 @@
+/*
+ * 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.Manifest;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.CloseGuard;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides the public APIs to control the Bluetooth Volume Control service.
+ *
+ * <p>BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC
+ * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
+ * the BluetoothVolumeControl proxy object.
+ * @hide
+ */
+@SystemApi
+public final class BluetoothVolumeControl implements BluetoothProfile, AutoCloseable {
+ private static final String TAG = "BluetoothVolumeControl";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
+
+ private CloseGuard mCloseGuard;
+
+ /**
+ * Intent used to broadcast the change in connection state of the Volume Control
+ * profile.
+ *
+ * <p>This intent will have 3 extras:
+ * <ul>
+ * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
+ * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
+ * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * </ul>
+ *
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
+ * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
+ * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @SuppressLint("ActionValue")
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CONNECTION_STATE_CHANGED =
+ "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED";
+
+ private BluetoothAdapter mAdapter;
+ private final BluetoothProfileConnector<IBluetoothVolumeControl> mProfileConnector =
+ new BluetoothProfileConnector(this, BluetoothProfile.VOLUME_CONTROL, TAG,
+ IBluetoothVolumeControl.class.getName()) {
+ @Override
+ public IBluetoothVolumeControl getServiceInterface(IBinder service) {
+ return IBluetoothVolumeControl.Stub.asInterface(Binder.allowBlocking(service));
+ }
+ };
+
+ /**
+ * Create a BluetoothVolumeControl proxy object for interacting with the local
+ * Bluetooth Volume Control service.
+ */
+ /*package*/ BluetoothVolumeControl(Context context, ServiceListener listener,
+ BluetoothAdapter adapter) {
+ mAdapter = adapter;
+ mProfileConnector.connect(context, listener);
+ mCloseGuard = new CloseGuard();
+ mCloseGuard.open("close");
+ }
+
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /*package*/
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void close() {
+ mProfileConnector.disconnect();
+ }
+
+ private IBluetoothVolumeControl getService() { return mProfileConnector.getService(); }
+
+ /**
+ * Get the list of connected devices. Currently at most one.
+ *
+ * @return list of connected devices
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @NonNull List<BluetoothDevice> getConnectedDevices() {
+ if (DBG) log("getConnectedDevices()");
+ final IBluetoothVolumeControl service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getConnectedDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Get the list of devices matching specified states. Currently at most one.
+ *
+ * @return list of matching devices
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
+ if (DBG) log("getDevicesMatchingStates()");
+ final IBluetoothVolumeControl service = getService();
+ if (service != null && isEnabled()) {
+ try {
+ return service.getDevicesMatchingConnectionStates(states);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return new ArrayList<BluetoothDevice>();
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return new ArrayList<BluetoothDevice>();
+ }
+
+ /**
+ * Get connection state of device
+ *
+ * @return device connection state
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public int getConnectionState(BluetoothDevice device) {
+ if (DBG) log("getConnectionState(" + device + ")");
+ final IBluetoothVolumeControl service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.getConnectionState(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.STATE_DISCONNECTED;
+ }
+
+ /**
+ * Tells remote device to set an absolute volume.
+ *
+ * @param volume Absolute volume to be set on remote device.
+ * Minimum value is 0 and maximum value is 255
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public void setVolume(@Nullable BluetoothDevice device,
+ @IntRange(from = 0, to = 255) int volume) {
+ if (DBG)
+ log("setVolume(" + volume + ")");
+ final IBluetoothVolumeControl service = getService();
+ try {
+ if (service != null && isEnabled()) {
+ service.setVolume(device, volume);
+ return;
+ }
+ if (service == null)
+ Log.w(TAG, "Proxy not attached to service");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ }
+ }
+
+ /**
+ * Set priority of the profile
+ *
+ * <p> The device should already be paired.
+ * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
+ *
+ * @param device Paired bluetooth device
+ * @param priority
+ * @return true if priority is set, false on error
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setPriority(BluetoothDevice device, int priority) {
+ if (DBG) log("setPriority(" + device + ", " + priority + ")");
+ return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
+ }
+
+ /**
+ * Set connection policy of the profile
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if connectionPolicy is set, false on error
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
+ if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ final IBluetoothVolumeControl service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ try {
+ return service.setConnectionPolicy(device, connectionPolicy);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ }
+
+ /**
+ * Get the priority of the profile.
+ *
+ * <p> The priority can be any of:
+ * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
+ *
+ * @param device Bluetooth device
+ * @return priority of the device
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public int getPriority(BluetoothDevice device) {
+ if (VDBG) log("getPriority(" + device + ")");
+ return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
+ }
+
+ /**
+ * Get the connection policy of the profile.
+ *
+ * <p> The connection policy can be any of:
+ * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
+ * {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Bluetooth device
+ * @return connection policy of the device
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
+ if (VDBG) log("getConnectionPolicy(" + device + ")");
+ final IBluetoothVolumeControl service = getService();
+ if (service != null && isEnabled() && isValidDevice(device)) {
+ try {
+ return service.getConnectionPolicy(device);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
+ }
+
+ private boolean isEnabled() {
+ return mAdapter.getState() == BluetoothAdapter.STATE_ON;
+ }
+
+ private static boolean isValidDevice(@Nullable BluetoothDevice device) {
+ return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
+ }
+
+ private static void log(String msg) {
+ Log.d(TAG, msg);
+ }
+}