1 /* 2 * Copyright 2017 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 /* 18 * Defines the native inteface that is used by HID Device service to 19 * send or receive messages from the native stack. This file is registered 20 * for the native methods in the corresponding JNI C++ file. 21 */ 22 23 package com.android.bluetooth.hid; 24 25 import android.bluetooth.BluetoothAdapter; 26 import android.bluetooth.BluetoothDevice; 27 import android.util.Log; 28 29 import com.android.bluetooth.Utils; 30 import com.android.internal.annotations.GuardedBy; 31 import com.android.internal.annotations.VisibleForTesting; 32 33 /** 34 * HID Device Native Interface to/from JNI. 35 */ 36 public class HidDeviceNativeInterface { 37 private static final String TAG = "HidDeviceNativeInterface"; 38 private BluetoothAdapter mAdapter; 39 40 @GuardedBy("INSTANCE_LOCK") 41 private static HidDeviceNativeInterface sInstance; 42 private static final Object INSTANCE_LOCK = new Object(); 43 44 static { classInitNative()45 classInitNative(); 46 } 47 48 @VisibleForTesting HidDeviceNativeInterface()49 private HidDeviceNativeInterface() { 50 mAdapter = BluetoothAdapter.getDefaultAdapter(); 51 if (mAdapter == null) { 52 Log.wtf(TAG, "No Bluetooth Adapter Available"); 53 } 54 } 55 56 /** 57 * Get the singleton instance. 58 */ getInstance()59 public static HidDeviceNativeInterface getInstance() { 60 synchronized (INSTANCE_LOCK) { 61 if (sInstance == null) { 62 setInstance(new HidDeviceNativeInterface()); 63 } 64 return sInstance; 65 } 66 } 67 68 /** 69 * Set the singleton instance. 70 * 71 * @param nativeInterface native interface 72 */ setInstance(HidDeviceNativeInterface nativeInterface)73 private static void setInstance(HidDeviceNativeInterface nativeInterface) { 74 sInstance = nativeInterface; 75 } 76 77 /** 78 * Initializes the native interface. 79 */ init()80 public void init() { 81 initNative(); 82 } 83 84 /** 85 * Cleanup the native interface. 86 */ cleanup()87 public void cleanup() { 88 cleanupNative(); 89 } 90 91 /** 92 * Registers the application 93 * 94 * @param name name of the HID Device application 95 * @param description description of the HID Device application 96 * @param provider provider of the HID Device application 97 * @param subclass subclass of the HID Device application 98 * @param descriptors HID descriptors 99 * @param inQos incoming QoS settings 100 * @param outQos outgoing QoS settings 101 * @return the result of the native call 102 */ registerApp(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos)103 public boolean registerApp(String name, String description, String provider, 104 byte subclass, byte[] descriptors, int[] inQos, int[] outQos) { 105 return registerAppNative(name, description, provider, subclass, descriptors, inQos, outQos); 106 } 107 108 /** 109 * Unregisters the application 110 * 111 * @return the result of the native call 112 */ unregisterApp()113 public boolean unregisterApp() { 114 return unregisterAppNative(); 115 } 116 117 /** 118 * Send report to the remote host 119 * 120 * @param id report ID 121 * @param data report data array 122 * @return the result of the native call 123 */ sendReport(int id, byte[] data)124 public boolean sendReport(int id, byte[] data) { 125 return sendReportNative(id, data); 126 } 127 128 /** 129 * Reply report to the remote host 130 * 131 * @param type report type 132 * @param id report ID 133 * @param data report data array 134 * @return the result of the native call 135 */ replyReport(byte type, byte id, byte[] data)136 public boolean replyReport(byte type, byte id, byte[] data) { 137 return replyReportNative(type, id, data); 138 } 139 140 /** 141 * Send virtual unplug to the remote host 142 * 143 * @return the result of the native call 144 */ unplug()145 public boolean unplug() { 146 return unplugNative(); 147 } 148 149 /** 150 * Connect to the remote host 151 * 152 * @param device remote host device 153 * @return the result of the native call 154 */ connect(BluetoothDevice device)155 public boolean connect(BluetoothDevice device) { 156 return connectNative(getByteAddress(device)); 157 } 158 159 /** 160 * Disconnect from the remote host 161 * 162 * @return the result of the native call 163 */ disconnect()164 public boolean disconnect() { 165 return disconnectNative(); 166 } 167 168 /** 169 * Report error to the remote host 170 * 171 * @param error error byte 172 * @return the result of the native call 173 */ reportError(byte error)174 public boolean reportError(byte error) { 175 return reportErrorNative(error); 176 } 177 onApplicationStateChanged(byte[] address, boolean registered)178 private synchronized void onApplicationStateChanged(byte[] address, boolean registered) { 179 HidDeviceService service = HidDeviceService.getHidDeviceService(); 180 if (service != null) { 181 service.onApplicationStateChangedFromNative(getDevice(address), registered); 182 } else { 183 Log.wtf(TAG, "FATAL: onApplicationStateChanged() " 184 + "is called from the stack while service is not available."); 185 } 186 } 187 onConnectStateChanged(byte[] address, int state)188 private synchronized void onConnectStateChanged(byte[] address, int state) { 189 HidDeviceService service = HidDeviceService.getHidDeviceService(); 190 if (service != null) { 191 service.onConnectStateChangedFromNative(getDevice(address), state); 192 } else { 193 Log.wtf(TAG, "FATAL: onConnectStateChanged() " 194 + "is called from the stack while service is not available."); 195 } 196 } 197 onGetReport(byte type, byte id, short bufferSize)198 private synchronized void onGetReport(byte type, byte id, short bufferSize) { 199 HidDeviceService service = HidDeviceService.getHidDeviceService(); 200 if (service != null) { 201 service.onGetReportFromNative(type, id, bufferSize); 202 } else { 203 Log.wtf(TAG, "FATAL: onGetReport() " 204 + "is called from the stack while service is not available."); 205 } 206 } 207 onSetReport(byte reportType, byte reportId, byte[] data)208 private synchronized void onSetReport(byte reportType, byte reportId, byte[] data) { 209 HidDeviceService service = HidDeviceService.getHidDeviceService(); 210 if (service != null) { 211 service.onSetReportFromNative(reportType, reportId, data); 212 } else { 213 Log.wtf(TAG, "FATAL: onSetReport() " 214 + "is called from the stack while service is not available."); 215 } 216 } 217 onSetProtocol(byte protocol)218 private synchronized void onSetProtocol(byte protocol) { 219 HidDeviceService service = HidDeviceService.getHidDeviceService(); 220 if (service != null) { 221 service.onSetProtocolFromNative(protocol); 222 } else { 223 Log.wtf(TAG, "FATAL: onSetProtocol() " 224 + "is called from the stack while service is not available."); 225 } 226 } 227 onInterruptData(byte reportId, byte[] data)228 private synchronized void onInterruptData(byte reportId, byte[] data) { 229 HidDeviceService service = HidDeviceService.getHidDeviceService(); 230 if (service != null) { 231 service.onInterruptDataFromNative(reportId, data); 232 } else { 233 Log.wtf(TAG, "FATAL: onInterruptData() " 234 + "is called from the stack while service is not available."); 235 } 236 } 237 onVirtualCableUnplug()238 private synchronized void onVirtualCableUnplug() { 239 HidDeviceService service = HidDeviceService.getHidDeviceService(); 240 if (service != null) { 241 service.onVirtualCableUnplugFromNative(); 242 } else { 243 Log.wtf(TAG, "FATAL: onVirtualCableUnplug() " 244 + "is called from the stack while service is not available."); 245 } 246 } 247 getDevice(byte[] address)248 private BluetoothDevice getDevice(byte[] address) { 249 if (address == null) { 250 return null; 251 } 252 return mAdapter.getRemoteDevice(address); 253 } 254 getByteAddress(BluetoothDevice device)255 private byte[] getByteAddress(BluetoothDevice device) { 256 return Utils.getBytesFromAddress(device.getAddress()); 257 } 258 classInitNative()259 private static native void classInitNative(); 260 initNative()261 private native void initNative(); 262 cleanupNative()263 private native void cleanupNative(); 264 registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos)265 private native boolean registerAppNative(String name, String description, String provider, 266 byte subclass, byte[] descriptors, int[] inQos, int[] outQos); 267 unregisterAppNative()268 private native boolean unregisterAppNative(); 269 sendReportNative(int id, byte[] data)270 private native boolean sendReportNative(int id, byte[] data); 271 replyReportNative(byte type, byte id, byte[] data)272 private native boolean replyReportNative(byte type, byte id, byte[] data); 273 unplugNative()274 private native boolean unplugNative(); 275 connectNative(byte[] btAddress)276 private native boolean connectNative(byte[] btAddress); 277 disconnectNative()278 private native boolean disconnectNative(); 279 reportErrorNative(byte error)280 private native boolean reportErrorNative(byte error); 281 } 282