blob: 5a8055a29cfc0bc32d7c44e2e225f761281bc687 [file] [log] [blame]
Mike Lockwood2263dd12014-05-14 09:51:30 -07001/*
2 * Copyright (C) 2014 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
Mathew Inwood4dc66d32018-08-01 15:07:20 +010019import android.annotation.UnsupportedAppUsage;
Mike Lockwood2263dd12014-05-14 09:51:30 -070020import android.content.Context;
Jeff Sharkey0a17db12016-11-04 11:23:46 -060021import android.os.Binder;
Mike Lockwood2263dd12014-05-14 09:51:30 -070022import android.os.IBinder;
23import android.os.RemoteException;
24import android.util.Log;
25
26import java.util.ArrayList;
27import java.util.List;
28
29/**
30 * This class provides the public APIs to control the Bluetooth A2DP Sink
31 * profile.
32 *
Jack Hea355e5e2017-08-22 16:06:54 -070033 * <p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
Mike Lockwood2263dd12014-05-14 09:51:30 -070034 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
35 * the BluetoothA2dpSink proxy object.
36 *
37 * @hide
38 */
39public final class BluetoothA2dpSink implements BluetoothProfile {
40 private static final String TAG = "BluetoothA2dpSink";
41 private static final boolean DBG = true;
42 private static final boolean VDBG = false;
43
44 /**
45 * Intent used to broadcast the change in connection state of the A2DP Sink
46 * profile.
47 *
48 * <p>This intent will have 3 extras:
49 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070050 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
51 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
52 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -070053 * </ul>
54 *
55 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
56 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
57 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
58 *
59 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
60 * receive.
61 */
62 public static final String ACTION_CONNECTION_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070063 "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -070064
65 /**
66 * Intent used to broadcast the change in the Playing state of the A2DP Sink
67 * profile.
68 *
69 * <p>This intent will have 3 extras:
70 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -070071 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
72 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
73 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -070074 * </ul>
75 *
76 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
77 * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
78 *
79 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
80 * receive.
81 */
82 public static final String ACTION_PLAYING_STATE_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -070083 "android.bluetooth.a2dp-sink.profile.action.PLAYING_STATE_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -070084
85 /**
86 * A2DP sink device is streaming music. This state can be one of
87 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
88 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
89 */
Jack Hea355e5e2017-08-22 16:06:54 -070090 public static final int STATE_PLAYING = 10;
Mike Lockwood2263dd12014-05-14 09:51:30 -070091
92 /**
93 * A2DP sink device is NOT streaming music. This state can be one of
94 * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
95 * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
96 */
Jack Hea355e5e2017-08-22 16:06:54 -070097 public static final int STATE_NOT_PLAYING = 11;
Mike Lockwood2263dd12014-05-14 09:51:30 -070098
99 /**
100 * Intent used to broadcast the change in the Playing state of the A2DP Sink
101 * profile.
102 *
103 * <p>This intent will have 3 extras:
104 * <ul>
Jack Hea355e5e2017-08-22 16:06:54 -0700105 * <li> {@link #EXTRA_AUDIO_CONFIG} - The audio configuration for the remote device. </li>
106 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
Mike Lockwood2263dd12014-05-14 09:51:30 -0700107 * </ul>
108 *
109 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
110 * receive.
111 */
112 public static final String ACTION_AUDIO_CONFIG_CHANGED =
Jack Hea355e5e2017-08-22 16:06:54 -0700113 "android.bluetooth.a2dp-sink.profile.action.AUDIO_CONFIG_CHANGED";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700114
115 /**
116 * Extra for the {@link #ACTION_AUDIO_CONFIG_CHANGED} intent.
117 *
118 * This extra represents the current audio configuration of the A2DP source device.
119 * {@see BluetoothAudioConfig}
120 */
Jack He2992cd02017-08-22 21:21:23 -0700121 public static final String EXTRA_AUDIO_CONFIG =
122 "android.bluetooth.a2dp-sink.profile.extra.AUDIO_CONFIG";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700123
Mike Lockwood2263dd12014-05-14 09:51:30 -0700124 private BluetoothAdapter mAdapter;
Ugo Yud0115462019-03-26 21:38:08 +0800125 private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
126 new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
127 "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) {
128 @Override
129 public IBluetoothA2dpSink getServiceInterface(IBinder service) {
130 return IBluetoothA2dpSink.Stub.asInterface(Binder.allowBlocking(service));
Mike Lockwood2263dd12014-05-14 09:51:30 -0700131 }
Ugo Yud0115462019-03-26 21:38:08 +0800132 };
Jack Hea355e5e2017-08-22 16:06:54 -0700133
Mike Lockwood2263dd12014-05-14 09:51:30 -0700134 /**
135 * Create a BluetoothA2dp proxy object for interacting with the local
136 * Bluetooth A2DP service.
Mike Lockwood2263dd12014-05-14 09:51:30 -0700137 */
Ugo Yud0115462019-03-26 21:38:08 +0800138 /*package*/ BluetoothA2dpSink(Context context, ServiceListener listener) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700139 mAdapter = BluetoothAdapter.getDefaultAdapter();
Ugo Yud0115462019-03-26 21:38:08 +0800140 mProfileConnector.connect(context, listener);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700141 }
142
143 /*package*/ void close() {
Ugo Yud0115462019-03-26 21:38:08 +0800144 mProfileConnector.disconnect();
145 }
Mike Lockwood2263dd12014-05-14 09:51:30 -0700146
Ugo Yud0115462019-03-26 21:38:08 +0800147 private IBluetoothA2dpSink getService() {
148 return mProfileConnector.getService();
Mike Lockwood2263dd12014-05-14 09:51:30 -0700149 }
150
Jack He2992cd02017-08-22 21:21:23 -0700151 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700152 public void finalize() {
153 close();
154 }
Jack Hea355e5e2017-08-22 16:06:54 -0700155
Mike Lockwood2263dd12014-05-14 09:51:30 -0700156 /**
157 * Initiate connection to a profile of the remote bluetooth device.
158 *
159 * <p> Currently, the system supports only 1 connection to the
160 * A2DP profile. The API will automatically disconnect connected
161 * devices before connecting.
162 *
163 * <p> This API returns false in scenarios like the profile on the
164 * device is already connected or Bluetooth is not turned on.
165 * When this API returns true, it is guaranteed that
166 * connection state intent for the profile will be broadcasted with
167 * the state. Users can get the connection state of the profile
168 * from this intent.
169 *
170 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
171 * permission.
172 *
173 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700174 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700175 * @hide
176 */
177 public boolean connect(BluetoothDevice device) {
178 if (DBG) log("connect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800179 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700180 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700181 try {
Jack He16eeac32017-08-17 12:11:18 -0700182 return service.connect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700183 } catch (RemoteException e) {
184 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
185 return false;
186 }
187 }
Jack He16eeac32017-08-17 12:11:18 -0700188 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700189 return false;
190 }
191
192 /**
193 * Initiate disconnection from a profile
194 *
195 * <p> This API will return false in scenarios like the profile on the
196 * Bluetooth device is not in connected state etc. When this API returns,
197 * true, it is guaranteed that the connection state change
198 * intent will be broadcasted with the state. Users can get the
199 * disconnection state of the profile from this intent.
200 *
201 * <p> If the disconnection is initiated by a remote device, the state
202 * will transition from {@link #STATE_CONNECTED} to
203 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
204 * host (local) device the state will transition from
205 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
206 * state {@link #STATE_DISCONNECTED}. The transition to
207 * {@link #STATE_DISCONNECTING} can be used to distinguish between the
208 * two scenarios.
209 *
210 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
211 * permission.
212 *
213 * @param device Remote Bluetooth Device
Jack Hea355e5e2017-08-22 16:06:54 -0700214 * @return false on immediate error, true otherwise
Mike Lockwood2263dd12014-05-14 09:51:30 -0700215 * @hide
216 */
Mathew Inwood4dc66d32018-08-01 15:07:20 +0100217 @UnsupportedAppUsage
Mike Lockwood2263dd12014-05-14 09:51:30 -0700218 public boolean disconnect(BluetoothDevice device) {
219 if (DBG) log("disconnect(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800220 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700221 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700222 try {
Jack He16eeac32017-08-17 12:11:18 -0700223 return service.disconnect(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700224 } catch (RemoteException e) {
225 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
226 return false;
227 }
228 }
Jack He16eeac32017-08-17 12:11:18 -0700229 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700230 return false;
231 }
232
233 /**
234 * {@inheritDoc}
235 */
Jack He2992cd02017-08-22 21:21:23 -0700236 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700237 public List<BluetoothDevice> getConnectedDevices() {
238 if (VDBG) log("getConnectedDevices()");
Ugo Yud0115462019-03-26 21:38:08 +0800239 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700240 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700241 try {
Jack He16eeac32017-08-17 12:11:18 -0700242 return service.getConnectedDevices();
Mike Lockwood2263dd12014-05-14 09:51:30 -0700243 } catch (RemoteException e) {
244 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
245 return new ArrayList<BluetoothDevice>();
246 }
247 }
Jack He16eeac32017-08-17 12:11:18 -0700248 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700249 return new ArrayList<BluetoothDevice>();
250 }
251
252 /**
253 * {@inheritDoc}
254 */
Jack He2992cd02017-08-22 21:21:23 -0700255 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700256 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
257 if (VDBG) log("getDevicesMatchingStates()");
Ugo Yud0115462019-03-26 21:38:08 +0800258 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700259 if (service != null && isEnabled()) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700260 try {
Jack He16eeac32017-08-17 12:11:18 -0700261 return service.getDevicesMatchingConnectionStates(states);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700262 } catch (RemoteException e) {
263 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
264 return new ArrayList<BluetoothDevice>();
265 }
266 }
Jack He16eeac32017-08-17 12:11:18 -0700267 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700268 return new ArrayList<BluetoothDevice>();
269 }
270
271 /**
272 * {@inheritDoc}
273 */
Jack He2992cd02017-08-22 21:21:23 -0700274 @Override
Mike Lockwood2263dd12014-05-14 09:51:30 -0700275 public int getConnectionState(BluetoothDevice device) {
276 if (VDBG) log("getState(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800277 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700278 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700279 try {
Jack He16eeac32017-08-17 12:11:18 -0700280 return service.getConnectionState(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700281 } catch (RemoteException e) {
282 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
283 return BluetoothProfile.STATE_DISCONNECTED;
284 }
285 }
Jack He16eeac32017-08-17 12:11:18 -0700286 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700287 return BluetoothProfile.STATE_DISCONNECTED;
288 }
289
290 /**
291 * Get the current audio configuration for the A2DP source device,
292 * or null if the device has no audio configuration
293 *
294 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
295 *
296 * @param device Remote bluetooth device.
297 * @return audio configuration for the device, or null
298 *
299 * {@see BluetoothAudioConfig}
300 */
Jack Hea355e5e2017-08-22 16:06:54 -0700301 public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700302 if (VDBG) log("getAudioConfig(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800303 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700304 if (service != null && isEnabled() && isValidDevice(device)) {
Mike Lockwood2263dd12014-05-14 09:51:30 -0700305 try {
Jack He16eeac32017-08-17 12:11:18 -0700306 return service.getAudioConfig(device);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700307 } catch (RemoteException e) {
308 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
309 return null;
310 }
311 }
Jack He16eeac32017-08-17 12:11:18 -0700312 if (service == null) Log.w(TAG, "Proxy not attached to service");
Mike Lockwood2263dd12014-05-14 09:51:30 -0700313 return null;
314 }
315
316 /**
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700317 * Set priority of the profile
318 *
319 * <p> The device should already be paired.
Jack Hea355e5e2017-08-22 16:06:54 -0700320 * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700321 * {@link #PRIORITY_OFF},
322 *
323 * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
324 * permission.
325 *
326 * @param device Paired bluetooth device
327 * @param priority
328 * @return true if priority is set, false on error
329 * @hide
330 */
331 public boolean setPriority(BluetoothDevice device, int priority) {
332 if (DBG) log("setPriority(" + device + ", " + priority + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800333 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700334 if (service != null && isEnabled() && isValidDevice(device)) {
Jack He2992cd02017-08-22 21:21:23 -0700335 if (priority != BluetoothProfile.PRIORITY_OFF
336 && priority != BluetoothProfile.PRIORITY_ON) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700337 return false;
338 }
339 try {
Jack He16eeac32017-08-17 12:11:18 -0700340 return service.setPriority(device, priority);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700341 } catch (RemoteException e) {
Jack Hea355e5e2017-08-22 16:06:54 -0700342 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
343 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700344 }
345 }
Jack He16eeac32017-08-17 12:11:18 -0700346 if (service == null) Log.w(TAG, "Proxy not attached to service");
Jack Hea355e5e2017-08-22 16:06:54 -0700347 return false;
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700348 }
349
350 /**
351 * Get the priority of the profile.
352 *
353 * <p> The priority can be any of:
354 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
355 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
356 *
357 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
358 *
359 * @param device Bluetooth device
360 * @return priority of the device
361 * @hide
362 */
363 public int getPriority(BluetoothDevice device) {
364 if (VDBG) log("getPriority(" + device + ")");
Ugo Yud0115462019-03-26 21:38:08 +0800365 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700366 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700367 try {
Jack He16eeac32017-08-17 12:11:18 -0700368 return service.getPriority(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700369 } catch (RemoteException e) {
370 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
371 return BluetoothProfile.PRIORITY_OFF;
372 }
373 }
Jack He16eeac32017-08-17 12:11:18 -0700374 if (service == null) Log.w(TAG, "Proxy not attached to service");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700375 return BluetoothProfile.PRIORITY_OFF;
376 }
377
378 /**
379 * Check if A2DP profile is streaming music.
380 *
381 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
382 *
383 * @param device BluetoothDevice device
384 */
385 public boolean isA2dpPlaying(BluetoothDevice device) {
Ugo Yud0115462019-03-26 21:38:08 +0800386 final IBluetoothA2dpSink service = getService();
Jack He16eeac32017-08-17 12:11:18 -0700387 if (service != null && isEnabled() && isValidDevice(device)) {
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700388 try {
Jack He16eeac32017-08-17 12:11:18 -0700389 return service.isA2dpPlaying(device);
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700390 } catch (RemoteException e) {
391 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
392 return false;
393 }
394 }
Jack He16eeac32017-08-17 12:11:18 -0700395 if (service == null) Log.w(TAG, "Proxy not attached to service");
Sanket Agarwal1bec6a52015-10-21 18:23:27 -0700396 return false;
397 }
398
399 /**
Mike Lockwood2263dd12014-05-14 09:51:30 -0700400 * Helper for converting a state to a string.
401 *
402 * For debug use only - strings are not internationalized.
Jack Hea355e5e2017-08-22 16:06:54 -0700403 *
Mike Lockwood2263dd12014-05-14 09:51:30 -0700404 * @hide
405 */
406 public static String stateToString(int state) {
407 switch (state) {
Jack Hea355e5e2017-08-22 16:06:54 -0700408 case STATE_DISCONNECTED:
409 return "disconnected";
410 case STATE_CONNECTING:
411 return "connecting";
412 case STATE_CONNECTED:
413 return "connected";
414 case STATE_DISCONNECTING:
415 return "disconnecting";
416 case STATE_PLAYING:
417 return "playing";
418 case STATE_NOT_PLAYING:
419 return "not playing";
420 default:
421 return "<unknown state " + state + ">";
Mike Lockwood2263dd12014-05-14 09:51:30 -0700422 }
423 }
424
Mike Lockwood2263dd12014-05-14 09:51:30 -0700425 private boolean isEnabled() {
Jack He16eeac32017-08-17 12:11:18 -0700426 return mAdapter.getState() == BluetoothAdapter.STATE_ON;
Mike Lockwood2263dd12014-05-14 09:51:30 -0700427 }
428
Jack He16eeac32017-08-17 12:11:18 -0700429 private static boolean isValidDevice(BluetoothDevice device) {
430 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
Mike Lockwood2263dd12014-05-14 09:51:30 -0700431 }
432
433 private static void log(String msg) {
Jack Hea355e5e2017-08-22 16:06:54 -0700434 Log.d(TAG, msg);
Mike Lockwood2263dd12014-05-14 09:51:30 -0700435 }
436}