blob: 1fe1b10005cf96b47a127c1aca67b41a0233f7a2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.bluetooth;
18
Tor Norbye2d497522015-04-23 17:10:21 -070019import android.Manifest;
Pavlin Radoslavov64a94352017-12-19 13:20:06 -080020import android.annotation.Nullable;
Tor Norbye2d497522015-04-23 17:10:21 -070021import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Mathew Inwood4dc66d32018-08-01 15:07:20 +010024import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060026import android.os.Binder;
Mathew Inwood8c854f82018-09-14 12:35:36 +010027import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070029import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070030import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.util.Log;
32
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070033import java.util.ArrayList;
34import java.util.List;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
37/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070038 * This class provides the public APIs to control the Bluetooth A2DP
39 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 *
Jack Hea355e5e2017-08-22 16:06:54 -070041 * <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070042 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
43 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070045 * <p> Android only supports one connected Bluetooth A2dp device at a time.
46 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070048public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080050 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070051 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070053 /**
54 * Intent used to broadcast the change in connection state of the A2DP
55 * profile.
56 *
57 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080058 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070059 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
60 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
61 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080062 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070063 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080064 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070065 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
66 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
67 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080068 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
69 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 */
71 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070072 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070073 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070075 /**
76 * Intent used to broadcast the change in the Playing state of the A2DP
77 * profile.
78 *
79 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080080 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070081 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
82 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
83 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080084 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070085 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080086 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070087 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
88 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080089 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
90 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070091 */
92 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
93 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070094 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
Hemant Gupta3b76a4b2014-02-14 19:53:31 +053096 /** @hide */
97 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
98 public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070099 "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530100
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700101 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800102 * Intent used to broadcast the selection of a connected device as active.
103 *
104 * <p>This intent will have one extra:
105 * <ul>
106 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
107 * be null if no device is active. </li>
108 * </ul>
109 *
110 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
111 * receive.
112 *
113 * @hide
114 */
115 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100116 @UnsupportedAppUsage
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800117 public static final String ACTION_ACTIVE_DEVICE_CHANGED =
118 "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
119
120 /**
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800121 * Intent used to broadcast the change in the Audio Codec state of the
122 * A2DP Source profile.
123 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800124 * <p>This intent will have 2 extras:
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800125 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700126 * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
127 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
128 * connected, otherwise it is not included.</li>
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800129 * </ul>
130 *
131 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
132 * receive.
133 *
134 * @hide
135 */
136 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100137 @UnsupportedAppUsage
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800138 public static final String ACTION_CODEC_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700139 "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800140
141 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700142 * A2DP sink device is streaming music. This state can be one of
143 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
144 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
145 */
Jack Hea355e5e2017-08-22 16:06:54 -0700146 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -0700147
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700148 /**
149 * A2DP sink device is NOT streaming music. This state can be one of
150 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
151 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
152 */
Jack Hea355e5e2017-08-22 16:06:54 -0700153 public static final int STATE_NOT_PLAYING = 11;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700154
Antony Sargentf5772c62017-04-26 16:37:53 -0700155 /**
156 * We don't have a stored preference for whether or not the given A2DP sink device supports
157 * optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700158 *
159 * @hide
160 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100161 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700162 public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
163
164 /**
165 * The given A2DP sink device does not support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700166 *
167 * @hide
168 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100169 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700170 public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
171
172 /**
173 * The given A2DP sink device does support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700174 *
175 * @hide
176 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100177 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700178 public static final int OPTIONAL_CODECS_SUPPORTED = 1;
179
180 /**
181 * We don't have a stored preference for whether optional codecs should be enabled or disabled
182 * for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700183 *
184 * @hide
185 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100186 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700187 public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
188
189 /**
190 * Optional codecs should be disabled for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700191 *
192 * @hide
193 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100194 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700195 public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
196
197 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700198 * Optional codecs should be enabled for the given A2DP device.
199 *
200 * @hide
201 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100202 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700203 public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
204
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700205 private BluetoothAdapter mAdapter;
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800206 private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
207 new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
208 IBluetoothA2dp.class.getName()) {
209 @Override
210 public IBluetoothA2dp getServiceInterface(IBinder service) {
211 return IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
fredc0f420372012-04-12 00:02:00 -0700212 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800213 };
Jack Hea355e5e2017-08-22 16:06:54 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 /**
216 * Create a BluetoothA2dp proxy object for interacting with the local
217 * Bluetooth A2DP service.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 */
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800219 /*package*/ BluetoothA2dp(Context context, ServiceListener listener) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700220 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800221 mProfileConnector.connect(context, listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 }
223
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100224 @UnsupportedAppUsage
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800225 /*package*/ void close() {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800226 mProfileConnector.disconnect();
227 }
fredc0f420372012-04-12 00:02:00 -0700228
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800229 private IBluetoothA2dp getService() {
230 return mProfileConnector.getService();
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800231 }
232
Jack He2992cd02017-08-22 21:21:23 -0700233 @Override
fredc0f420372012-04-12 00:02:00 -0700234 public void finalize() {
Mathias Jeppsson2d2d8c22013-08-06 11:41:55 +0200235 // The empty finalize needs to be kept or the
236 // cts signature tests would fail.
fredc0f420372012-04-12 00:02:00 -0700237 }
Jack Hea355e5e2017-08-22 16:06:54 -0700238
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700239 /**
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800240 * Initiate connection to a profile of the remote Bluetooth device.
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700241 *
242 * <p> This API returns false in scenarios like the profile on the
243 * device is already connected or Bluetooth is not turned on.
244 * When this API returns true, it is guaranteed that
245 * connection state intent for the profile will be broadcasted with
246 * the state. Users can get the connection state of the profile
247 * from this intent.
248 *
249 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
250 * permission.
251 *
252 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700253 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700254 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100256 @UnsupportedAppUsage
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700257 public boolean connect(BluetoothDevice device) {
258 if (DBG) log("connect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700259 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800260 final IBluetoothA2dp service = getService();
261 if (service != null && isEnabled() && isValidDevice(device)) {
262 return service.connect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700263 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800264 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700265 return false;
266 } catch (RemoteException e) {
267 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
268 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 }
270 }
271
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700272 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700273 * Initiate disconnection from a profile
274 *
275 * <p> This API will return false in scenarios like the profile on the
276 * Bluetooth device is not in connected state etc. When this API returns,
277 * true, it is guaranteed that the connection state change
278 * intent will be broadcasted with the state. Users can get the
279 * disconnection state of the profile from this intent.
280 *
281 * <p> If the disconnection is initiated by a remote device, the state
282 * will transition from {@link #STATE_CONNECTED} to
283 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
284 * host (local) device the state will transition from
285 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
286 * state {@link #STATE_DISCONNECTED}. The transition to
287 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
288 * two scenarios.
289 *
290 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
291 * permission.
292 *
293 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700294 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700295 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100297 @UnsupportedAppUsage
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700298 public boolean disconnect(BluetoothDevice device) {
299 if (DBG) log("disconnect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700300 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800301 final IBluetoothA2dp service = getService();
302 if (service != null && isEnabled() && isValidDevice(device)) {
303 return service.disconnect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700304 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800305 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700306 return false;
307 } catch (RemoteException e) {
308 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
309 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 }
311 }
312
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700313 /**
314 * {@inheritDoc}
315 */
Jack He2992cd02017-08-22 21:21:23 -0700316 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700317 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700318 if (VDBG) log("getConnectedDevices()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700319 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800320 final IBluetoothA2dp service = getService();
321 if (service != null && isEnabled()) {
322 return service.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700323 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800324 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700325 return new ArrayList<BluetoothDevice>();
326 } catch (RemoteException e) {
327 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
328 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700329 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700330 }
331
332 /**
333 * {@inheritDoc}
334 */
Jack He2992cd02017-08-22 21:21:23 -0700335 @Override
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700336 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700337 if (VDBG) log("getDevicesMatchingStates()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700338 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800339 final IBluetoothA2dp service = getService();
340 if (service != null && isEnabled()) {
341 return service.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700342 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800343 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700344 return new ArrayList<BluetoothDevice>();
345 } catch (RemoteException e) {
346 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
347 return new ArrayList<BluetoothDevice>();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700348 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700349 }
350
351 /**
352 * {@inheritDoc}
353 */
Jack He2992cd02017-08-22 21:21:23 -0700354 @Override
Jean-Michel Trivi58850372018-09-14 16:01:28 -0700355 public @BtProfileState int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700356 if (VDBG) log("getState(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700357 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800358 final IBluetoothA2dp service = getService();
359 if (service != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700360 && isValidDevice(device)) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800361 return service.getConnectionState(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700362 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800363 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700364 return BluetoothProfile.STATE_DISCONNECTED;
365 } catch (RemoteException e) {
366 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
367 return BluetoothProfile.STATE_DISCONNECTED;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700368 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700369 }
370
371 /**
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800372 * Select a connected device as active.
373 *
374 * The active device selection is per profile. An active device's
375 * purpose is profile-specific. For example, A2DP audio streaming
376 * is to the active A2DP Sink device. If a remote device is not
377 * connected, it cannot be selected as active.
378 *
379 * <p> This API returns false in scenarios like the profile on the
380 * device is not connected or Bluetooth is not turned on.
381 * When this API returns true, it is guaranteed that the
382 * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
383 * with the active device.
384 *
385 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
386 * permission.
387 *
388 * @param device the remote Bluetooth device. Could be null to clear
389 * the active device and stop streaming audio to a Bluetooth device.
390 * @return false on immediate error, true otherwise
391 * @hide
392 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100393 @UnsupportedAppUsage
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800394 public boolean setActiveDevice(@Nullable BluetoothDevice device) {
395 if (DBG) log("setActiveDevice(" + device + ")");
396 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800397 final IBluetoothA2dp service = getService();
398 if (service != null && isEnabled()
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800399 && ((device == null) || isValidDevice(device))) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800400 return service.setActiveDevice(device);
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800401 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800402 if (service == null) Log.w(TAG, "Proxy not attached to service");
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800403 return false;
404 } catch (RemoteException e) {
405 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
406 return false;
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800407 }
408 }
409
410 /**
411 * Get the connected device that is active.
412 *
413 * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
414 * permission.
415 *
416 * @return the connected device that is active or null if no device
417 * is active
418 * @hide
419 */
420 @RequiresPermission(Manifest.permission.BLUETOOTH)
421 @Nullable
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100422 @UnsupportedAppUsage
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800423 public BluetoothDevice getActiveDevice() {
424 if (VDBG) log("getActiveDevice()");
425 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800426 final IBluetoothA2dp service = getService();
427 if (service != null && isEnabled()) {
428 return service.getActiveDevice();
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800429 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800430 if (service == null) Log.w(TAG, "Proxy not attached to service");
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800431 return null;
432 } catch (RemoteException e) {
433 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
434 return null;
Pavlin Radoslavov64a94352017-12-19 13:20:06 -0800435 }
436 }
437
438 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700439 * Set priority of the profile
440 *
441 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700442 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700443 * {@link #PRIORITY_OFF},
444 *
445 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
446 * permission.
447 *
448 * @param device Paired bluetooth device
449 * @param priority
450 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700451 * @hide
452 */
453 public boolean setPriority(BluetoothDevice device, int priority) {
454 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700455 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800456 final IBluetoothA2dp service = getService();
457 if (service != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700458 && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700459 if (priority != BluetoothProfile.PRIORITY_OFF
460 && priority != BluetoothProfile.PRIORITY_ON) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700461 return false;
462 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800463 return service.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700464 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800465 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700466 return false;
467 } catch (RemoteException e) {
468 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
469 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700470 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700471 }
472
473 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700474 * Get the priority of the profile.
475 *
476 * <p> The priority can be any of:
477 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
478 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
479 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700480 * @param device Bluetooth device
481 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700482 * @hide
483 */
Tor Norbye2d497522015-04-23 17:10:21 -0700484 @RequiresPermission(Manifest.permission.BLUETOOTH)
Mathew Inwood8c854f82018-09-14 12:35:36 +0100485 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700486 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700487 if (VDBG) log("getPriority(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700488 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800489 final IBluetoothA2dp service = getService();
490 if (service != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700491 && isValidDevice(device)) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800492 return service.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700493 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800494 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700495 return BluetoothProfile.PRIORITY_OFF;
496 } catch (RemoteException e) {
497 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
498 return BluetoothProfile.PRIORITY_OFF;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700499 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700500 }
501
502 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700503 * Checks if Avrcp device supports the absolute volume feature.
504 *
505 * @return true if device supports absolute volume
506 * @hide
507 */
508 public boolean isAvrcpAbsoluteVolumeSupported() {
509 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
Calvin Ond7d16b92016-06-20 15:59:48 -0700510 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800511 final IBluetoothA2dp service = getService();
512 if (service != null && isEnabled()) {
513 return service.isAvrcpAbsoluteVolumeSupported();
John Du5a0cf7a2013-07-19 11:30:34 -0700514 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800515 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700516 return false;
517 } catch (RemoteException e) {
518 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
519 return false;
John Du5a0cf7a2013-07-19 11:30:34 -0700520 }
John Du5a0cf7a2013-07-19 11:30:34 -0700521 }
522
523 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700524 * Tells remote device to set an absolute volume. Only if absolute volume is supported
525 *
526 * @param volume Absolute volume to be set on AVRCP side
527 * @hide
528 */
529 public void setAvrcpAbsoluteVolume(int volume) {
530 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700531 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800532 final IBluetoothA2dp service = getService();
533 if (service != null && isEnabled()) {
534 service.setAvrcpAbsoluteVolume(volume);
John Du5a0cf7a2013-07-19 11:30:34 -0700535 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800536 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700537 } catch (RemoteException e) {
538 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
John Du5a0cf7a2013-07-19 11:30:34 -0700539 }
John Du5a0cf7a2013-07-19 11:30:34 -0700540 }
541
542 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700543 * Check if A2DP profile is streaming music.
544 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800545 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700546 *
547 * @param device BluetoothDevice device
548 */
549 public boolean isA2dpPlaying(BluetoothDevice device) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700550 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800551 final IBluetoothA2dp service = getService();
552 if (service != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700553 && isValidDevice(device)) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800554 return service.isA2dpPlaying(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700555 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800556 if (service == null) Log.w(TAG, "Proxy not attached to service");
Calvin Ond7d16b92016-06-20 15:59:48 -0700557 return false;
558 } catch (RemoteException e) {
559 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
560 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700561 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700562 }
563
564 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700565 * This function checks if the remote device is an AVCRP
566 * target and thus whether we should send volume keys
567 * changes or not.
Jack Hea355e5e2017-08-22 16:06:54 -0700568 *
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700569 * @hide
570 */
571 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
572 if (isEnabled() && isValidDevice(device)) {
573 ParcelUuid[] uuids = device.getUuids();
574 if (uuids == null) return false;
575
Jack Hea355e5e2017-08-22 16:06:54 -0700576 for (ParcelUuid uuid : uuids) {
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700577 if (BluetoothUuid.isAvrcpTarget(uuid)) {
578 return true;
579 }
580 }
581 }
582 return false;
583 }
584
Matthew Xiea0c68032011-06-25 21:47:07 -0700585 /**
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800586 * Gets the current codec status (configuration and capability).
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800587 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800588 * @param device the remote Bluetooth device. If null, use the current
589 * active A2DP Bluetooth device.
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800590 * @return the current codec status
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800591 * @hide
592 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100593 @UnsupportedAppUsage
Jean-Michel Trivi58850372018-09-14 16:01:28 -0700594 public @Nullable BluetoothCodecStatus getCodecStatus(BluetoothDevice device) {
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800595 if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800596 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800597 final IBluetoothA2dp service = getService();
598 if (service != null && isEnabled()) {
599 return service.getCodecStatus(device);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800600 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800601 if (service == null) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800602 Log.w(TAG, "Proxy not attached to service");
603 }
604 return null;
605 } catch (RemoteException e) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800606 Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800607 return null;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800608 }
609 }
610
611 /**
612 * Sets the codec configuration preference.
613 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800614 * @param device the remote Bluetooth device. If null, use the current
615 * active A2DP Bluetooth device.
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800616 * @param codecConfig the codec configuration preference
617 * @hide
618 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100619 @UnsupportedAppUsage
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800620 public void setCodecConfigPreference(BluetoothDevice device,
621 BluetoothCodecConfig codecConfig) {
622 if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800623 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800624 final IBluetoothA2dp service = getService();
625 if (service != null && isEnabled()) {
626 service.setCodecConfigPreference(device, codecConfig);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800627 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800628 if (service == null) Log.w(TAG, "Proxy not attached to service");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800629 return;
630 } catch (RemoteException e) {
631 Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
632 return;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800633 }
634 }
635
636 /**
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800637 * Enables the optional codecs.
638 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800639 * @param device the remote Bluetooth device. If null, use the currect
640 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800641 * @hide
642 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100643 @UnsupportedAppUsage
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800644 public void enableOptionalCodecs(BluetoothDevice device) {
645 if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
646 enableDisableOptionalCodecs(device, true);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800647 }
648
649 /**
650 * Disables the optional codecs.
651 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800652 * @param device the remote Bluetooth device. If null, use the currect
653 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800654 * @hide
655 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100656 @UnsupportedAppUsage
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800657 public void disableOptionalCodecs(BluetoothDevice device) {
658 if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
659 enableDisableOptionalCodecs(device, false);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800660 }
661
662 /**
663 * Enables or disables the optional codecs.
664 *
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800665 * @param device the remote Bluetooth device. If null, use the currect
666 * active A2DP Bluetooth device.
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800667 * @param enable if true, enable the optional codecs, other disable them
668 */
Pavlin Radoslavov502af212018-01-03 19:38:39 -0800669 private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800670 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800671 final IBluetoothA2dp service = getService();
672 if (service != null && isEnabled()) {
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800673 if (enable) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800674 service.enableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800675 } else {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800676 service.disableOptionalCodecs(device);
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800677 }
678 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800679 if (service == null) Log.w(TAG, "Proxy not attached to service");
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800680 return;
681 } catch (RemoteException e) {
682 Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
683 return;
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800684 }
685 }
686
687 /**
Antony Sargentf5772c62017-04-26 16:37:53 -0700688 * Returns whether this device supports optional codecs.
689 *
690 * @param device The device to check
691 * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700692 * OPTIONAL_CODECS_SUPPORTED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700693 * @hide
694 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100695 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700696 public int supportsOptionalCodecs(BluetoothDevice device) {
697 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800698 final IBluetoothA2dp service = getService();
699 if (service != null && isEnabled() && isValidDevice(device)) {
700 return service.supportsOptionalCodecs(device);
Antony Sargentf5772c62017-04-26 16:37:53 -0700701 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800702 if (service == null) Log.w(TAG, "Proxy not attached to service");
Antony Sargentf5772c62017-04-26 16:37:53 -0700703 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
704 } catch (RemoteException e) {
705 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
706 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
Antony Sargentf5772c62017-04-26 16:37:53 -0700707 }
708 }
709
710 /**
711 * Returns whether this device should have optional codecs enabled.
712 *
713 * @param device The device in question.
714 * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700715 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700716 * @hide
717 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100718 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700719 public int getOptionalCodecsEnabled(BluetoothDevice device) {
720 try {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800721 final IBluetoothA2dp service = getService();
722 if (service != null && isEnabled() && isValidDevice(device)) {
723 return service.getOptionalCodecsEnabled(device);
Antony Sargentf5772c62017-04-26 16:37:53 -0700724 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800725 if (service == null) Log.w(TAG, "Proxy not attached to service");
Antony Sargentf5772c62017-04-26 16:37:53 -0700726 return OPTIONAL_CODECS_PREF_UNKNOWN;
727 } catch (RemoteException e) {
728 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
729 return OPTIONAL_CODECS_PREF_UNKNOWN;
Antony Sargentf5772c62017-04-26 16:37:53 -0700730 }
731 }
732
733 /**
734 * Sets a persistent preference for whether a given device should have optional codecs enabled.
735 *
736 * @param device The device to set this preference for.
737 * @param value Whether the optional codecs should be enabled for this device. This should be
Jack Hea355e5e2017-08-22 16:06:54 -0700738 * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
739 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700740 * @hide
741 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100742 @UnsupportedAppUsage
Antony Sargentf5772c62017-04-26 16:37:53 -0700743 public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
744 try {
Jack He2992cd02017-08-22 21:21:23 -0700745 if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
746 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
747 && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
Antony Sargentf5772c62017-04-26 16:37:53 -0700748 Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
749 return;
750 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800751 final IBluetoothA2dp service = getService();
752 if (service != null && isEnabled()
Antony Sargentf5772c62017-04-26 16:37:53 -0700753 && isValidDevice(device)) {
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800754 service.setOptionalCodecsEnabled(device, value);
Antony Sargentf5772c62017-04-26 16:37:53 -0700755 }
Ugo Yu6d9cfce2019-03-26 21:38:08 +0800756 if (service == null) Log.w(TAG, "Proxy not attached to service");
Antony Sargentf5772c62017-04-26 16:37:53 -0700757 return;
758 } catch (RemoteException e) {
759 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
760 return;
Antony Sargentf5772c62017-04-26 16:37:53 -0700761 }
762 }
763
764 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700765 * Helper for converting a state to a string.
766 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700768 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 * @hide
770 */
Mathew Inwood31755f92018-12-20 13:53:36 +0000771 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 public static String stateToString(int state) {
773 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700774 case STATE_DISCONNECTED:
775 return "disconnected";
776 case STATE_CONNECTING:
777 return "connecting";
778 case STATE_CONNECTED:
779 return "connected";
780 case STATE_DISCONNECTING:
781 return "disconnecting";
782 case STATE_PLAYING:
783 return "playing";
784 case STATE_NOT_PLAYING:
785 return "not playing";
786 default:
787 return "<unknown state " + state + ">";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 }
789 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800790
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700791 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700792 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
793 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700794 }
795
796 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700797 if (device == null) return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700798
Jack Hea355e5e2017-08-22 16:06:54 -0700799 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
800 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700801 }
802
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800803 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700804 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800805 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806}