blob: 7d6879d5a615c810132e7fdf03da0acc5fd179c8 [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;
20import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080023import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
Matthew Xie3e8c82e2012-02-16 16:57:18 -080025import android.content.Intent;
26import android.content.ServiceConnection;
RoboErik4197cb62015-01-21 15:45:32 -080027import android.media.AudioManager;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060028import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.IBinder;
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -070030import android.os.ParcelUuid;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070031import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.util.Log;
33
Calvin Ond7d16b92016-06-20 15:59:48 -070034import com.android.internal.annotations.GuardedBy;
35
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -070036import java.util.ArrayList;
37import java.util.List;
Calvin Ond7d16b92016-06-20 15:59:48 -070038import java.util.concurrent.locks.ReentrantReadWriteLock;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040
41/**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070042 * This class provides the public APIs to control the Bluetooth A2DP
43 * profile.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 *
Jack Hea355e5e2017-08-22 16:06:54 -070045 * <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070046 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
47 * the BluetoothA2dp proxy object.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048 *
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070049 * <p> Android only supports one connected Bluetooth A2dp device at a time.
50 * Each method is protected with its appropriate permission.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070052public final class BluetoothA2dp implements BluetoothProfile {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 private static final String TAG = "BluetoothA2dp";
Matthew Xie3e8c82e2012-02-16 16:57:18 -080054 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070055 private static final boolean VDBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070057 /**
58 * Intent used to broadcast the change in connection state of the A2DP
59 * profile.
60 *
61 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080062 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070063 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
64 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
65 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080066 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070067 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080068 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070069 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
70 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
71 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080072 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
73 * receive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 */
75 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070076 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070077 "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070079 /**
80 * Intent used to broadcast the change in the Playing state of the A2DP
81 * profile.
82 *
83 * <p>This intent will have 3 extras:
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080084 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070085 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
86 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
87 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080088 * </ul>
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070089 *
Jaikumar Ganesh0706fed2011-01-26 11:46:56 -080090 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070091 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
92 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -080093 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
94 * receive.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -070095 */
96 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
97 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070098 "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530100 /** @hide */
101 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102 public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700103 "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
Hemant Gupta3b76a4b2014-02-14 19:53:31 +0530104
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700105 /**
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800106 * Intent used to broadcast the change in the Audio Codec state of the
107 * A2DP Source profile.
108 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800109 * <p>This intent will have 2 extras:
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800110 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700111 * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
112 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
113 * connected, otherwise it is not included.</li>
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800114 * </ul>
115 *
116 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
117 * receive.
118 *
119 * @hide
120 */
121 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
122 public static final String ACTION_CODEC_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700123 "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800124
125 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700126 * A2DP sink device is streaming music. This state can be one of
127 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
128 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
129 */
Jack Hea355e5e2017-08-22 16:06:54 -0700130 public static final int STATE_PLAYING = 10;
Nick Pellybd022f42009-08-14 18:33:38 -0700131
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700132 /**
133 * A2DP sink device is NOT streaming music. This state can be one of
134 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
135 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
136 */
Jack Hea355e5e2017-08-22 16:06:54 -0700137 public static final int STATE_NOT_PLAYING = 11;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700138
Antony Sargentf5772c62017-04-26 16:37:53 -0700139 /**
140 * We don't have a stored preference for whether or not the given A2DP sink device supports
141 * optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700142 *
143 * @hide
144 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700145 public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
146
147 /**
148 * The given A2DP sink device does not support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700149 *
150 * @hide
151 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700152 public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
153
154 /**
155 * The given A2DP sink device does support optional codecs.
Jack Hea355e5e2017-08-22 16:06:54 -0700156 *
157 * @hide
158 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700159 public static final int OPTIONAL_CODECS_SUPPORTED = 1;
160
161 /**
162 * We don't have a stored preference for whether optional codecs should be enabled or disabled
163 * for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700164 *
165 * @hide
166 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700167 public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
168
169 /**
170 * Optional codecs should be disabled for the given A2DP device.
Jack Hea355e5e2017-08-22 16:06:54 -0700171 *
172 * @hide
173 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700174 public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
175
176 /**
Jack Hea355e5e2017-08-22 16:06:54 -0700177 * Optional codecs should be enabled for the given A2DP device.
178 *
179 * @hide
180 */
Antony Sargentf5772c62017-04-26 16:37:53 -0700181 public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
182
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800183 private Context mContext;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700184 private ServiceListener mServiceListener;
Calvin Ond7d16b92016-06-20 15:59:48 -0700185 private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
Jack Hea355e5e2017-08-22 16:06:54 -0700186 @GuardedBy("mServiceLock")
187 private IBluetoothA2dp mService;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700188 private BluetoothAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
fredc0f420372012-04-12 00:02:00 -0700190 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
191 new IBluetoothStateChangeCallback.Stub() {
192 public void onBluetoothStateChange(boolean up) {
193 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
194 if (!up) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700195 if (VDBG) Log.d(TAG, "Unbinding service...");
196 try {
197 mServiceLock.writeLock().lock();
198 mService = null;
199 mContext.unbindService(mConnection);
200 } catch (Exception re) {
201 Log.e(TAG, "", re);
202 } finally {
203 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700204 }
205 } else {
Calvin Ond7d16b92016-06-20 15:59:48 -0700206 try {
207 mServiceLock.readLock().lock();
208 if (mService == null) {
Jack Hea355e5e2017-08-22 16:06:54 -0700209 if (VDBG) Log.d(TAG, "Binding service...");
Calvin Ond7d16b92016-06-20 15:59:48 -0700210 doBind();
fredc0f420372012-04-12 00:02:00 -0700211 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700212 } catch (Exception re) {
Jack Hea355e5e2017-08-22 16:06:54 -0700213 Log.e(TAG, "", re);
Calvin Ond7d16b92016-06-20 15:59:48 -0700214 } finally {
215 mServiceLock.readLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700216 }
217 }
218 }
Jack Hea355e5e2017-08-22 16:06:54 -0700219 };
220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 /**
222 * Create a BluetoothA2dp proxy object for interacting with the local
223 * Bluetooth A2DP service.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 */
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800225 /*package*/ BluetoothA2dp(Context context, ServiceListener l) {
226 mContext = context;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700227 mServiceListener = l;
228 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700229 IBluetoothManager mgr = mAdapter.getBluetoothManager();
230 if (mgr != null) {
231 try {
232 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
233 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700234 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700235 }
236 }
237
Dianne Hackborn221ea892013-08-04 16:50:16 -0700238 doBind();
239 }
240
241 boolean doBind() {
242 Intent intent = new Intent(IBluetoothA2dp.class.getName());
243 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
244 intent.setComponent(comp);
Dianne Hackborn466ce962014-03-19 18:06:58 -0700245 if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
246 android.os.Process.myUserHandle())) {
Dianne Hackborn221ea892013-08-04 16:50:16 -0700247 Log.e(TAG, "Could not bind to Bluetooth A2DP Service with " + intent);
248 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700250 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 }
252
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800253 /*package*/ void close() {
254 mServiceListener = null;
fredc0f420372012-04-12 00:02:00 -0700255 IBluetoothManager mgr = mAdapter.getBluetoothManager();
256 if (mgr != null) {
257 try {
258 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
259 } catch (Exception e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700260 Log.e(TAG, "", e);
fredc0f420372012-04-12 00:02:00 -0700261 }
262 }
263
Calvin Ond7d16b92016-06-20 15:59:48 -0700264 try {
265 mServiceLock.writeLock().lock();
fredc0f420372012-04-12 00:02:00 -0700266 if (mService != null) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700267 mService = null;
268 mContext.unbindService(mConnection);
fredc0f420372012-04-12 00:02:00 -0700269 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700270 } catch (Exception re) {
271 Log.e(TAG, "", re);
272 } finally {
273 mServiceLock.writeLock().unlock();
fredc0f420372012-04-12 00:02:00 -0700274 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800275 }
276
fredc0f420372012-04-12 00:02:00 -0700277 public void finalize() {
Mathias Jeppsson2d2d8c22013-08-06 11:41:55 +0200278 // The empty finalize needs to be kept or the
279 // cts signature tests would fail.
fredc0f420372012-04-12 00:02:00 -0700280 }
Jack Hea355e5e2017-08-22 16:06:54 -0700281
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700282 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700283 * Initiate connection to a profile of the remote bluetooth device.
284 *
285 * <p> Currently, the system supports only 1 connection to the
286 * A2DP profile. The API will automatically disconnect connected
287 * devices before connecting.
288 *
289 * <p> This API returns false in scenarios like the profile on the
290 * device is already connected or Bluetooth is not turned on.
291 * When this API returns true, it is guaranteed that
292 * connection state intent for the profile will be broadcasted with
293 * the state. Users can get the connection state of the profile
294 * from this intent.
295 *
296 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
297 * permission.
298 *
299 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700300 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700301 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700303 public boolean connect(BluetoothDevice device) {
304 if (DBG) log("connect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700305 try {
306 mServiceLock.readLock().lock();
307 if (mService != null && isEnabled() &&
Jack Hea355e5e2017-08-22 16:06:54 -0700308 isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700309 return mService.connect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700310 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700311 if (mService == null) Log.w(TAG, "Proxy not attached to service");
312 return false;
313 } catch (RemoteException e) {
314 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
315 return false;
316 } finally {
317 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 }
319 }
320
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700321 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700322 * Initiate disconnection from a profile
323 *
324 * <p> This API will return false in scenarios like the profile on the
325 * Bluetooth device is not in connected state etc. When this API returns,
326 * true, it is guaranteed that the connection state change
327 * intent will be broadcasted with the state. Users can get the
328 * disconnection state of the profile from this intent.
329 *
330 * <p> If the disconnection is initiated by a remote device, the state
331 * will transition from {@link #STATE_CONNECTED} to
332 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
333 * host (local) device the state will transition from
334 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
335 * state {@link #STATE_DISCONNECTED}. The transition to
336 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
337 * two scenarios.
338 *
339 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
340 * permission.
341 *
342 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700343 * @return false on immediate error, true otherwise
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700344 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 */
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700346 public boolean disconnect(BluetoothDevice device) {
347 if (DBG) log("disconnect(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700348 try {
349 mServiceLock.readLock().lock();
350 if (mService != null && isEnabled() &&
Jack Hea355e5e2017-08-22 16:06:54 -0700351 isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700352 return mService.disconnect(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700353 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700354 if (mService == null) Log.w(TAG, "Proxy not attached to service");
355 return false;
356 } catch (RemoteException e) {
357 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
358 return false;
359 } finally {
360 mServiceLock.readLock().unlock();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
362 }
363
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700364 /**
365 * {@inheritDoc}
366 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700367 public List<BluetoothDevice> getConnectedDevices() {
Matthew Xie563e4142012-10-09 22:10:37 -0700368 if (VDBG) log("getConnectedDevices()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700369 try {
370 mServiceLock.readLock().lock();
371 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700372 return mService.getConnectedDevices();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700373 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700374 if (mService == null) Log.w(TAG, "Proxy not attached to service");
375 return new ArrayList<BluetoothDevice>();
376 } catch (RemoteException e) {
377 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
378 return new ArrayList<BluetoothDevice>();
379 } finally {
380 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700381 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700382 }
383
384 /**
385 * {@inheritDoc}
386 */
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700387 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Matthew Xie563e4142012-10-09 22:10:37 -0700388 if (VDBG) log("getDevicesMatchingStates()");
Calvin Ond7d16b92016-06-20 15:59:48 -0700389 try {
390 mServiceLock.readLock().lock();
391 if (mService != null && isEnabled()) {
Jaikumar Ganesh03cd78c2010-10-18 16:41:53 -0700392 return mService.getDevicesMatchingConnectionStates(states);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700393 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700394 if (mService == null) Log.w(TAG, "Proxy not attached to service");
395 return new ArrayList<BluetoothDevice>();
396 } catch (RemoteException e) {
397 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
398 return new ArrayList<BluetoothDevice>();
399 } finally {
400 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700401 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700402 }
403
404 /**
405 * {@inheritDoc}
406 */
407 public int getConnectionState(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700408 if (VDBG) log("getState(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700409 try {
410 mServiceLock.readLock().lock();
411 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700412 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700413 return mService.getConnectionState(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700414 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700415 if (mService == null) Log.w(TAG, "Proxy not attached to service");
416 return BluetoothProfile.STATE_DISCONNECTED;
417 } catch (RemoteException e) {
418 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
419 return BluetoothProfile.STATE_DISCONNECTED;
420 } finally {
421 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700422 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700423 }
424
425 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700426 * Set priority of the profile
427 *
428 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700429 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700430 * {@link #PRIORITY_OFF},
431 *
432 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
433 * permission.
434 *
435 * @param device Paired bluetooth device
436 * @param priority
437 * @return true if priority is set, false on error
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700438 * @hide
439 */
440 public boolean setPriority(BluetoothDevice device, int priority) {
441 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700442 try {
443 mServiceLock.readLock().lock();
444 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700445 && isValidDevice(device)) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700446 if (priority != BluetoothProfile.PRIORITY_OFF &&
Jack Hea355e5e2017-08-22 16:06:54 -0700447 priority != BluetoothProfile.PRIORITY_ON) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700448 return false;
449 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700450 return mService.setPriority(device, priority);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700451 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700452 if (mService == null) Log.w(TAG, "Proxy not attached to service");
453 return false;
454 } catch (RemoteException e) {
455 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
456 return false;
457 } finally {
458 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700459 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700460 }
461
462 /**
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700463 * Get the priority of the profile.
464 *
465 * <p> The priority can be any of:
466 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
467 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
468 *
Jaikumar Ganeshf8789162011-05-26 13:56:40 -0700469 * @param device Bluetooth device
470 * @return priority of the device
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700471 * @hide
472 */
Tor Norbye2d497522015-04-23 17:10:21 -0700473 @RequiresPermission(Manifest.permission.BLUETOOTH)
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700474 public int getPriority(BluetoothDevice device) {
Matthew Xie563e4142012-10-09 22:10:37 -0700475 if (VDBG) log("getPriority(" + device + ")");
Calvin Ond7d16b92016-06-20 15:59:48 -0700476 try {
477 mServiceLock.readLock().lock();
478 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700479 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700480 return mService.getPriority(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700481 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700482 if (mService == null) Log.w(TAG, "Proxy not attached to service");
483 return BluetoothProfile.PRIORITY_OFF;
484 } catch (RemoteException e) {
485 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
486 return BluetoothProfile.PRIORITY_OFF;
487 } finally {
488 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700489 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700490 }
491
492 /**
John Du5a0cf7a2013-07-19 11:30:34 -0700493 * Checks if Avrcp device supports the absolute volume feature.
494 *
495 * @return true if device supports absolute volume
496 * @hide
497 */
498 public boolean isAvrcpAbsoluteVolumeSupported() {
499 if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
Calvin Ond7d16b92016-06-20 15:59:48 -0700500 try {
501 mServiceLock.readLock().lock();
502 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700503 return mService.isAvrcpAbsoluteVolumeSupported();
John Du5a0cf7a2013-07-19 11:30:34 -0700504 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700505 if (mService == null) Log.w(TAG, "Proxy not attached to service");
506 return false;
507 } catch (RemoteException e) {
508 Log.e(TAG, "Error talking to BT service in isAvrcpAbsoluteVolumeSupported()", e);
509 return false;
510 } finally {
511 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700512 }
John Du5a0cf7a2013-07-19 11:30:34 -0700513 }
514
515 /**
RoboErik4197cb62015-01-21 15:45:32 -0800516 * Tells remote device to adjust volume. Only if absolute volume is
517 * supported. Uses the following values:
518 * <ul>
519 * <li>{@link AudioManager#ADJUST_LOWER}</li>
520 * <li>{@link AudioManager#ADJUST_RAISE}</li>
521 * <li>{@link AudioManager#ADJUST_MUTE}</li>
522 * <li>{@link AudioManager#ADJUST_UNMUTE}</li>
523 * </ul>
John Du5a0cf7a2013-07-19 11:30:34 -0700524 *
RoboErik4197cb62015-01-21 15:45:32 -0800525 * @param direction One of the supported adjust values.
John Du5a0cf7a2013-07-19 11:30:34 -0700526 * @hide
527 */
528 public void adjustAvrcpAbsoluteVolume(int direction) {
529 if (DBG) Log.d(TAG, "adjustAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700530 try {
531 mServiceLock.readLock().lock();
532 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700533 mService.adjustAvrcpAbsoluteVolume(direction);
John Du5a0cf7a2013-07-19 11:30:34 -0700534 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700535 if (mService == null) Log.w(TAG, "Proxy not attached to service");
536 } catch (RemoteException e) {
537 Log.e(TAG, "Error talking to BT service in adjustAvrcpAbsoluteVolume()", e);
538 } finally {
539 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700540 }
John Du5a0cf7a2013-07-19 11:30:34 -0700541 }
542
543 /**
544 * Tells remote device to set an absolute volume. Only if absolute volume is supported
545 *
546 * @param volume Absolute volume to be set on AVRCP side
547 * @hide
548 */
549 public void setAvrcpAbsoluteVolume(int volume) {
550 if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
Calvin Ond7d16b92016-06-20 15:59:48 -0700551 try {
552 mServiceLock.readLock().lock();
553 if (mService != null && isEnabled()) {
John Du5a0cf7a2013-07-19 11:30:34 -0700554 mService.setAvrcpAbsoluteVolume(volume);
John Du5a0cf7a2013-07-19 11:30:34 -0700555 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700556 if (mService == null) Log.w(TAG, "Proxy not attached to service");
557 } catch (RemoteException e) {
558 Log.e(TAG, "Error talking to BT service in setAvrcpAbsoluteVolume()", e);
559 } finally {
560 mServiceLock.readLock().unlock();
John Du5a0cf7a2013-07-19 11:30:34 -0700561 }
John Du5a0cf7a2013-07-19 11:30:34 -0700562 }
563
564 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700565 * Check if A2DP profile is streaming music.
566 *
Jaikumar Ganeshc8fa4ff2011-01-25 16:03:13 -0800567 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700568 *
569 * @param device BluetoothDevice device
570 */
571 public boolean isA2dpPlaying(BluetoothDevice device) {
Calvin Ond7d16b92016-06-20 15:59:48 -0700572 try {
573 mServiceLock.readLock().lock();
574 if (mService != null && isEnabled()
Jack Hea355e5e2017-08-22 16:06:54 -0700575 && isValidDevice(device)) {
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700576 return mService.isA2dpPlaying(device);
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700577 }
Calvin Ond7d16b92016-06-20 15:59:48 -0700578 if (mService == null) Log.w(TAG, "Proxy not attached to service");
579 return false;
580 } catch (RemoteException e) {
581 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
582 return false;
583 } finally {
584 mServiceLock.readLock().unlock();
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700585 }
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700586 }
587
588 /**
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700589 * This function checks if the remote device is an AVCRP
590 * target and thus whether we should send volume keys
591 * changes or not.
Jack Hea355e5e2017-08-22 16:06:54 -0700592 *
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700593 * @hide
594 */
595 public boolean shouldSendVolumeKeys(BluetoothDevice device) {
596 if (isEnabled() && isValidDevice(device)) {
597 ParcelUuid[] uuids = device.getUuids();
598 if (uuids == null) return false;
599
Jack Hea355e5e2017-08-22 16:06:54 -0700600 for (ParcelUuid uuid : uuids) {
Jaikumar Ganesh41d5c802010-10-13 19:11:28 -0700601 if (BluetoothUuid.isAvrcpTarget(uuid)) {
602 return true;
603 }
604 }
605 }
606 return false;
607 }
608
Matthew Xiea0c68032011-06-25 21:47:07 -0700609 /**
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800610 * Gets the current codec status (configuration and capability).
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800611 *
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800612 * @return the current codec status
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800613 * @hide
614 */
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800615 public BluetoothCodecStatus getCodecStatus() {
616 if (DBG) Log.d(TAG, "getCodecStatus");
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800617 try {
618 mServiceLock.readLock().lock();
619 if (mService != null && isEnabled()) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800620 return mService.getCodecStatus();
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800621 }
622 if (mService == null) {
623 Log.w(TAG, "Proxy not attached to service");
624 }
625 return null;
626 } catch (RemoteException e) {
Pavlin Radoslavovb37f1812017-01-25 16:54:07 -0800627 Log.e(TAG, "Error talking to BT service in getCodecStatus()", e);
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800628 return null;
629 } finally {
630 mServiceLock.readLock().unlock();
631 }
632 }
633
634 /**
635 * Sets the codec configuration preference.
636 *
637 * @param codecConfig the codec configuration preference
638 * @hide
639 */
640 public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) {
641 if (DBG) Log.d(TAG, "setCodecConfigPreference");
642 try {
643 mServiceLock.readLock().lock();
644 if (mService != null && isEnabled()) {
645 mService.setCodecConfigPreference(codecConfig);
646 }
647 if (mService == null) Log.w(TAG, "Proxy not attached to service");
648 return;
649 } catch (RemoteException e) {
650 Log.e(TAG, "Error talking to BT service in setCodecConfigPreference()", e);
651 return;
652 } finally {
653 mServiceLock.readLock().unlock();
654 }
655 }
656
657 /**
Pavlin Radoslavov011597b2017-02-24 10:19:14 -0800658 * Enables the optional codecs.
659 *
660 * @hide
661 */
662 public void enableOptionalCodecs() {
663 if (DBG) Log.d(TAG, "enableOptionalCodecs");
664 enableDisableOptionalCodecs(true);
665 }
666
667 /**
668 * Disables the optional codecs.
669 *
670 * @hide
671 */
672 public void disableOptionalCodecs() {
673 if (DBG) Log.d(TAG, "disableOptionalCodecs");
674 enableDisableOptionalCodecs(false);
675 }
676
677 /**
678 * Enables or disables the optional codecs.
679 *
680 * @param enable if true, enable the optional codecs, other disable them
681 */
682 private void enableDisableOptionalCodecs(boolean enable) {
683 try {
684 mServiceLock.readLock().lock();
685 if (mService != null && isEnabled()) {
686 if (enable) {
687 mService.enableOptionalCodecs();
688 } else {
689 mService.disableOptionalCodecs();
690 }
691 }
692 if (mService == null) Log.w(TAG, "Proxy not attached to service");
693 return;
694 } catch (RemoteException e) {
695 Log.e(TAG, "Error talking to BT service in enableDisableOptionalCodecs()", e);
696 return;
697 } finally {
698 mServiceLock.readLock().unlock();
699 }
700 }
701
702 /**
Antony Sargentf5772c62017-04-26 16:37:53 -0700703 * Returns whether this device supports optional codecs.
704 *
705 * @param device The device to check
706 * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700707 * OPTIONAL_CODECS_SUPPORTED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700708 * @hide
709 */
710 public int supportsOptionalCodecs(BluetoothDevice device) {
711 try {
712 mServiceLock.readLock().lock();
713 if (mService != null && isEnabled() && isValidDevice(device)) {
714 return mService.supportsOptionalCodecs(device);
715 }
716 if (mService == null) Log.w(TAG, "Proxy not attached to service");
717 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
718 } catch (RemoteException e) {
719 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
720 return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
721 } finally {
722 mServiceLock.readLock().unlock();
723 }
724 }
725
726 /**
727 * Returns whether this device should have optional codecs enabled.
728 *
729 * @param device The device in question.
730 * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
Jack Hea355e5e2017-08-22 16:06:54 -0700731 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700732 * @hide
733 */
734 public int getOptionalCodecsEnabled(BluetoothDevice device) {
735 try {
736 mServiceLock.readLock().lock();
737 if (mService != null && isEnabled() && isValidDevice(device)) {
738 return mService.getOptionalCodecsEnabled(device);
739 }
740 if (mService == null) Log.w(TAG, "Proxy not attached to service");
741 return OPTIONAL_CODECS_PREF_UNKNOWN;
742 } catch (RemoteException e) {
743 Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
744 return OPTIONAL_CODECS_PREF_UNKNOWN;
745 } finally {
746 mServiceLock.readLock().unlock();
747 }
748 }
749
750 /**
751 * Sets a persistent preference for whether a given device should have optional codecs enabled.
752 *
753 * @param device The device to set this preference for.
754 * @param value Whether the optional codecs should be enabled for this device. This should be
Jack Hea355e5e2017-08-22 16:06:54 -0700755 * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
756 * OPTIONAL_CODECS_PREF_DISABLED.
Antony Sargentf5772c62017-04-26 16:37:53 -0700757 * @hide
758 */
759 public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
760 try {
761 if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN &&
762 value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED &&
763 value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
764 Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
765 return;
766 }
767 mServiceLock.readLock().lock();
768 if (mService != null && isEnabled()
769 && isValidDevice(device)) {
770 mService.setOptionalCodecsEnabled(device, value);
771 }
772 if (mService == null) Log.w(TAG, "Proxy not attached to service");
773 return;
774 } catch (RemoteException e) {
775 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
776 return;
777 } finally {
778 mServiceLock.readLock().unlock();
779 }
780 }
781
782 /**
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700783 * Helper for converting a state to a string.
784 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700786 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 * @hide
788 */
789 public static String stateToString(int state) {
790 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700791 case STATE_DISCONNECTED:
792 return "disconnected";
793 case STATE_CONNECTING:
794 return "connecting";
795 case STATE_CONNECTED:
796 return "connected";
797 case STATE_DISCONNECTING:
798 return "disconnecting";
799 case STATE_PLAYING:
800 return "playing";
801 case STATE_NOT_PLAYING:
802 return "not playing";
803 default:
804 return "<unknown state " + state + ">";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
806 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800807
Matthew Xie9b693992013-10-10 11:21:40 -0700808 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800809 public void onServiceConnected(ComponentName className, IBinder service) {
810 if (DBG) Log.d(TAG, "Proxy object connected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700811 try {
812 mServiceLock.writeLock().lock();
Jeff Sharkey0a17db12016-11-04 11:23:46 -0600813 mService = IBluetoothA2dp.Stub.asInterface(Binder.allowBlocking(service));
Calvin Ond7d16b92016-06-20 15:59:48 -0700814 } finally {
815 mServiceLock.writeLock().unlock();
816 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800817
818 if (mServiceListener != null) {
819 mServiceListener.onServiceConnected(BluetoothProfile.A2DP, BluetoothA2dp.this);
820 }
821 }
Jack Hea355e5e2017-08-22 16:06:54 -0700822
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800823 public void onServiceDisconnected(ComponentName className) {
824 if (DBG) Log.d(TAG, "Proxy object disconnected");
Calvin Ond7d16b92016-06-20 15:59:48 -0700825 try {
826 mServiceLock.writeLock().lock();
827 mService = null;
828 } finally {
829 mServiceLock.writeLock().unlock();
830 }
Matthew Xie3e8c82e2012-02-16 16:57:18 -0800831 if (mServiceListener != null) {
832 mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
833 }
834 }
835 };
836
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700837 private boolean isEnabled() {
Jack Hea355e5e2017-08-22 16:06:54 -0700838 if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
839 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700840 }
841
842 private boolean isValidDevice(BluetoothDevice device) {
Jack Hea355e5e2017-08-22 16:06:54 -0700843 if (device == null) return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700844
Jack Hea355e5e2017-08-22 16:06:54 -0700845 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
846 return false;
Jaikumar Ganesh62c37ef2010-08-24 17:36:13 -0700847 }
848
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800849 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700850 Log.d(TAG, msg);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852}