blob: daf3bad3774d01574e2ac832ea36a42256b2d547 [file] [log] [blame]
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -07001/*
2 * Copyright (C) 2011 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
Matthew Xie13450df2012-03-22 17:18:37 -070019import android.content.ComponentName;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070020import android.content.Context;
Matthew Xie13450df2012-03-22 17:18:37 -070021import android.content.Intent;
22import android.content.ServiceConnection;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070023import android.os.IBinder;
24import android.os.ParcelFileDescriptor;
25import android.os.RemoteException;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070026import android.util.Log;
27
28import java.util.ArrayList;
29import java.util.List;
30
31/**
32 * Public API for Bluetooth Health Profile.
33 *
34 * <p>BluetoothHealth is a proxy object for controlling the Bluetooth
35 * Service via IPC.
36 *
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -070037 * <p> How to connect to a health device which is acting in the source role.
38 * <li> Use {@link BluetoothAdapter#getProfileProxy} to get
39 * the BluetoothHealth proxy object. </li>
40 * <li> Create an {@link BluetoothHealth} callback and call
41 * {@link #registerSinkAppConfiguration} to register an application
42 * configuration </li>
43 * <li> Pair with the remote device. This currently needs to be done manually
44 * from Bluetooth Settings </li>
45 * <li> Connect to a health device using {@link #connectChannelToSource}. Some
46 * devices will connect the channel automatically. The {@link BluetoothHealth}
47 * callback will inform the application of channel state change. </li>
48 * <li> Use the file descriptor provided with a connected channel to read and
49 * write data to the health channel. </li>
50 * <li> The received data needs to be interpreted using a health manager which
51 * implements the IEEE 11073-xxxxx specifications.
52 * <li> When done, close the health channel by calling {@link #disconnectChannel}
53 * and unregister the application configuration calling
54 * {@link #unregisterAppConfiguration}
55 *
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070056 */
57public final class BluetoothHealth implements BluetoothProfile {
58 private static final String TAG = "BluetoothHealth";
fredc0f420372012-04-12 00:02:00 -070059 private static final boolean DBG = true;
Matthew Xie563e4142012-10-09 22:10:37 -070060 private static final boolean VDBG = false;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070061
62 /**
63 * Health Profile Source Role - the health device.
64 */
65 public static final int SOURCE_ROLE = 1 << 0;
66
67 /**
68 * Health Profile Sink Role the device talking to the health device.
69 */
70 public static final int SINK_ROLE = 1 << 1;
71
72 /**
73 * Health Profile - Channel Type used - Reliable
74 */
75 public static final int CHANNEL_TYPE_RELIABLE = 10;
76
77 /**
78 * Health Profile - Channel Type used - Streaming
79 */
80 public static final int CHANNEL_TYPE_STREAMING = 11;
81
82 /**
83 * @hide
84 */
85 public static final int CHANNEL_TYPE_ANY = 12;
86
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -070087 /** @hide */
88 public static final int HEALTH_OPERATION_SUCCESS = 6000;
89 /** @hide */
90 public static final int HEALTH_OPERATION_ERROR = 6001;
91 /** @hide */
92 public static final int HEALTH_OPERATION_INVALID_ARGS = 6002;
93 /** @hide */
94 public static final int HEALTH_OPERATION_GENERIC_FAILURE = 6003;
95 /** @hide */
96 public static final int HEALTH_OPERATION_NOT_FOUND = 6004;
97 /** @hide */
98 public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
99
fredc0f420372012-04-12 00:02:00 -0700100 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
101 new IBluetoothStateChangeCallback.Stub() {
102 public void onBluetoothStateChange(boolean up) {
103 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
104 if (!up) {
Matthew Xie563e4142012-10-09 22:10:37 -0700105 if (VDBG) Log.d(TAG,"Unbinding service...");
fredc0f420372012-04-12 00:02:00 -0700106 synchronized (mConnection) {
107 try {
108 mService = null;
109 mContext.unbindService(mConnection);
110 } catch (Exception re) {
111 Log.e(TAG,"",re);
112 }
113 }
114 } else {
115 synchronized (mConnection) {
116 try {
117 if (mService == null) {
Matthew Xie563e4142012-10-09 22:10:37 -0700118 if (VDBG) Log.d(TAG,"Binding service...");
Dianne Hackborn221ea892013-08-04 16:50:16 -0700119 doBind();
fredc0f420372012-04-12 00:02:00 -0700120 }
121 } catch (Exception re) {
122 Log.e(TAG,"",re);
123 }
124 }
125 }
126 }
127 };
128
Jaikumar Ganeshb5d2d452011-09-07 14:16:52 -0700129
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700130 /**
131 * Register an application configuration that acts as a Health SINK.
132 * This is the configuration that will be used to communicate with health devices
133 * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
134 * the callback is used to notify success or failure if the function returns true.
135 *
136 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
137 *
138 * @param name The friendly name associated with the application or configuration.
139 * @param dataType The dataType of the Source role of Health Profile to which
140 * the sink wants to connect to.
141 * @param callback A callback to indicate success or failure of the registration and
142 * all operations done on this application configuration.
143 * @return If true, callback will be called.
144 */
145 public boolean registerSinkAppConfiguration(String name, int dataType,
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700146 BluetoothHealthCallback callback) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700147 if (!isEnabled() || name == null) return false;
148
Matthew Xie563e4142012-10-09 22:10:37 -0700149 if (VDBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700150 return registerAppConfiguration(name, dataType, SINK_ROLE,
151 CHANNEL_TYPE_ANY, callback);
152 }
153
154 /**
155 * Register an application configuration that acts as a Health SINK or in a Health
156 * SOURCE role.This is an asynchronous call and so
157 * the callback is used to notify success or failure if the function returns true.
158 *
159 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
160 *
161 * @param name The friendly name associated with the application or configuration.
162 * @param dataType The dataType of the Source role of Health Profile.
163 * @param channelType The channel type. Will be one of
164 * {@link #CHANNEL_TYPE_RELIABLE} or
165 * {@link #CHANNEL_TYPE_STREAMING}
166 * @param callback - A callback to indicate success or failure.
167 * @return If true, callback will be called.
168 * @hide
169 */
170 public boolean registerAppConfiguration(String name, int dataType, int role,
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700171 int channelType, BluetoothHealthCallback callback) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700172 boolean result = false;
173 if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;
174
Matthew Xie563e4142012-10-09 22:10:37 -0700175 if (VDBG) log("registerApplication(" + name + ":" + dataType + ")");
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700176 BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700177 BluetoothHealthAppConfiguration config =
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700178 new BluetoothHealthAppConfiguration(name, dataType, role, channelType);
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700179
180 if (mService != null) {
181 try {
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700182 result = mService.registerAppConfiguration(config, wrapper);
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700183 } catch (RemoteException e) {
184 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700185 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700186 } else {
187 Log.w(TAG, "Proxy not attached to service");
188 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
189 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700190 return result;
191 }
192
193 /**
194 * Unregister an application configuration that has been registered using
195 * {@link #registerSinkAppConfiguration}
196 *
197 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
198 *
199 * @param config The health app configuration
200 * @return Success or failure.
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700201 */
202 public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
203 boolean result = false;
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700204 if (mService != null && isEnabled() && config != null) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700205 try {
206 result = mService.unregisterAppConfiguration(config);
207 } catch (RemoteException e) {
208 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700209 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700210 } else {
211 Log.w(TAG, "Proxy not attached to service");
212 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
213 }
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700214
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700215 return result;
216 }
217
218 /**
219 * Connect to a health device which has the {@link #SOURCE_ROLE}.
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700220 * This is an asynchronous call. If this function returns true, the callback
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700221 * associated with the application configuration will be called.
222 *
223 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
224 *
225 * @param device The remote Bluetooth device.
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700226 * @param config The application configuration which has been registered using
227 * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700228 * @return If true, the callback associated with the application config will be called.
229 */
230 public boolean connectChannelToSource(BluetoothDevice device,
231 BluetoothHealthAppConfiguration config) {
232 if (mService != null && isEnabled() && isValidDevice(device) &&
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700233 config != null) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700234 try {
235 return mService.connectChannelToSource(device, config);
236 } catch (RemoteException e) {
237 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700238 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700239 } else {
240 Log.w(TAG, "Proxy not attached to service");
241 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
242 }
243 return false;
244 }
245
246 /**
247 * Connect to a health device which has the {@link #SINK_ROLE}.
248 * This is an asynchronous call. If this function returns true, the callback
249 * associated with the application configuration will be called.
250 *
251 *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
252 *
253 * @param device The remote Bluetooth device.
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700254 * @param config The application configuration which has been registered using
255 * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700256 * @return If true, the callback associated with the application config will be called.
257 * @hide
258 */
259 public boolean connectChannelToSink(BluetoothDevice device,
260 BluetoothHealthAppConfiguration config, int channelType) {
261 if (mService != null && isEnabled() && isValidDevice(device) &&
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700262 config != null) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700263 try {
264 return mService.connectChannelToSink(device, config, channelType);
265 } catch (RemoteException e) {
266 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700267 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700268 } else {
269 Log.w(TAG, "Proxy not attached to service");
270 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
271 }
272 return false;
273 }
274
275 /**
276 * Disconnect a connected health channel.
277 * This is an asynchronous call. If this function returns true, the callback
278 * associated with the application configuration will be called.
279 *
280 *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
281 *
282 * @param device The remote Bluetooth device.
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700283 * @param config The application configuration which has been registered using
284 * {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700285 * @param channelId The channel id associated with the channel
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700286 * @return If true, the callback associated with the application config will be called.
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700287 */
288 public boolean disconnectChannel(BluetoothDevice device,
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700289 BluetoothHealthAppConfiguration config, int channelId) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700290 if (mService != null && isEnabled() && isValidDevice(device) &&
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700291 config != null) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700292 try {
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700293 return mService.disconnectChannel(device, config, channelId);
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700294 } catch (RemoteException e) {
295 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700296 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700297 } else {
298 Log.w(TAG, "Proxy not attached to service");
299 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
300 }
301 return false;
302 }
303
304 /**
305 * Get the file descriptor of the main channel associated with the remote device
306 * and application configuration.
307 *
308 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
309 *
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700310 * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
311 * when done.
312 *
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700313 * @param device The remote Bluetooth health device
314 * @param config The application configuration
315 * @return null on failure, ParcelFileDescriptor on success.
316 */
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700317 public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
318 BluetoothHealthAppConfiguration config) {
319 if (mService != null && isEnabled() && isValidDevice(device) &&
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700320 config != null) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700321 try {
322 return mService.getMainChannelFd(device, config);
323 } catch (RemoteException e) {
324 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700325 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700326 } else {
327 Log.w(TAG, "Proxy not attached to service");
328 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
329 }
330 return null;
331 }
332
333 /**
334 * Get the current connection state of the profile.
335 *
336 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
337 *
338 * This is not specific to any application configuration but represents the connection
339 * state of the local Bluetooth adapter with the remote device. This can be used
340 * by applications like status bar which would just like to know the state of the
341 * local adapter.
342 *
343 * @param device Remote bluetooth device.
344 * @return State of the profile connection. One of
345 * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
346 * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
347 */
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700348 @Override
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700349 public int getConnectionState(BluetoothDevice device) {
350 if (mService != null && isEnabled() && isValidDevice(device)) {
351 try {
352 return mService.getHealthDeviceConnectionState(device);
353 } catch (RemoteException e) {
354 Log.e(TAG, e.toString());
Matthew Xie13450df2012-03-22 17:18:37 -0700355 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700356 } else {
357 Log.w(TAG, "Proxy not attached to service");
358 if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
359 }
360 return STATE_DISCONNECTED;
361 }
362
363 /**
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700364 * Get connected devices for the health profile.
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700365 *
366 * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
367 *
368 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
369 *
370 * This is not specific to any application configuration but represents the connection
371 * state of the local Bluetooth adapter for this profile. This can be used
372 * by applications like status bar which would just like to know the state of the
373 * local adapter.
374 * @return List of devices. The list will be empty on error.
375 */
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700376 @Override
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700377 public List<BluetoothDevice> getConnectedDevices() {
378 if (mService != null && isEnabled()) {
379 try {
380 return mService.getConnectedHealthDevices();
381 } catch (RemoteException e) {
382 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
383 return new ArrayList<BluetoothDevice>();
Matthew Xie13450df2012-03-22 17:18:37 -0700384 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700385 }
386 if (mService == null) Log.w(TAG, "Proxy not attached to service");
387 return new ArrayList<BluetoothDevice>();
388 }
389
390 /**
391 * Get a list of devices that match any of the given connection
392 * states.
393 *
394 * <p> If none of the devices match any of the given states,
395 * an empty list will be returned.
396 *
397 * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
398 * This is not specific to any application configuration but represents the connection
399 * state of the local Bluetooth adapter for this profile. This can be used
400 * by applications like status bar which would just like to know the state of the
401 * local adapter.
402 *
403 * @param states Array of states. States can be one of
404 * {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
405 * {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
406 * @return List of devices. The list will be empty on error.
407 */
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700408 @Override
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700409 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
410 if (mService != null && isEnabled()) {
411 try {
412 return mService.getHealthDevicesMatchingConnectionStates(states);
413 } catch (RemoteException e) {
414 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
415 return new ArrayList<BluetoothDevice>();
Matthew Xie13450df2012-03-22 17:18:37 -0700416 }
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700417 }
418 if (mService == null) Log.w(TAG, "Proxy not attached to service");
419 return new ArrayList<BluetoothDevice>();
420 }
421
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700422 private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
423 private BluetoothHealthCallback mCallback;
424
425 public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
426 mCallback = callback;
427 }
428
429 @Override
430 public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
431 int status) {
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700432 mCallback.onHealthAppConfigurationStatusChange(config, status);
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700433 }
434
435 @Override
436 public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
437 BluetoothDevice device, int prevState, int newState,
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700438 ParcelFileDescriptor fd, int channelId) {
439 mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd,
440 channelId);
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700441 }
442 }
443
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700444 /** Health Channel Connection State - Disconnected */
445 public static final int STATE_CHANNEL_DISCONNECTED = 0;
446 /** Health Channel Connection State - Connecting */
447 public static final int STATE_CHANNEL_CONNECTING = 1;
448 /** Health Channel Connection State - Connected */
449 public static final int STATE_CHANNEL_CONNECTED = 2;
450 /** Health Channel Connection State - Disconnecting */
451 public static final int STATE_CHANNEL_DISCONNECTING = 3;
452
453 /** Health App Configuration registration success */
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700454 public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700455 /** Health App Configuration registration failure */
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700456 public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700457 /** Health App Configuration un-registration success */
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700458 public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700459 /** Health App Configuration un-registration failure */
Jaikumar Ganesheb9d3462011-08-31 15:36:05 -0700460 public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700461
Matthew Xie13450df2012-03-22 17:18:37 -0700462 private Context mContext;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700463 private ServiceListener mServiceListener;
Matthew Xie13450df2012-03-22 17:18:37 -0700464 private IBluetoothHealth mService;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700465 BluetoothAdapter mAdapter;
466
467 /**
468 * Create a BluetoothHealth proxy object.
469 */
Matthew Xie13450df2012-03-22 17:18:37 -0700470 /*package*/ BluetoothHealth(Context context, ServiceListener l) {
471 mContext = context;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700472 mServiceListener = l;
473 mAdapter = BluetoothAdapter.getDefaultAdapter();
fredc0f420372012-04-12 00:02:00 -0700474 IBluetoothManager mgr = mAdapter.getBluetoothManager();
475 if (mgr != null) {
476 try {
477 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
478 } catch (RemoteException e) {
479 Log.e(TAG,"",e);
480 }
481 }
482
Dianne Hackborn221ea892013-08-04 16:50:16 -0700483 doBind();
484 }
485
486 boolean doBind() {
487 Intent intent = new Intent(IBluetoothHealth.class.getName());
488 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
489 intent.setComponent(comp);
490 if (comp == null || !mContext.bindService(intent, mConnection, 0)) {
491 Log.e(TAG, "Could not bind to Bluetooth Health Service with " + intent);
492 return false;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700493 }
Dianne Hackborn221ea892013-08-04 16:50:16 -0700494 return true;
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700495 }
496
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800497 /*package*/ void close() {
Matthew Xie563e4142012-10-09 22:10:37 -0700498 if (VDBG) log("close()");
fredc0f420372012-04-12 00:02:00 -0700499 IBluetoothManager mgr = mAdapter.getBluetoothManager();
500 if (mgr != null) {
501 try {
502 mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
503 } catch (Exception e) {
504 Log.e(TAG,"",e);
505 }
506 }
507
508 synchronized (mConnection) {
509 if (mService != null) {
510 try {
511 mService = null;
512 mContext.unbindService(mConnection);
513 } catch (Exception re) {
514 Log.e(TAG,"",re);
515 }
516 }
Matthew Xie13450df2012-03-22 17:18:37 -0700517 }
Jaikumar Ganesh9bb27512011-11-28 09:59:08 -0800518 mServiceListener = null;
519 }
520
Matthew Xie9b693992013-10-10 11:21:40 -0700521 private final ServiceConnection mConnection = new ServiceConnection() {
Matthew Xie13450df2012-03-22 17:18:37 -0700522 public void onServiceConnected(ComponentName className, IBinder service) {
523 if (DBG) Log.d(TAG, "Proxy object connected");
524 mService = IBluetoothHealth.Stub.asInterface(service);
525
526 if (mServiceListener != null) {
527 mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
528 }
529 }
530 public void onServiceDisconnected(ComponentName className) {
531 if (DBG) Log.d(TAG, "Proxy object disconnected");
532 mService = null;
533 if (mServiceListener != null) {
534 mServiceListener.onServiceDisconnected(BluetoothProfile.HEALTH);
535 }
536 }
537 };
538
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700539 private boolean isEnabled() {
540 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
541
542 if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
543 log("Bluetooth is Not enabled");
544 return false;
545 }
546
547 private boolean isValidDevice(BluetoothDevice device) {
548 if (device == null) return false;
549
550 if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
551 return false;
552 }
553
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700554 private boolean checkAppParam(String name, int role, int channelType,
Jaikumar Ganeshfb658c72011-07-06 17:37:02 -0700555 BluetoothHealthCallback callback) {
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700556 if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
557 (channelType != CHANNEL_TYPE_RELIABLE &&
558 channelType != CHANNEL_TYPE_STREAMING &&
559 channelType != CHANNEL_TYPE_ANY) || callback == null) {
560 return false;
561 }
562 if (role == SOURCE_ROLE && channelType == CHANNEL_TYPE_ANY) return false;
563 return true;
564 }
565
566 private static void log(String msg) {
567 Log.d(TAG, msg);
568 }
569}