Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(733)

Side by Side Diff: webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCBluetoothManager.java

Issue 2501983002: Adds basic Bluetooth support to AppRTCMobile (Closed)
Patch Set: Cleaned up AppRTCBluetoothManager.java Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 package org.appspot.apprtc;
12
13 import org.appspot.apprtc.util.AppRTCUtils;
14
15 import android.bluetooth.BluetoothAdapter;
16 import android.bluetooth.BluetoothDevice;
17 import android.bluetooth.BluetoothHeadset;
18 import android.bluetooth.BluetoothProfile;
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.pm.PackageManager;
24 import android.media.AudioManager;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Process;
28 import android.util.Log;
29
30 import org.webrtc.ThreadUtils;
31
32 import java.util.List;
33 import java.util.Set;
34
35 /**
36 * AppRTCProximitySensor manages functions related to Bluetoth devices in the
37 * AppRTC demo.
38 */
39 public class AppRTCBluetoothManager {
40 private static final String TAG = "AppRTCBluetoothManager";
41
42 // Timeout interval for starting or stopping audio to a Bluetooth SCO device.
43 private static final int BLUETOOTH_SCO_TIMEOUT_MS = 4000;
44 // Maximum number of SCO connection attempts.
45 private static final int MAX_SCO_CONNECTION_ATTEMPTS = 2;
46
47 // Bluetooth connection state.
48 public enum State {
49 // Bluetooth is not available; no adapter or Bluetooth is off.
50 UNINITIALIZED,
51 // Bluetooth error happened when trying to start Bluetooth.
52 ERROR,
53 // Bluetooth proxy object for the Headset profile exists, but no connected h eadset devices,
54 // SCO is not started or disconnected.
55 HEADSET_UNAVAILABLE,
56 // Bluetooth proxy object for the Headset profile connected, connected Bluet ooth headset
57 // present, but SCO is not started or disconnected.
58 HEADSET_AVAILABLE,
59 // Bluetooth audio SCO connection with remote device is closing.
60 SCO_DISCONNECTING,
61 // Bluetooth audio SCO connection with remote device is initiated.
62 SCO_CONNECTING,
63 // Bluetooth audio SCO connection with remote device is established.
64 SCO_CONNECTED
65 }
66
67 private final ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.Thread Checker();
68
69 private final Context apprtcContext;
70 private final AppRTCAudioManager apprtcAudioManager;
71 private final AudioManager audioManager;
72 private final Handler handler;
73
74 int scoConnectionAttempts;
75 private State bluetoothState;
76 private final BluetoothProfile.ServiceListener bluetoothServiceListener;
77 private BluetoothAdapter bluetoothAdapter;
78 private BluetoothHeadset bluetoothHeadset;
79 private BluetoothDevice bluetoothDevice;
80 private final BroadcastReceiver bluetoothHeadsetReceiver;
81
82 // Runs when the Bluetooth timeout expires. We use that timeout after calling
83 // startScoAudio() or stopScoAudio() because we're not guaranteed to get a
84 // callback after those calls.
85 private final Runnable bluetoothTimeoutRunnable = new Runnable() {
86 @Override
87 public void run() {
88 bluetoothTimeout();
89 }
90 };
91
92 /**
93 * Implementation of an interface that notifies BluetoothProfile IPC clients w hen they have been
94 * connected to or disconnected from the service.
95 */
96 private class BluetoothServiceListener implements BluetoothProfile.ServiceList ener {
97 @Override
98 // Called to notify the client when the proxy object has been connected to t he service.
99 // Once we have the profile proxy object, we can use it to monitor the state of the
100 // connection and perform other operations that are relevant to the headset profile.
101 public void onServiceConnected(int profile, BluetoothProfile proxy) {
102 if (profile != BluetoothProfile.HEADSET || bluetoothState == State.UNINITI ALIZED) {
103 return;
104 }
105 Log.d(TAG, "BluetoothServiceListener.onServiceConnected: BT state=" + blue toothState);
106 // Android only supports one connected Bluetooth Headset at a time.
107 bluetoothHeadset = (BluetoothHeadset) proxy;
108 updateAudioDeviceState();
109 Log.d(TAG, "onServiceConnected done: BT state=" + bluetoothState);
110 }
111
112 @Override
113 /** Notifies the client when the proxy object has been disconnected from the service. */
114 public void onServiceDisconnected(int profile) {
115 if (profile != BluetoothProfile.HEADSET || bluetoothState == State.UNINITI ALIZED) {
116 return;
117 }
118 Log.d(TAG, "BluetoothServiceListener.onServiceDisconnected: BT state=" + b luetoothState);
119 stopScoAudio();
120 bluetoothHeadset = null;
121 bluetoothDevice = null;
122 bluetoothState = State.HEADSET_UNAVAILABLE;
123 updateAudioDeviceState();
124 Log.d(TAG, "onServiceDisconnected done: BT state=" + bluetoothState);
125 }
126 }
127
128 // Intent broadcast receiver which handles changes in Bluetooth device availab ility.
129 // Detects headset changes and Bluetooth SCO state changes.
130 private class BluetoothHeadsetBroadcastReceiver extends BroadcastReceiver {
131 @Override
132 public void onReceive(Context context, Intent intent) {
133 if (bluetoothState == State.UNINITIALIZED) {
134 return;
135 }
136 final String action = intent.getAction();
137 // Change in connection state of the Headset profile. Note that the
138 // change does not tell us anything about whether we're streaming
139 // audio to BT over SCO. Typically received when user turns on a BT
140 // headset while audio is active using another audio device.
141 if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
142 final int state =
143 intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.ST ATE_DISCONNECTED);
144 final BluetoothDevice device =
145 (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DE VICE);
146 Log.d(TAG, "BluetoothHeadsetBroadcastReceiver.onReceive: "
147 + "a=ACTION_CONNECTION_STATE_CHANGED, "
148 + "s=" + stateToString(state) + ", "
149 + "n=" + device.getName() + ", "
150 + "sb=" + isInitialStickyBroadcast() + ", "
151 + "BT state: " + bluetoothState);
152 if (state == BluetoothHeadset.STATE_CONNECTED) {
153 scoConnectionAttempts = 0;
154 updateAudioDeviceState();
155 } else if (state == BluetoothHeadset.STATE_CONNECTING) {
156 // No action needed.
157 } else if (state == BluetoothHeadset.STATE_DISCONNECTING) {
158 // No action needed.
159 } else if (state == BluetoothHeadset.STATE_DISCONNECTED) {
160 // Bluetooth is probably powered off during the call.
161 stopScoAudio();
162 updateAudioDeviceState();
163 }
164 // Change in the audio (SCO) connection state of the Headset profile.
165 // Typically received after call to startScoAudio() has finalized.
166 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
167 final int state = intent.getIntExtra(
168 BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNEC TED);
169 final BluetoothDevice device =
170 (BluetoothDevice) intent.getParcelableExtra(BluetoothDevice.EXTRA_DE VICE);
171 Log.d(TAG, "BluetoothHeadsetBroadcastReceiver.onReceive: "
172 + "a=ACTION_AUDIO_STATE_CHANGED, "
173 + "s=" + stateToString(state) + ", "
174 + "n=" + device.getName() + ", "
175 + "sb=" + isInitialStickyBroadcast() + ", "
176 + "BT state: " + bluetoothState);
177 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
178 cancelTimer();
179 if (bluetoothState == State.SCO_CONNECTING) {
180 Log.d(TAG, "+++ Bluetooth audio SCO is now connected");
181 bluetoothState = State.SCO_CONNECTED;
182 scoConnectionAttempts = 0;
183 updateAudioDeviceState();
184 } else {
185 Log.w(TAG, "Unexpected state BluetoothHeadset.STATE_AUDIO_CONNECTED" );
186 }
187 } else if (state == BluetoothHeadset.STATE_AUDIO_CONNECTING) {
188 Log.d(TAG, "+++ Bluetooth audio SCO is now connecting...");
189 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
190 Log.d(TAG, "+++ Bluetooth audio SCO is now disconnected");
191 if (isInitialStickyBroadcast()) {
192 Log.d(TAG, "Ignore STATE_AUDIO_DISCONNECTED initial sticky broadcast .");
193 return;
194 }
195 updateAudioDeviceState();
196 }
197 }
198 Log.d(TAG, "onReceive done: BT state=" + bluetoothState);
199 }
200 };
201
202 /** Construction. */
203 static AppRTCBluetoothManager create(Context context, AppRTCAudioManager audio Manager) {
204 Log.d(TAG, "create" + AppRTCUtils.getThreadInfo());
205 return new AppRTCBluetoothManager(context, audioManager);
206 }
207
208 private AppRTCBluetoothManager(Context context, AppRTCAudioManager audioManage r) {
209 ThreadUtils.checkIsOnMainThread();
210 apprtcContext = context;
211 apprtcAudioManager = audioManager;
212 this.audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_S ERVICE));
213 bluetoothState = State.UNINITIALIZED;
214 bluetoothServiceListener = new BluetoothServiceListener();
215 bluetoothHeadsetReceiver = new BluetoothHeadsetBroadcastReceiver();
216 handler = new Handler(Looper.getMainLooper());
217 }
218
219 /** Returns the internal state. */
220 public State getState() {
221 threadChecker.checkIsOnValidThread();
222 return bluetoothState;
223 }
224
225 /**
226 * Activates components required to detect Bluetooth devices and to enable
227 * BT SCO (audio is routed via BT SCO) for the headset profile. The end
228 * state will be HEADSET_UNAVAILABLE but a state machine has started which
229 * will start a state change sequence where the final outcome depends on
230 * if/when the BT headset is enabled.
231 * Example of state change sequence when start() is called while BT device
232 * is connected and enabled:
233 * UNINITIALIZED --> HEADSET_UNAVAILABLE --> HEADSET_AVAILABLE -->
234 * SCO_CONNECTING --> SCO_CONNECTED <==> audio is now routed via BT SCO.
235 * Note that the AppRTCAudioManager is also involved in driving this state
236 * change.
237 */
238 public void start() {
239 threadChecker.checkIsOnValidThread();
240 Log.d(TAG, "start");
241 if (!hasPermission(android.Manifest.permission.BLUETOOTH)) {
242 Log.w(TAG, "Process (pid=" + Process.myPid() + ") lacks BLUETOOTH permissi on");
243 return;
244 }
245 if (bluetoothState != State.UNINITIALIZED) {
246 Log.w(TAG, "Invalid BT state");
247 return;
248 }
249 bluetoothHeadset = null;
250 bluetoothDevice = null;
251 scoConnectionAttempts = 0;
252 // Get a handle to the default local Bluetooth adapter.
253 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
254 if (bluetoothAdapter == null) {
255 Log.w(TAG, "Device does not support Bluetooth");
256 return;
257 }
258 // Ensure that the device supports use of BT SCO audio for off call use case s.
259 if (!audioManager.isBluetoothScoAvailableOffCall()) {
260 Log.e(TAG, "Bluetooth SCO audio is not available off call");
261 return;
262 }
263 logBluetoothAdapterInfo(bluetoothAdapter);
264 // Establish a connection to the HEADSET profile (includes both Bluetooth He adset and
265 // Hands-Free) proxy object and install a listener.
266 if (!bluetoothAdapter.getProfileProxy(
267 apprtcContext, bluetoothServiceListener, BluetoothProfile.HEADSET)) {
268 Log.e(TAG, "BluetoothAdapter.getProfileProxy(HEADSET) failed");
269 return;
270 }
271 // Register receivers for BluetoothHeadset change notifications.
272 IntentFilter bluetoothHeadsetFilter = new IntentFilter();
273 // Register receiver for change in connection state of the Headset profile.
274 bluetoothHeadsetFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CH ANGED);
275 // Register receiver for change in audio connection state of the Headset pro file.
276 bluetoothHeadsetFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED );
277 registerReceiver(bluetoothHeadsetReceiver, bluetoothHeadsetFilter);
278 Log.d(TAG, "HEADSET profile state: "
279 + stateToString(bluetoothAdapter.getProfileConnectionState(Bluetooth Profile.HEADSET)));
280 Log.d(TAG, "Bluetooth proxy for headset profile has started");
281 bluetoothState = State.HEADSET_UNAVAILABLE;
282 Log.d(TAG, "start done: BT state=" + bluetoothState);
283 }
284
285 /** Stops and closes all components related to Bluetooth audio. */
286 public void stop() {
287 threadChecker.checkIsOnValidThread();
288 unregisterReceiver(bluetoothHeadsetReceiver);
289 Log.d(TAG, "stop: BT state=" + bluetoothState);
290 if (bluetoothAdapter != null) {
291 // Stop BT SCO connection with remote device if needed.
292 stopScoAudio();
293 // Close down remaining BT resources.
294 if (bluetoothState != State.UNINITIALIZED) {
295 cancelTimer();
296 if (bluetoothHeadset != null) {
297 bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, bluetooth Headset);
298 bluetoothHeadset = null;
299 }
300 bluetoothAdapter = null;
301 bluetoothDevice = null;
302 bluetoothState = State.UNINITIALIZED;
303 }
304 }
305 Log.d(TAG, "stop done: BT state=" + bluetoothState);
306 }
307
308 /**
309 * Starts Bluetooth SCO connection with remote device.
310 * Note that the phone application always has the priority on the usage of the SCO connection
311 * for telephony. If this method is called while the phone is in call it will be ignored.
312 * Similarly, if a call is received or sent while an application is using the SCO connection,
313 * the connection will be lost for the application and NOT returned automatica lly when the call
314 * ends. Also note that: up to and including API version JELLY_BEAN_MR1, this method initiates a
315 * virtual voice call to the Bluetooth headset. After API version JELLY_BEAN_M R2 only a raw SCO
316 * audio connection is established.
317 * TODO(henrika): should we add support for virtual voice call to BT headset a lso for JBMR2 and
318 * higher. It might be required to initiates a virtual voice call since many d evices do not
319 * accept SCO audio without a "call".
320 */
321 public boolean startScoAudio() {
322 threadChecker.checkIsOnValidThread();
323 Log.d(TAG, "startSco: BT state=" + bluetoothState + ", "
324 + "attempts: " + scoConnectionAttempts + ", "
325 + "SCO is on: " + isScoOn());
326 if (scoConnectionAttempts >= MAX_SCO_CONNECTION_ATTEMPTS) {
327 Log.e(TAG, "BT SCO connection fails - no more attempts");
328 return false;
329 }
330 if (bluetoothState != State.HEADSET_AVAILABLE) {
331 Log.e(TAG, "BT SCO connection fails - no headset available");
332 return false;
333 }
334 // Start BT SCO channel and wait for ACTION_AUDIO_STATE_CHANGED.
335 Log.d(TAG, "Starting Bluetooth SCO and waits for ACTION_AUDIO_STATE_CHANGED. ..");
336 // The SCO connection establishment can take several seconds, hence we canno t rely on the
337 // connection to be available when the method returns but instead register t o receive the
338 // intent ACTION_SCO_AUDIO_STATE_UPDATED and wait for the state to be SCO_AU DIO_STATE_CONNECTED.
339 bluetoothState = State.SCO_CONNECTING;
340 audioManager.startBluetoothSco();
341 scoConnectionAttempts++;
342 startTimer();
343 Log.d(TAG, "startScoAudio done: BT state=" + bluetoothState);
344 return true;
345 }
346
347 /** Stops Bluetooth SCO connection with remote device. */
348 public void stopScoAudio() {
349 threadChecker.checkIsOnValidThread();
350 Log.d(TAG, "stopScoAudio: BT state=" + bluetoothState + ", "
351 + "SCO is on: " + isScoOn());
352 if (bluetoothState != State.SCO_CONNECTING && bluetoothState != State.SCO_CO NNECTED) {
353 return;
354 }
355 cancelTimer();
356 audioManager.stopBluetoothSco();
357 bluetoothState = State.SCO_DISCONNECTING;
358 Log.d(TAG, "stopScoAudio done: BT state=" + bluetoothState);
359 }
360
361 /**
362 * Use the BluetoothHeadset proxy object (controls the Bluetooth Headset
363 * Service via IPC) to update the list of connected devices for the HEADSET
364 * profile. The internal state will change to HEADSET_UNAVAILABLE or to
365 * HEADSET_AVAILABLE and |bluetoothDevice| will be mapped to the connected
366 * device if available.
367 */
368 public void updateDevice() {
369 if (bluetoothState == State.UNINITIALIZED || bluetoothHeadset == null) {
370 return;
371 }
372 Log.d(TAG, "updateDevice");
373 // Get connected devices for the headset profile. Returns the set of
374 // devices which are in state STATE_CONNECTED. The BluetoothDevice class
375 // is just a thin wrapper for a Bluetooth hardware address.
376 List<BluetoothDevice> devices = bluetoothHeadset.getConnectedDevices();
377 if (devices.size() == 0) {
378 bluetoothDevice = null;
379 } else {
380 // Always use first device is list. Android only supports one device.
381 bluetoothDevice = devices.get(0);
382 }
383 if (bluetoothDevice == null) {
384 bluetoothState = State.HEADSET_UNAVAILABLE;
385 Log.d(TAG, "No connected bluetooth headset");
386 } else {
387 bluetoothState = State.HEADSET_AVAILABLE;
388 Log.d(TAG, "Connected bluetooth headset: "
389 + "name=" + bluetoothDevice.getName() + ", "
390 + "state=" + stateToString(bluetoothHeadset.getConnectionState(blu etoothDevice))
391 + ", SCO audio=" + bluetoothHeadset.isAudioConnected(bluetoothDevi ce));
392 }
393 Log.d(TAG, "updateDevice done: BT state=" + bluetoothState);
394 }
395
396 /** Ensures that the audio manager updates its list of available audio devices . */
397 private void updateAudioDeviceState() {
398 threadChecker.checkIsOnValidThread();
399 Log.d(TAG, "updateAudioDeviceState");
400 apprtcAudioManager.updateAudioDeviceState();
401 }
402
403 /** Starts timer which times out after BLUETOOTH_SCO_TIMEOUT_MS milliseconds. */
404 private void startTimer() {
405 threadChecker.checkIsOnValidThread();
406 Log.d(TAG, "startTimer");
407 handler.postDelayed(bluetoothTimeoutRunnable, BLUETOOTH_SCO_TIMEOUT_MS);
408 }
409
410 /** Cancels any outstanding timer tasks. */
411 private void cancelTimer() {
412 threadChecker.checkIsOnValidThread();
413 Log.d(TAG, "cancelTimer");
414 handler.removeCallbacks(bluetoothTimeoutRunnable);
415 }
416
417 /**
418 * Called when start of the BT SCO channel takes too long time. Usually
419 * happens when the BT device has been turned on during an ongoing call.
420 */
421 private void bluetoothTimeout() {
422 threadChecker.checkIsOnValidThread();
423 if (bluetoothState == State.UNINITIALIZED
424 || bluetoothHeadset == null) {
425 return;
426 }
427 Log.d(TAG, "bluetoothTimeout: BT state=" + bluetoothState + ", "
428 + "attempts: " + scoConnectionAttempts + ", "
429 + "SCO is on: " + isScoOn());
430 if (bluetoothState != State.SCO_CONNECTING) {
431 return;
432 }
433 // Bluetooth SCO should be connecting; check the latest result.
434 boolean scoConnected = false;
435 List<BluetoothDevice> devices = bluetoothHeadset.getConnectedDevices();
436 if (devices.size() > 0) {
437 bluetoothDevice = devices.get(0);
438 if (bluetoothHeadset.isAudioConnected(bluetoothDevice)) {
439 Log.d(TAG, "SCO connected with " + bluetoothDevice.getName());
440 scoConnected = true;
441 } else {
442 Log.d(TAG, "SCO is not connected with " + bluetoothDevice.getName());
443 }
444 }
445 if (scoConnected) {
446 // We thought BT had timed out, but it's actually on; updating state.
447 bluetoothState = State.SCO_CONNECTED;
448 scoConnectionAttempts = 0;
449 updateAudioDeviceState();
450 } else {
451 // Give up and "cancel" our request by calling stopBluetoothSco().
452 Log.w(TAG, "BT failed to connect after timeout");
453 stopScoAudio();
454 updateAudioDeviceState();
455 }
456 Log.d(TAG, "bluetoothTimeout done: BT state=" + bluetoothState);
457 }
458
459 /** Checks if the process has as specified permission or not. */
460 private boolean hasPermission(String permission) {
461 return apprtcContext.checkPermission(permission, Process.myPid(), Process.my Uid())
462 == PackageManager.PERMISSION_GRANTED;
463 }
464
465 /** Checks whether audio uses Bluetooth SCO. */
466 private boolean isScoOn() {
467 return audioManager.isBluetoothScoOn();
468 }
469
470 // Helper method for receiver registration.
471 private void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
472 apprtcContext.registerReceiver(receiver, filter);
473 }
474
475 // Helper method for unregistration of an existing receiver.
476 private void unregisterReceiver(BroadcastReceiver receiver) {
477 apprtcContext.unregisterReceiver(receiver);
478 }
479
480 /** Logs the state of the local Bluetooth adapter. */
481 private void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
482 Log.d(TAG, "BluetoothAdapter: "
483 + "enabled=" + localAdapter.isEnabled() + ", "
484 + "state=" + stateToString(localAdapter.getState()) + ", "
485 + "name=" + localAdapter.getName() + ", "
486 + "address=" + localAdapter.getAddress());
487 // Log the set of BluetoothDevice objects that are bonded (paired) to the lo cal adapter.
488 Set<BluetoothDevice> pairedDevices = localAdapter.getBondedDevices();
489 if (pairedDevices.size() > 0) {
490 Log.d(TAG, "paired devices:");
491 for (BluetoothDevice device : pairedDevices) {
492 Log.d(TAG, " name=" + device.getName() + ", address=" + device.getAddres s());
493 }
494 }
495 }
496
497 /** Converts BluetoothAdapter states into local string representations. */
498 private String stateToString(int state) {
499 String stateString;
500 switch (state) {
501 case BluetoothAdapter.STATE_DISCONNECTED:
502 // The profile is in disconnected state.
503 stateString = "DISCONNECTED";
504 break;
505 case BluetoothAdapter.STATE_CONNECTED:
506 // The profile is in connected state.
507 stateString = "CONNECTED";
508 break;
509 case BluetoothAdapter.STATE_CONNECTING:
510 // The profile is in connecting state.
511 stateString = "CONNECTING";
512 break;
513 case BluetoothAdapter.STATE_DISCONNECTING:
514 // The profile is in disconnecting state.
515 stateString = "DISCONNECTING";
516 break;
517 case BluetoothAdapter.STATE_OFF:
518 // Indicates the local Bluetooth adapter is off.
519 stateString = "OFF";
520 break;
521 case BluetoothAdapter.STATE_ON:
522 // Indicates the local Bluetooth adapter is on, and ready for use.
523 stateString = "ON";
524 break;
525 case BluetoothAdapter.STATE_TURNING_OFF:
526 // Indicates the local Bluetooth adapter is turning off. Local clients s hould immediately
527 // attempt graceful disconnection of any remote links.
528 stateString = "TURNING_OFF";
529 break;
530 case BluetoothAdapter.STATE_TURNING_ON:
531 // Indicates the local Bluetooth adapter is turning on. However local cl ients should wait
532 // for STATE_ON before attempting to use the adapter.
533 stateString = "TURNING_ON";
534 break;
535 default:
536 stateString = "INVALID";
537 break;
538 }
539 return stateString;
540 }
541 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698