• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.app.ActivityManager;
20 import android.bluetooth.BluetoothDevice;
21 import android.bluetooth.BluetoothHidDevice;
22 import android.bluetooth.BluetoothHidDeviceAppQosSettings;
23 import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
24 import android.bluetooth.BluetoothProfile;
25 import android.bluetooth.IBluetoothHidDevice;
26 import android.bluetooth.IBluetoothHidDeviceCallback;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.os.Binder;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.Message;
33 import android.os.Process;
34 import android.os.RemoteException;
35 import android.util.Log;
36 
37 import com.android.bluetooth.BluetoothMetricsProto;
38 import com.android.bluetooth.Utils;
39 import com.android.bluetooth.btservice.MetricsLogger;
40 import com.android.bluetooth.btservice.ProfileService;
41 import com.android.internal.annotations.VisibleForTesting;
42 
43 import java.nio.ByteBuffer;
44 import java.util.ArrayList;
45 import java.util.Arrays;
46 import java.util.List;
47 import java.util.NoSuchElementException;
48 
49 /** @hide */
50 public class HidDeviceService extends ProfileService {
51     private static final boolean DBG = false;
52     private static final String TAG = HidDeviceService.class.getSimpleName();
53 
54     private static final int MESSAGE_APPLICATION_STATE_CHANGED = 1;
55     private static final int MESSAGE_CONNECT_STATE_CHANGED = 2;
56     private static final int MESSAGE_GET_REPORT = 3;
57     private static final int MESSAGE_SET_REPORT = 4;
58     private static final int MESSAGE_SET_PROTOCOL = 5;
59     private static final int MESSAGE_INTR_DATA = 6;
60     private static final int MESSAGE_VC_UNPLUG = 7;
61     private static final int MESSAGE_IMPORTANCE_CHANGE = 8;
62 
63     private static final int FOREGROUND_IMPORTANCE_CUTOFF =
64             ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
65 
66     private static HidDeviceService sHidDeviceService;
67 
68     private HidDeviceNativeInterface mHidDeviceNativeInterface;
69 
70     private boolean mNativeAvailable = false;
71     private BluetoothDevice mHidDevice;
72     private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED;
73     private int mUserUid = 0;
74     private IBluetoothHidDeviceCallback mCallback;
75     private BluetoothHidDeviceDeathRecipient mDeathRcpt;
76     private ActivityManager mActivityManager;
77 
78     private HidDeviceServiceHandler mHandler;
79 
80     private class HidDeviceServiceHandler extends Handler {
81         @Override
handleMessage(Message msg)82         public void handleMessage(Message msg) {
83             if (DBG) {
84                 Log.d(TAG, "handleMessage(): msg.what=" + msg.what);
85             }
86 
87             switch (msg.what) {
88                 case MESSAGE_APPLICATION_STATE_CHANGED: {
89                     BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null;
90                     boolean success = (msg.arg1 != 0);
91 
92                     if (success) {
93                         Log.d(TAG, "App registered, set device to: " + device);
94                         mHidDevice = device;
95                     } else {
96                         mHidDevice = null;
97                     }
98 
99                     try {
100                         if (mCallback != null) {
101                             mCallback.onAppStatusChanged(device, success);
102                         } else {
103                             break;
104                         }
105                     } catch (RemoteException e) {
106                         Log.e(TAG, "e=" + e.toString());
107                         e.printStackTrace();
108                     }
109 
110                     if (success) {
111                         mDeathRcpt = new BluetoothHidDeviceDeathRecipient(HidDeviceService.this);
112                         if (mCallback != null) {
113                             IBinder binder = mCallback.asBinder();
114                             try {
115                                 binder.linkToDeath(mDeathRcpt, 0);
116                                 Log.i(TAG, "IBinder.linkToDeath() ok");
117                             } catch (RemoteException e) {
118                                 e.printStackTrace();
119                             }
120                         }
121                     } else if (mDeathRcpt != null) {
122                         if (mCallback != null) {
123                             IBinder binder = mCallback.asBinder();
124                             try {
125                                 binder.unlinkToDeath(mDeathRcpt, 0);
126                                 Log.i(TAG, "IBinder.unlinkToDeath() ok");
127                             } catch (NoSuchElementException e) {
128                                 e.printStackTrace();
129                             }
130                             mDeathRcpt.cleanup();
131                             mDeathRcpt = null;
132                         }
133                     }
134 
135                     if (!success) {
136                         mCallback = null;
137                     }
138 
139                     break;
140                 }
141 
142                 case MESSAGE_CONNECT_STATE_CHANGED: {
143                     BluetoothDevice device = (BluetoothDevice) msg.obj;
144                     int halState = msg.arg1;
145                     int state = convertHalState(halState);
146 
147                     if (state != BluetoothHidDevice.STATE_DISCONNECTED) {
148                         mHidDevice = device;
149                     }
150 
151                     setAndBroadcastConnectionState(device, state);
152 
153                     try {
154                         if (mCallback != null) {
155                             mCallback.onConnectionStateChanged(device, state);
156                         }
157                     } catch (RemoteException e) {
158                         e.printStackTrace();
159                     }
160                     break;
161                 }
162 
163                 case MESSAGE_GET_REPORT:
164                     byte type = (byte) msg.arg1;
165                     byte id = (byte) msg.arg2;
166                     int bufferSize = msg.obj == null ? 0 : ((Integer) msg.obj).intValue();
167 
168                     try {
169                         if (mCallback != null) {
170                             mCallback.onGetReport(mHidDevice, type, id, bufferSize);
171                         }
172                     } catch (RemoteException e) {
173                         e.printStackTrace();
174                     }
175                     break;
176 
177                 case MESSAGE_SET_REPORT: {
178                     byte reportType = (byte) msg.arg1;
179                     byte reportId = (byte) msg.arg2;
180                     byte[] data = ((ByteBuffer) msg.obj).array();
181 
182                     try {
183                         if (mCallback != null) {
184                             mCallback.onSetReport(mHidDevice, reportType, reportId, data);
185                         }
186                     } catch (RemoteException e) {
187                         e.printStackTrace();
188                     }
189                     break;
190                 }
191 
192                 case MESSAGE_SET_PROTOCOL:
193                     byte protocol = (byte) msg.arg1;
194 
195                     try {
196                         if (mCallback != null) {
197                             mCallback.onSetProtocol(mHidDevice, protocol);
198                         }
199                     } catch (RemoteException e) {
200                         e.printStackTrace();
201                     }
202                     break;
203 
204                 case MESSAGE_INTR_DATA:
205                     byte reportId = (byte) msg.arg1;
206                     byte[] data = ((ByteBuffer) msg.obj).array();
207 
208                     try {
209                         if (mCallback != null) {
210                             mCallback.onInterruptData(mHidDevice, reportId, data);
211                         }
212                     } catch (RemoteException e) {
213                         e.printStackTrace();
214                     }
215                     break;
216 
217                 case MESSAGE_VC_UNPLUG:
218                     try {
219                         if (mCallback != null) {
220                             mCallback.onVirtualCableUnplug(mHidDevice);
221                         }
222                     } catch (RemoteException e) {
223                         e.printStackTrace();
224                     }
225                     mHidDevice = null;
226                     break;
227 
228                 case MESSAGE_IMPORTANCE_CHANGE:
229                     int importance = msg.arg1;
230                     int uid = msg.arg2;
231                     if (importance > FOREGROUND_IMPORTANCE_CUTOFF
232                             && uid >= Process.FIRST_APPLICATION_UID) {
233                         unregisterAppUid(uid);
234                     }
235                     break;
236             }
237         }
238     }
239 
240     private static class BluetoothHidDeviceDeathRecipient implements IBinder.DeathRecipient {
241         private HidDeviceService mService;
242 
BluetoothHidDeviceDeathRecipient(HidDeviceService service)243         BluetoothHidDeviceDeathRecipient(HidDeviceService service) {
244             mService = service;
245         }
246 
247         @Override
binderDied()248         public void binderDied() {
249             Log.w(TAG, "Binder died, need to unregister app :(");
250             mService.unregisterApp();
251         }
252 
cleanup()253         public void cleanup() {
254             mService = null;
255         }
256     }
257 
258     private ActivityManager.OnUidImportanceListener mUidImportanceListener =
259             new ActivityManager.OnUidImportanceListener() {
260                 @Override
261                 public void onUidImportance(final int uid, final int importance) {
262                     Message message = mHandler.obtainMessage(MESSAGE_IMPORTANCE_CHANGE);
263                     message.arg1 = importance;
264                     message.arg2 = uid;
265                     mHandler.sendMessage(message);
266                 }
267             };
268 
269     @VisibleForTesting
270     static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub
271             implements IProfileServiceBinder {
272 
273         private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName();
274 
275         private HidDeviceService mService;
276 
BluetoothHidDeviceBinder(HidDeviceService service)277         BluetoothHidDeviceBinder(HidDeviceService service) {
278             mService = service;
279         }
280 
281         @VisibleForTesting
getServiceForTesting()282         HidDeviceService getServiceForTesting() {
283             if (mService != null && mService.isAvailable()) {
284                 return mService;
285             }
286             return null;
287         }
288 
289         @Override
cleanup()290         public void cleanup() {
291             mService = null;
292         }
293 
getService()294         private HidDeviceService getService() {
295             if (!Utils.checkCaller()) {
296                 Log.w(TAG, "HidDevice call not allowed for non-active user");
297                 return null;
298             }
299 
300             if (mService != null && mService.isAvailable()) {
301                 return mService;
302             }
303 
304             return null;
305         }
306 
307         @Override
registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)308         public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
309                 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
310                 IBluetoothHidDeviceCallback callback) {
311             if (DBG) {
312                 Log.d(TAG, "registerApp()");
313             }
314 
315             HidDeviceService service = getService();
316             if (service == null) {
317                 return false;
318             }
319 
320             return service.registerApp(sdp, inQos, outQos, callback);
321         }
322 
323         @Override
unregisterApp()324         public boolean unregisterApp() {
325             if (DBG) {
326                 Log.d(TAG, "unregisterApp()");
327             }
328 
329             HidDeviceService service = getService();
330             if (service == null) {
331                 return false;
332             }
333 
334             return service.unregisterApp();
335         }
336 
337         @Override
sendReport(BluetoothDevice device, int id, byte[] data)338         public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
339             if (DBG) {
340                 Log.d(TAG, "sendReport(): device=" + device + "  id=" + id);
341             }
342 
343             HidDeviceService service = getService();
344             if (service == null) {
345                 return false;
346             }
347 
348             return service.sendReport(device, id, data);
349         }
350 
351         @Override
replyReport(BluetoothDevice device, byte type, byte id, byte[] data)352         public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
353             if (DBG) {
354                 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
355             }
356 
357             HidDeviceService service = getService();
358             if (service == null) {
359                 return false;
360             }
361 
362             return service.replyReport(device, type, id, data);
363         }
364 
365         @Override
unplug(BluetoothDevice device)366         public boolean unplug(BluetoothDevice device) {
367             if (DBG) {
368                 Log.d(TAG, "unplug(): device=" + device);
369             }
370 
371             HidDeviceService service = getService();
372             if (service == null) {
373                 return false;
374             }
375 
376             return service.unplug(device);
377         }
378 
379         @Override
connect(BluetoothDevice device)380         public boolean connect(BluetoothDevice device) {
381             if (DBG) {
382                 Log.d(TAG, "connect(): device=" + device);
383             }
384 
385             HidDeviceService service = getService();
386             if (service == null) {
387                 return false;
388             }
389 
390             return service.connect(device);
391         }
392 
393         @Override
disconnect(BluetoothDevice device)394         public boolean disconnect(BluetoothDevice device) {
395             if (DBG) {
396                 Log.d(TAG, "disconnect(): device=" + device);
397             }
398 
399             HidDeviceService service = getService();
400             if (service == null) {
401                 return false;
402             }
403 
404             return service.disconnect(device);
405         }
406 
407         @Override
reportError(BluetoothDevice device, byte error)408         public boolean reportError(BluetoothDevice device, byte error) {
409             if (DBG) {
410                 Log.d(TAG, "reportError(): device=" + device + " error=" + error);
411             }
412 
413             HidDeviceService service = getService();
414             if (service == null) {
415                 return false;
416             }
417 
418             return service.reportError(device, error);
419         }
420 
421         @Override
getConnectionState(BluetoothDevice device)422         public int getConnectionState(BluetoothDevice device) {
423             if (DBG) {
424                 Log.d(TAG, "getConnectionState(): device=" + device);
425             }
426 
427             HidDeviceService service = getService();
428             if (service == null) {
429                 return BluetoothHidDevice.STATE_DISCONNECTED;
430             }
431 
432             return service.getConnectionState(device);
433         }
434 
435         @Override
getConnectedDevices()436         public List<BluetoothDevice> getConnectedDevices() {
437             if (DBG) {
438                 Log.d(TAG, "getConnectedDevices()");
439             }
440 
441             return getDevicesMatchingConnectionStates(new int[]{BluetoothProfile.STATE_CONNECTED});
442         }
443 
444         @Override
getDevicesMatchingConnectionStates(int[] states)445         public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
446             if (DBG) {
447                 Log.d(TAG,
448                         "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
449             }
450 
451             HidDeviceService service = getService();
452             if (service == null) {
453                 return new ArrayList<BluetoothDevice>(0);
454             }
455 
456             return service.getDevicesMatchingConnectionStates(states);
457         }
458 
459         @Override
getUserAppName()460         public String getUserAppName() {
461             HidDeviceService service = getService();
462             if (service == null) {
463                 return "";
464             }
465             return service.getUserAppName();
466         }
467     }
468 
469     @Override
initBinder()470     protected IProfileServiceBinder initBinder() {
471         return new BluetoothHidDeviceBinder(this);
472     }
473 
checkDevice(BluetoothDevice device)474     private boolean checkDevice(BluetoothDevice device) {
475         if (mHidDevice == null || !mHidDevice.equals(device)) {
476             Log.w(TAG, "Unknown device: " + device);
477             return false;
478         }
479         return true;
480     }
481 
checkCallingUid()482     private boolean checkCallingUid() {
483         int callingUid = Binder.getCallingUid();
484         if (callingUid != mUserUid) {
485             Log.w(TAG, "checkCallingUid(): caller UID doesn't match registered user UID");
486             return false;
487         }
488         return true;
489     }
490 
registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)491     synchronized boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp,
492             BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos,
493             IBluetoothHidDeviceCallback callback) {
494         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
495         if (mUserUid != 0) {
496             Log.w(TAG, "registerApp(): failed because another app is registered");
497             return false;
498         }
499 
500         int callingUid = Binder.getCallingUid();
501         if (DBG) {
502             Log.d(TAG, "registerApp(): calling uid=" + callingUid);
503         }
504         if (callingUid >= Process.FIRST_APPLICATION_UID
505                 && mActivityManager.getUidImportance(callingUid) > FOREGROUND_IMPORTANCE_CUTOFF) {
506             Log.w(TAG, "registerApp(): failed because the app is not foreground");
507             return false;
508         }
509         mUserUid = callingUid;
510         mCallback = callback;
511 
512         return mHidDeviceNativeInterface.registerApp(
513                 sdp.getName(),
514                 sdp.getDescription(),
515                 sdp.getProvider(),
516                 sdp.getSubclass(),
517                 sdp.getDescriptors(),
518                 inQos == null
519                         ? null
520                         : new int[] {
521                             inQos.getServiceType(),
522                             inQos.getTokenRate(),
523                             inQos.getTokenBucketSize(),
524                             inQos.getPeakBandwidth(),
525                             inQos.getLatency(),
526                             inQos.getDelayVariation()
527                         },
528                 outQos == null
529                         ? null
530                         : new int[] {
531                             outQos.getServiceType(),
532                             outQos.getTokenRate(),
533                             outQos.getTokenBucketSize(),
534                             outQos.getPeakBandwidth(),
535                             outQos.getLatency(),
536                             outQos.getDelayVariation()
537                         });
538     }
539 
unregisterApp()540     synchronized boolean unregisterApp() {
541         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
542         if (DBG) {
543             Log.d(TAG, "unregisterApp()");
544         }
545 
546         int callingUid = Binder.getCallingUid();
547         return unregisterAppUid(callingUid);
548     }
549 
unregisterAppUid(int uid)550     private synchronized boolean unregisterAppUid(int uid) {
551         if (DBG) {
552             Log.d(TAG, "unregisterAppUid(): uid=" + uid);
553         }
554 
555         if (mUserUid != 0 && (uid == mUserUid || uid < Process.FIRST_APPLICATION_UID)) {
556             mUserUid = 0;
557             return mHidDeviceNativeInterface.unregisterApp();
558         }
559         if (DBG) {
560             Log.d(TAG, "unregisterAppUid(): caller UID doesn't match user UID");
561         }
562         return false;
563     }
564 
sendReport(BluetoothDevice device, int id, byte[] data)565     synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) {
566         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
567         if (DBG) {
568             Log.d(TAG, "sendReport(): device=" + device + " id=" + id);
569         }
570 
571         return checkDevice(device) && checkCallingUid()
572                 && mHidDeviceNativeInterface.sendReport(id, data);
573     }
574 
replyReport(BluetoothDevice device, byte type, byte id, byte[] data)575     synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
576         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
577         if (DBG) {
578             Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id);
579         }
580 
581         return checkDevice(device) && checkCallingUid()
582                 && mHidDeviceNativeInterface.replyReport(type, id, data);
583     }
584 
unplug(BluetoothDevice device)585     synchronized boolean unplug(BluetoothDevice device) {
586         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
587         if (DBG) {
588             Log.d(TAG, "unplug(): device=" + device);
589         }
590 
591         return checkDevice(device) && checkCallingUid()
592                 && mHidDeviceNativeInterface.unplug();
593     }
594 
connect(BluetoothDevice device)595     synchronized boolean connect(BluetoothDevice device) {
596         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
597         if (DBG) {
598             Log.d(TAG, "connect(): device=" + device);
599         }
600 
601         return checkCallingUid() && mHidDeviceNativeInterface.connect(device);
602     }
603 
disconnect(BluetoothDevice device)604     synchronized boolean disconnect(BluetoothDevice device) {
605         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
606         if (DBG) {
607             Log.d(TAG, "disconnect(): device=" + device);
608         }
609 
610         int callingUid = Binder.getCallingUid();
611         if (callingUid != mUserUid && callingUid >= Process.FIRST_APPLICATION_UID) {
612             Log.w(TAG, "disconnect(): caller UID doesn't match user UID");
613             return false;
614         }
615         return checkDevice(device) && mHidDeviceNativeInterface.disconnect();
616     }
617 
reportError(BluetoothDevice device, byte error)618     synchronized boolean reportError(BluetoothDevice device, byte error) {
619         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
620         if (DBG) {
621             Log.d(TAG, "reportError(): device=" + device + " error=" + error);
622         }
623 
624         return checkDevice(device) && checkCallingUid()
625                 && mHidDeviceNativeInterface.reportError(error);
626     }
627 
getUserAppName()628     synchronized String getUserAppName() {
629         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
630         if (mUserUid < Process.FIRST_APPLICATION_UID) {
631             return "";
632         }
633         String appName = getPackageManager().getNameForUid(mUserUid);
634         return appName != null ? appName : "";
635     }
636 
637     @Override
start()638     protected boolean start() {
639         if (DBG) {
640             Log.d(TAG, "start()");
641         }
642 
643         mHandler = new HidDeviceServiceHandler();
644         mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance();
645         mHidDeviceNativeInterface.init();
646         mNativeAvailable = true;
647         mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
648         mActivityManager.addOnUidImportanceListener(mUidImportanceListener,
649                 FOREGROUND_IMPORTANCE_CUTOFF);
650         setHidDeviceService(this);
651         return true;
652     }
653 
654     @Override
stop()655     protected boolean stop() {
656         if (DBG) {
657             Log.d(TAG, "stop()");
658         }
659 
660         if (sHidDeviceService == null) {
661             Log.w(TAG, "stop() called before start()");
662             return true;
663         }
664 
665         setHidDeviceService(null);
666         if (mNativeAvailable) {
667             mHidDeviceNativeInterface.cleanup();
668             mNativeAvailable = false;
669         }
670         mActivityManager.removeOnUidImportanceListener(mUidImportanceListener);
671         return true;
672     }
673 
674     @Override
onUnbind(Intent intent)675     public boolean onUnbind(Intent intent) {
676         Log.d(TAG, "Need to unregister app");
677         unregisterApp();
678         return super.onUnbind(intent);
679     }
680 
681     /**
682      * Get the HID Device Service instance
683      * @return HID Device Service instance
684      */
getHidDeviceService()685     public static synchronized HidDeviceService getHidDeviceService() {
686         if (sHidDeviceService == null) {
687             Log.d(TAG, "getHidDeviceService(): service is NULL");
688             return null;
689         }
690         if (!sHidDeviceService.isAvailable()) {
691             Log.d(TAG, "getHidDeviceService(): service is not available");
692             return null;
693         }
694         return sHidDeviceService;
695     }
696 
setHidDeviceService(HidDeviceService instance)697     private static synchronized void setHidDeviceService(HidDeviceService instance) {
698         if (DBG) {
699             Log.d(TAG, "setHidDeviceService(): set to: " + instance);
700         }
701         sHidDeviceService = instance;
702     }
703 
getConnectionState(BluetoothDevice device)704     int getConnectionState(BluetoothDevice device) {
705         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
706         if (mHidDevice != null && mHidDevice.equals(device)) {
707             return mHidDeviceState;
708         }
709         return BluetoothHidDevice.STATE_DISCONNECTED;
710     }
711 
getDevicesMatchingConnectionStates(int[] states)712     List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
713         enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
714         List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
715 
716         if (mHidDevice != null) {
717             for (int state : states) {
718                 if (state == mHidDeviceState) {
719                     inputDevices.add(mHidDevice);
720                     break;
721                 }
722             }
723         }
724         return inputDevices;
725     }
726 
onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered)727     synchronized void onApplicationStateChangedFromNative(BluetoothDevice device,
728             boolean registered) {
729         if (DBG) {
730             Log.d(TAG, "onApplicationStateChanged(): registered=" + registered);
731         }
732 
733         Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED);
734         msg.obj = device;
735         msg.arg1 = registered ? 1 : 0;
736         mHandler.sendMessage(msg);
737     }
738 
onConnectStateChangedFromNative(BluetoothDevice device, int state)739     synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) {
740         if (DBG) {
741             Log.d(TAG, "onConnectStateChanged(): device="
742                     + device + " state=" + state);
743         }
744 
745         Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
746         msg.obj = device;
747         msg.arg1 = state;
748         mHandler.sendMessage(msg);
749     }
750 
onGetReportFromNative(byte type, byte id, short bufferSize)751     synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) {
752         if (DBG) {
753             Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize);
754         }
755 
756         Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
757         msg.obj = bufferSize > 0 ? new Integer(bufferSize) : null;
758         msg.arg1 = type;
759         msg.arg2 = id;
760         mHandler.sendMessage(msg);
761     }
762 
onSetReportFromNative(byte reportType, byte reportId, byte[] data)763     synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) {
764         if (DBG) {
765             Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId);
766         }
767 
768         ByteBuffer bb = ByteBuffer.wrap(data);
769 
770         Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
771         msg.arg1 = reportType;
772         msg.arg2 = reportId;
773         msg.obj = bb;
774         mHandler.sendMessage(msg);
775     }
776 
onSetProtocolFromNative(byte protocol)777     synchronized void onSetProtocolFromNative(byte protocol) {
778         if (DBG) {
779             Log.d(TAG, "onSetProtocol(): protocol=" + protocol);
780         }
781 
782         Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL);
783         msg.arg1 = protocol;
784         mHandler.sendMessage(msg);
785     }
786 
onInterruptDataFromNative(byte reportId, byte[] data)787     synchronized void onInterruptDataFromNative(byte reportId, byte[] data) {
788         if (DBG) {
789             Log.d(TAG, "onInterruptData(): reportId=" + reportId);
790         }
791 
792         ByteBuffer bb = ByteBuffer.wrap(data);
793 
794         Message msg = mHandler.obtainMessage(MESSAGE_INTR_DATA);
795         msg.arg1 = reportId;
796         msg.obj = bb;
797         mHandler.sendMessage(msg);
798     }
799 
onVirtualCableUnplugFromNative()800     synchronized void onVirtualCableUnplugFromNative() {
801         if (DBG) {
802             Log.d(TAG, "onVirtualCableUnplug()");
803         }
804 
805         Message msg = mHandler.obtainMessage(MESSAGE_VC_UNPLUG);
806         mHandler.sendMessage(msg);
807     }
808 
setAndBroadcastConnectionState(BluetoothDevice device, int newState)809     private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) {
810         if (DBG) {
811             Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress()
812                     + " oldState=" + mHidDeviceState + " newState=" + newState);
813         }
814 
815         if (mHidDevice != null && !mHidDevice.equals(device)) {
816             Log.w(TAG, "Connection state changed for unknown device, ignoring");
817             return;
818         }
819 
820         int prevState = mHidDeviceState;
821         mHidDeviceState = newState;
822 
823         if (prevState == newState) {
824             Log.w(TAG, "Connection state is unchanged, ignoring");
825             return;
826         }
827 
828         if (newState == BluetoothProfile.STATE_CONNECTED) {
829             MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HID_DEVICE);
830         }
831 
832         Intent intent = new Intent(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
833         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
834         intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
835         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
836         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
837         sendBroadcast(intent, BLUETOOTH_PERM);
838     }
839 
convertHalState(int halState)840     private static int convertHalState(int halState) {
841         switch (halState) {
842             case HAL_CONN_STATE_CONNECTED:
843                 return BluetoothProfile.STATE_CONNECTED;
844             case HAL_CONN_STATE_CONNECTING:
845                 return BluetoothProfile.STATE_CONNECTING;
846             case HAL_CONN_STATE_DISCONNECTED:
847                 return BluetoothProfile.STATE_DISCONNECTED;
848             case HAL_CONN_STATE_DISCONNECTING:
849                 return BluetoothProfile.STATE_DISCONNECTING;
850             default:
851                 return BluetoothProfile.STATE_DISCONNECTED;
852         }
853     }
854 
855     static final int HAL_CONN_STATE_CONNECTED = 0;
856     static final int HAL_CONN_STATE_CONNECTING = 1;
857     static final int HAL_CONN_STATE_DISCONNECTED = 2;
858     static final int HAL_CONN_STATE_DISCONNECTING = 3;
859 }
860