• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 
17 package com.android.bluetooth.hid;
18 
19 import android.bluetooth.BluetoothDevice;
20 import android.bluetooth.BluetoothInputDevice;
21 import android.bluetooth.BluetoothProfile;
22 import android.bluetooth.IBluetoothInputDevice;
23 import android.content.Intent;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.provider.Settings;
28 import android.util.Log;
29 
30 import com.android.bluetooth.btservice.AdapterService;
31 import com.android.bluetooth.btservice.ProfileService;
32 import com.android.bluetooth.Utils;
33 
34 import java.util.ArrayList;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 
40 /**
41  * Provides Bluetooth Hid Host profile, as a service in
42  * the Bluetooth application.
43  * @hide
44  */
45 public class HidService extends ProfileService {
46     private static final boolean DBG = true;
47     private static final String TAG = "HidService";
48 
49     private Map<BluetoothDevice, Integer> mInputDevices;
50     private boolean mNativeAvailable;
51     private static HidService sHidService;
52     private BluetoothDevice mTargetDevice = null;
53 
54     private static final int MESSAGE_CONNECT = 1;
55     private static final int MESSAGE_DISCONNECT = 2;
56     private static final int MESSAGE_CONNECT_STATE_CHANGED = 3;
57     private static final int MESSAGE_GET_PROTOCOL_MODE = 4;
58     private static final int MESSAGE_VIRTUAL_UNPLUG = 5;
59     private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6;
60     private static final int MESSAGE_SET_PROTOCOL_MODE = 7;
61     private static final int MESSAGE_GET_REPORT = 8;
62     private static final int MESSAGE_ON_GET_REPORT = 9;
63     private static final int MESSAGE_SET_REPORT = 10;
64     private static final int MESSAGE_SEND_DATA = 11;
65     private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12;
66     private static final int MESSAGE_ON_HANDSHAKE = 13;
67 
68     static {
classInitNative()69         classInitNative();
70     }
71 
getName()72     public String getName() {
73         return TAG;
74     }
75 
initBinder()76     public IProfileServiceBinder initBinder() {
77         return new BluetoothInputDeviceBinder(this);
78     }
79 
start()80     protected boolean start() {
81         mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>());
82         initializeNative();
83         mNativeAvailable=true;
84         setHidService(this);
85         return true;
86     }
87 
stop()88     protected boolean stop() {
89         if (DBG) log("Stopping Bluetooth HidService");
90         return true;
91     }
92 
cleanup()93     protected boolean cleanup() {
94         if (mNativeAvailable) {
95             cleanupNative();
96             mNativeAvailable=false;
97         }
98 
99         if(mInputDevices != null) {
100             for (BluetoothDevice device : mInputDevices.keySet()) {
101                 int inputDeviceState = getConnectionState(device);
102                 if (inputDeviceState != BluetoothProfile.STATE_DISCONNECTED) {
103                     broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
104                 }
105             }
106             mInputDevices.clear();
107         }
108         clearHidService();
109         return true;
110     }
111 
getHidService()112     public static synchronized HidService getHidService(){
113         if (sHidService != null && sHidService.isAvailable()) {
114             if (DBG) Log.d(TAG, "getHidService(): returning " + sHidService);
115             return sHidService;
116         }
117         if (DBG)  {
118             if (sHidService == null) {
119                 Log.d(TAG, "getHidService(): service is NULL");
120             } else if (!(sHidService.isAvailable())) {
121                 Log.d(TAG,"getHidService(): service is not available");
122             }
123         }
124         return null;
125     }
126 
setHidService(HidService instance)127     private static synchronized void setHidService(HidService instance) {
128         if (instance != null && instance.isAvailable()) {
129             if (DBG) Log.d(TAG, "setHidService(): set to: " + sHidService);
130             sHidService = instance;
131         } else {
132             if (DBG)  {
133                 if (sHidService == null) {
134                     Log.d(TAG, "setHidService(): service not available");
135                 } else if (!sHidService.isAvailable()) {
136                     Log.d(TAG,"setHidService(): service is cleaning up");
137                 }
138             }
139         }
140     }
141 
clearHidService()142     private static synchronized void clearHidService() {
143         sHidService = null;
144     }
145 
146 
147     private final Handler mHandler = new Handler() {
148 
149         @Override
150         public void handleMessage(Message msg) {
151             switch (msg.what) {
152                 case MESSAGE_CONNECT:
153                 {
154                     BluetoothDevice device = (BluetoothDevice) msg.obj;
155                     if (!connectHidNative(Utils.getByteAddress(device)) ) {
156                         broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
157                         broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
158                         break;
159                     }
160                     mTargetDevice = device;
161                 }
162                     break;
163                 case MESSAGE_DISCONNECT:
164                 {
165                     BluetoothDevice device = (BluetoothDevice) msg.obj;
166                     if (!disconnectHidNative(Utils.getByteAddress(device)) ) {
167                         broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
168                         broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
169                         break;
170                     }
171                 }
172                     break;
173                 case MESSAGE_CONNECT_STATE_CHANGED:
174                 {
175                     BluetoothDevice device = getDevice((byte[]) msg.obj);
176                     int halState = msg.arg1;
177                     Integer prevStateInteger = mInputDevices.get(device);
178                     int prevState = (prevStateInteger == null) ?
179                         BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger;
180                     if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+
181                         convertHalState(halState)+", prevState:"+prevState);
182                     if(halState == CONN_STATE_CONNECTED &&
183                        prevState == BluetoothInputDevice.STATE_DISCONNECTED &&
184                        (!okToConnect(device))) {
185                         if (DBG) Log.d(TAG,"Incoming HID connection rejected");
186                         disconnectHidNative(Utils.getByteAddress(device));
187                     } else {
188                         broadcastConnectionState(device, convertHalState(halState));
189                     }
190                     if (halState == CONN_STATE_CONNECTED &&
191                         (mTargetDevice != null && mTargetDevice.equals(device))) {
192                         mTargetDevice = null;
193                         // local device originated connection to hid device, move out
194                         // of quiet mode
195                         AdapterService adapterService = AdapterService.getAdapterService();
196                         adapterService.enable(false);
197                     }
198                 }
199                     break;
200                 case MESSAGE_GET_PROTOCOL_MODE:
201                 {
202                     BluetoothDevice device = (BluetoothDevice) msg.obj;
203                     if(!getProtocolModeNative(Utils.getByteAddress(device)) ) {
204                         Log.e(TAG, "Error: get protocol mode native returns false");
205                     }
206                 }
207                 break;
208 
209                 case MESSAGE_ON_GET_PROTOCOL_MODE:
210                 {
211                     BluetoothDevice device = getDevice((byte[]) msg.obj);
212                     int protocolMode = msg.arg1;
213                     broadcastProtocolMode(device, protocolMode);
214                 }
215                 break;
216                 case MESSAGE_VIRTUAL_UNPLUG:
217                 {
218                     BluetoothDevice device = (BluetoothDevice) msg.obj;
219                     if(!virtualUnPlugNative(Utils.getByteAddress(device))) {
220                         Log.e(TAG, "Error: virtual unplug native returns false");
221                     }
222                 }
223                 break;
224                 case MESSAGE_SET_PROTOCOL_MODE:
225                 {
226                     BluetoothDevice device = (BluetoothDevice) msg.obj;
227                     byte protocolMode = (byte) msg.arg1;
228                     log("sending set protocol mode(" + protocolMode + ")");
229                     if(!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) {
230                         Log.e(TAG, "Error: set protocol mode native returns false");
231                     }
232                 }
233                 break;
234                 case MESSAGE_GET_REPORT:
235                 {
236                     BluetoothDevice device = (BluetoothDevice) msg.obj;
237                     Bundle data = msg.getData();
238                     byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
239                     byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID);
240                     int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
241                     if(!getReportNative(Utils.getByteAddress(device), reportType, reportId, bufferSize)) {
242                         Log.e(TAG, "Error: get report native returns false");
243                     }
244                 }
245                 break;
246                 case MESSAGE_ON_GET_REPORT:
247                 {
248                     BluetoothDevice device = getDevice((byte[])msg.obj);
249                     Bundle data = msg.getData();
250                     byte[] report = data.getByteArray(BluetoothInputDevice.EXTRA_REPORT);
251                     int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
252                     broadcastReport(device, report, bufferSize);
253                 }
254                 break;
255                 case MESSAGE_ON_HANDSHAKE:
256                 {
257                     BluetoothDevice device = getDevice((byte[])msg.obj);
258                     int status = msg.arg1;
259                     broadcastHandshake(device, status);
260                 }
261                 break;
262                 case MESSAGE_SET_REPORT:
263                 {
264                     BluetoothDevice device = (BluetoothDevice) msg.obj;
265                     Bundle data = msg.getData();
266                     byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
267                     String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
268                     if(!setReportNative(Utils.getByteAddress(device), reportType, report)) {
269                         Log.e(TAG, "Error: set report native returns false");
270                     }
271                 }
272                 break;
273                 case MESSAGE_SEND_DATA:
274                 {
275                     BluetoothDevice device = (BluetoothDevice) msg.obj;
276                     Bundle data = msg.getData();
277                     String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
278                     if(!sendDataNative(Utils.getByteAddress(device), report)) {
279                         Log.e(TAG, "Error: send data native returns false");
280                     }
281                 }
282                 break;
283                 case MESSAGE_ON_VIRTUAL_UNPLUG:
284                 {
285                     BluetoothDevice device = getDevice((byte[]) msg.obj);
286                     int status = msg.arg1;
287                     broadcastVirtualUnplugStatus(device, status);
288                 }
289                 break;
290             }
291         }
292     };
293 
294     /**
295      * Handlers for incoming service calls
296      */
297     private static class BluetoothInputDeviceBinder extends IBluetoothInputDevice.Stub implements IProfileServiceBinder{
298         private HidService mService;
BluetoothInputDeviceBinder(HidService svc)299         public BluetoothInputDeviceBinder(HidService svc) {
300             mService = svc;
301         }
302 
cleanup()303         public boolean cleanup() {
304             mService = null;
305             return true;
306         }
307 
getService()308         private HidService getService() {
309             if (!Utils.checkCaller()) {
310                 Log.w(TAG,"InputDevice call not allowed for non-active user");
311                 return null;
312             }
313 
314             if (mService  != null && mService.isAvailable()) {
315                 return mService;
316             }
317             return null;
318         }
319 
connect(BluetoothDevice device)320         public boolean connect(BluetoothDevice device) {
321             HidService service = getService();
322             if (service == null) return false;
323             return service.connect(device);
324         }
325 
disconnect(BluetoothDevice device)326         public boolean disconnect(BluetoothDevice device) {
327             HidService service = getService();
328             if (service == null) return false;
329             return service.disconnect(device);
330         }
331 
getConnectionState(BluetoothDevice device)332         public int getConnectionState(BluetoothDevice device) {
333             HidService service = getService();
334             if (service == null) return BluetoothInputDevice.STATE_DISCONNECTED;
335             return service.getConnectionState(device);
336         }
337 
getConnectedDevices()338         public List<BluetoothDevice> getConnectedDevices() {
339             return getDevicesMatchingConnectionStates(
340                     new int[] {BluetoothProfile.STATE_CONNECTED});
341         }
342 
getDevicesMatchingConnectionStates(int[] states)343         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
344             HidService service = getService();
345             if (service == null) return new ArrayList<BluetoothDevice>(0);
346             return service.getDevicesMatchingConnectionStates(states);
347         }
348 
setPriority(BluetoothDevice device, int priority)349         public boolean setPriority(BluetoothDevice device, int priority) {
350             HidService service = getService();
351             if (service == null) return false;
352             return service.setPriority(device, priority);
353         }
354 
getPriority(BluetoothDevice device)355         public int getPriority(BluetoothDevice device) {
356             HidService service = getService();
357             if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
358             return service.getPriority(device);
359         }
360 
361         /* The following APIs regarding test app for compliance */
getProtocolMode(BluetoothDevice device)362         public boolean getProtocolMode(BluetoothDevice device) {
363             HidService service = getService();
364             if (service == null) return false;
365             return service.getProtocolMode(device);
366         }
367 
virtualUnplug(BluetoothDevice device)368         public boolean virtualUnplug(BluetoothDevice device) {
369             HidService service = getService();
370             if (service == null) return false;
371             return service.virtualUnplug(device);
372         }
373 
setProtocolMode(BluetoothDevice device, int protocolMode)374         public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
375             HidService service = getService();
376             if (service == null) return false;
377             return service.setProtocolMode(device, protocolMode);
378         }
379 
getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize)380         public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
381             HidService service = getService();
382             if (service == null) return false;
383             return service.getReport(device, reportType, reportId, bufferSize) ;
384         }
385 
setReport(BluetoothDevice device, byte reportType, String report)386         public boolean setReport(BluetoothDevice device, byte reportType, String report) {
387             HidService service = getService();
388             if (service == null) return false;
389             return service.setReport(device, reportType, report);
390         }
391 
sendData(BluetoothDevice device, String report)392         public boolean sendData(BluetoothDevice device, String report) {
393             HidService service = getService();
394             if (service == null) return false;
395             return service.sendData(device, report);
396         }
397     };
398 
399     //APIs
connect(BluetoothDevice device)400     boolean connect(BluetoothDevice device) {
401         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
402         if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) {
403             Log.e(TAG, "Hid Device not disconnected: " + device);
404             return false;
405         }
406         if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
407             Log.e(TAG, "Hid Device PRIORITY_OFF: " + device);
408             return false;
409         }
410 
411         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device);
412         mHandler.sendMessage(msg);
413         return true;
414     }
415 
disconnect(BluetoothDevice device)416     boolean disconnect(BluetoothDevice device) {
417         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
418         Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device);
419         mHandler.sendMessage(msg);
420         return true;
421     }
422 
getConnectionState(BluetoothDevice device)423     int getConnectionState(BluetoothDevice device) {
424         if (mInputDevices.get(device) == null) {
425             return BluetoothInputDevice.STATE_DISCONNECTED;
426         }
427         return mInputDevices.get(device);
428     }
429 
getDevicesMatchingConnectionStates(int[] states)430     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
431         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
432         List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
433 
434         for (BluetoothDevice device: mInputDevices.keySet()) {
435             int inputDeviceState = getConnectionState(device);
436             for (int state : states) {
437                 if (state == inputDeviceState) {
438                     inputDevices.add(device);
439                     break;
440                 }
441             }
442         }
443         return inputDevices;
444     }
445 
setPriority(BluetoothDevice device, int priority)446     public boolean setPriority(BluetoothDevice device, int priority) {
447         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
448                                        "Need BLUETOOTH_ADMIN permission");
449         Settings.Global.putInt(getContentResolver(),
450             Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
451             priority);
452         if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
453         return true;
454     }
455 
getPriority(BluetoothDevice device)456     public  int getPriority(BluetoothDevice device) {
457         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
458                                        "Need BLUETOOTH_ADMIN permission");
459         int priority = Settings.Global.getInt(getContentResolver(),
460             Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
461             BluetoothProfile.PRIORITY_UNDEFINED);
462         return priority;
463     }
464 
465     /* The following APIs regarding test app for compliance */
getProtocolMode(BluetoothDevice device)466     boolean getProtocolMode(BluetoothDevice device) {
467         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
468                                        "Need BLUETOOTH_ADMIN permission");
469         int state = this.getConnectionState(device);
470         if (state != BluetoothInputDevice.STATE_CONNECTED) {
471             return false;
472         }
473         Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE,device);
474         mHandler.sendMessage(msg);
475         return true;
476         /* String objectPath = getObjectPathFromAddress(device.getAddress());
477             return getProtocolModeInputDeviceNative(objectPath);*/
478     }
479 
virtualUnplug(BluetoothDevice device)480     boolean virtualUnplug(BluetoothDevice device) {
481         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
482                                        "Need BLUETOOTH_ADMIN permission");
483         int state = this.getConnectionState(device);
484         if (state != BluetoothInputDevice.STATE_CONNECTED) {
485             return false;
486         }
487         Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG,device);
488         mHandler.sendMessage(msg);
489         return true;
490     }
491 
setProtocolMode(BluetoothDevice device, int protocolMode)492     boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
493         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
494                                        "Need BLUETOOTH_ADMIN permission");
495         int state = this.getConnectionState(device);
496         if (state != BluetoothInputDevice.STATE_CONNECTED) {
497             return false;
498         }
499         Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE);
500         msg.obj = device;
501         msg.arg1 = protocolMode;
502         mHandler.sendMessage(msg);
503         return true ;
504     }
505 
getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize)506     boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
507         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
508                                        "Need BLUETOOTH_ADMIN permission");
509         int state = this.getConnectionState(device);
510         if (state != BluetoothInputDevice.STATE_CONNECTED) {
511             return false;
512         }
513         Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
514         msg.obj = device;
515         Bundle data = new Bundle();
516         data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
517         data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId);
518         data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize);
519         msg.setData(data);
520         mHandler.sendMessage(msg);
521         return true ;
522     }
523 
setReport(BluetoothDevice device, byte reportType, String report)524     boolean setReport(BluetoothDevice device, byte reportType, String report) {
525         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
526                                                    "Need BLUETOOTH_ADMIN permission");
527         int state = this.getConnectionState(device);
528         if (state != BluetoothInputDevice.STATE_CONNECTED) {
529             return false;
530         }
531         Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
532         msg.obj = device;
533         Bundle data = new Bundle();
534         data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
535         data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
536         msg.setData(data);
537         mHandler.sendMessage(msg);
538         return true ;
539 
540     }
541 
sendData(BluetoothDevice device, String report)542     boolean sendData(BluetoothDevice device, String report) {
543         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
544                                                    "Need BLUETOOTH_ADMIN permission");
545         int state = this.getConnectionState(device);
546         if (state != BluetoothInputDevice.STATE_CONNECTED) {
547             return false;
548         }
549 
550         return sendDataNative(Utils.getByteAddress(device), report);
551     }
552 
onGetProtocolMode(byte[] address, int mode)553     private void onGetProtocolMode(byte[] address, int mode) {
554         Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE);
555         msg.obj = address;
556         msg.arg1 = mode;
557         mHandler.sendMessage(msg);
558     }
559 
onGetReport(byte[] address, byte[] report, int rpt_size)560     private void onGetReport(byte[] address, byte[] report, int rpt_size) {
561         Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT);
562         msg.obj = address;
563         Bundle data = new Bundle();
564         data.putByteArray(BluetoothInputDevice.EXTRA_REPORT, report);
565         data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size);
566         msg.setData(data);
567         mHandler.sendMessage(msg);
568     }
569 
onHandshake(byte[] address, int status)570     private void onHandshake(byte[] address, int status) {
571         Message msg = mHandler.obtainMessage(MESSAGE_ON_HANDSHAKE);
572         msg.obj = address;
573         msg.arg1 = status;
574         mHandler.sendMessage(msg);
575     }
576 
onVirtualUnplug(byte[] address, int status)577     private void onVirtualUnplug(byte[] address, int status) {
578         Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG);
579         msg.obj = address;
580         msg.arg1 = status;
581         mHandler.sendMessage(msg);
582     }
583 
onConnectStateChanged(byte[] address, int state)584     private void onConnectStateChanged(byte[] address, int state) {
585         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
586         msg.obj = address;
587         msg.arg1 = state;
588         mHandler.sendMessage(msg);
589     }
590 
591     // This method does not check for error conditon (newState == prevState)
broadcastConnectionState(BluetoothDevice device, int newState)592     private void broadcastConnectionState(BluetoothDevice device, int newState) {
593         Integer prevStateInteger = mInputDevices.get(device);
594         int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED :
595                                                      prevStateInteger;
596         if (prevState == newState) {
597             Log.w(TAG, "no state change: " + newState);
598             return;
599         }
600         mInputDevices.put(device, newState);
601 
602         /* Notifying the connection state change of the profile before sending the intent for
603            connection state change, as it was causing a race condition, with the UI not being
604            updated with the correct connection state. */
605         log("Connection state " + device + ": " + prevState + "->" + newState);
606         Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
607         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
608         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
609         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
610         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
611         sendBroadcast(intent, BLUETOOTH_PERM);
612     }
613 
broadcastHandshake(BluetoothDevice device, int status)614     private void broadcastHandshake(BluetoothDevice device, int status) {
615         Intent intent = new Intent(BluetoothInputDevice.ACTION_HANDSHAKE);
616         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
617         intent.putExtra(BluetoothInputDevice.EXTRA_STATUS, status);
618         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
619         sendBroadcast(intent, BLUETOOTH_PERM);
620     }
621 
broadcastProtocolMode(BluetoothDevice device, int protocolMode)622     private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) {
623         Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED);
624         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
625         intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode);
626         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
627         sendBroadcast(intent, BLUETOOTH_PERM);
628         if (DBG) log("Protocol Mode (" + device + "): " + protocolMode);
629     }
630 
broadcastReport(BluetoothDevice device, byte[] report, int rpt_size)631     private void broadcastReport(BluetoothDevice device, byte[] report, int rpt_size) {
632         Intent intent = new Intent(BluetoothInputDevice.ACTION_REPORT);
633         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
634         intent.putExtra(BluetoothInputDevice.EXTRA_REPORT, report);
635         intent.putExtra(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size);
636         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
637         sendBroadcast(intent, BLUETOOTH_PERM);
638     }
639 
broadcastVirtualUnplugStatus(BluetoothDevice device, int status)640     private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) {
641         Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS);
642         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
643         intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status);
644         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
645         sendBroadcast(intent, BLUETOOTH_PERM);
646     }
647 
okToConnect(BluetoothDevice device)648     private boolean okToConnect(BluetoothDevice device) {
649         AdapterService adapterService = AdapterService.getAdapterService();
650         //check if it is inbound connection in Quiet mode, priority and Bond status
651         //to decide if its ok to allow this connection
652         if((adapterService == null)||
653            ((adapterService.isQuietModeEnabled()) &&(mTargetDevice == null)) ||
654            (BluetoothProfile.PRIORITY_OFF == getPriority(device)) ||
655            (device.getBondState() == BluetoothDevice.BOND_NONE))
656             return false;
657 
658         return true;
659     }
convertHalState(int halState)660     private static int convertHalState(int halState) {
661         switch (halState) {
662             case CONN_STATE_CONNECTED:
663                 return BluetoothProfile.STATE_CONNECTED;
664             case CONN_STATE_CONNECTING:
665                 return BluetoothProfile.STATE_CONNECTING;
666             case CONN_STATE_DISCONNECTED:
667                 return BluetoothProfile.STATE_DISCONNECTED;
668             case CONN_STATE_DISCONNECTING:
669                 return BluetoothProfile.STATE_DISCONNECTING;
670             default:
671                 Log.e(TAG, "bad hid connection state: " + halState);
672                 return BluetoothProfile.STATE_DISCONNECTED;
673         }
674     }
675 
676     @Override
dump(StringBuilder sb)677     public void dump(StringBuilder sb) {
678         super.dump(sb);
679         println(sb, "mTargetDevice: " + mTargetDevice);
680         println(sb, "mInputDevices:");
681         for (BluetoothDevice device : mInputDevices.keySet()) {
682             println(sb, "  " + device + " : " + mInputDevices.get(device));
683         }
684     }
685 
686     // Constants matching Hal header file bt_hh.h
687     // bthh_connection_state_t
688     private final static int CONN_STATE_CONNECTED = 0;
689     private final static int CONN_STATE_CONNECTING = 1;
690     private final static int CONN_STATE_DISCONNECTED = 2;
691     private final static int CONN_STATE_DISCONNECTING = 3;
692 
classInitNative()693     private native static void classInitNative();
initializeNative()694     private native void initializeNative();
cleanupNative()695     private native void cleanupNative();
connectHidNative(byte[] btAddress)696     private native boolean connectHidNative(byte[] btAddress);
disconnectHidNative(byte[] btAddress)697     private native boolean disconnectHidNative(byte[] btAddress);
getProtocolModeNative(byte[] btAddress)698     private native boolean getProtocolModeNative(byte[] btAddress);
virtualUnPlugNative(byte[] btAddress)699     private native boolean virtualUnPlugNative(byte[] btAddress);
setProtocolModeNative(byte[] btAddress, byte protocolMode)700     private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode);
getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize)701     private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize);
setReportNative(byte[] btAddress, byte reportType, String report)702     private native boolean setReportNative(byte[] btAddress, byte reportType, String report);
sendDataNative(byte[] btAddress, String report)703     private native boolean sendDataNative(byte[] btAddress, String report);
704 }
705