Loading android/app/jni/com_android_bluetooth_hid_device.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -474,8 +474,8 @@ static JNINativeMethod sMethods[] = { }; int register_com_android_bluetooth_hid_device(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidDeviceService", sMethods, NELEM(sMethods)); return jniRegisterNativeMethods( env, "com/android/bluetooth/hid/HidDeviceNativeInterface", sMethods, NELEM(sMethods)); } } // namespace android android/app/src/com/android/bluetooth/btservice/ServiceFactory.java +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.bluetooth.btservice; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.hid.HidDeviceService; import com.android.bluetooth.hid.HidHostService; import com.android.bluetooth.pan.PanService; Loading @@ -35,6 +36,10 @@ public class ServiceFactory { return HidHostService.getHidHostService(); } public HidDeviceService getHidDeviceService() { return HidDeviceService.getHidDeviceService(); } public PanService getPanService() { return PanService.getPanService(); } Loading android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java 0 → 100644 +281 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Defines the native inteface that is used by HID Device service to * send or receive messages from the native stack. This file is registered * for the native methods in the corresponding JNI C++ file. */ package com.android.bluetooth.hid; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.support.annotation.VisibleForTesting; import android.util.Log; import com.android.bluetooth.Utils; import com.android.internal.annotations.GuardedBy; /** * HID Device Native Interface to/from JNI. */ public class HidDeviceNativeInterface { private static final String TAG = "HidDeviceNativeInterface"; private BluetoothAdapter mAdapter; @GuardedBy("INSTANCE_LOCK") private static HidDeviceNativeInterface sInstance; private static final Object INSTANCE_LOCK = new Object(); static { classInitNative(); } @VisibleForTesting private HidDeviceNativeInterface() { mAdapter = BluetoothAdapter.getDefaultAdapter(); if (mAdapter == null) { Log.wtfStack(TAG, "No Bluetooth Adapter Available"); } } /** * Get the singleton instance. */ public static HidDeviceNativeInterface getInstance() { synchronized (INSTANCE_LOCK) { if (sInstance == null) { setInstance(new HidDeviceNativeInterface()); } return sInstance; } } /** * Set the singleton instance. * * @param nativeInterface native interface */ private static void setInstance(HidDeviceNativeInterface nativeInterface) { sInstance = nativeInterface; } /** * Initializes the native interface. */ public void init() { initNative(); } /** * Cleanup the native interface. */ public void cleanup() { cleanupNative(); } /** * Registers the application * * @param name name of the HID Device application * @param description description of the HID Device application * @param provider provider of the HID Device application * @param subclass subclass of the HID Device application * @param descriptors HID descriptors * @param inQos incoming QoS settings * @param outQos outgoing QoS settings * @return the result of the native call */ public boolean registerApp(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos) { return registerAppNative(name, description, provider, subclass, descriptors, inQos, outQos); } /** * Unregisters the application * * @return the result of the native call */ public boolean unregisterApp() { return unregisterAppNative(); } /** * Send report to the remote host * * @param id report ID * @param data report data array * @return the result of the native call */ public boolean sendReport(int id, byte[] data) { return sendReportNative(id, data); } /** * Reply report to the remote host * * @param type report type * @param id report ID * @param data report data array * @return the result of the native call */ public boolean replyReport(byte type, byte id, byte[] data) { return replyReportNative(type, id, data); } /** * Send virtual unplug to the remote host * * @return the result of the native call */ public boolean unplug() { return unplugNative(); } /** * Connect to the remote host * * @param device remote host device * @return the result of the native call */ public boolean connect(BluetoothDevice device) { return connectNative(getByteAddress(device)); } /** * Disconnect from the remote host * * @return the result of the native call */ public boolean disconnect() { return disconnectNative(); } /** * Report error to the remote host * * @param error error byte * @return the result of the native call */ public boolean reportError(byte error) { return reportErrorNative(error); } private synchronized void onApplicationStateChanged(byte[] address, boolean registered) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onApplicationStateChangedFromNative(getDevice(address), registered); } else { Log.wtfStack(TAG, "FATAL: onApplicationStateChanged() " + "is called from the stack while service is not available."); } } private synchronized void onConnectStateChanged(byte[] address, int state) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onConnectStateChangedFromNative(getDevice(address), state); } else { Log.wtfStack(TAG, "FATAL: onConnectStateChanged() " + "is called from the stack while service is not available."); } } private synchronized void onGetReport(byte type, byte id, short bufferSize) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onGetReportFromNative(type, id, bufferSize); } else { Log.wtfStack(TAG, "FATAL: onGetReport() " + "is called from the stack while service is not available."); } } private synchronized void onSetReport(byte reportType, byte reportId, byte[] data) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onSetReportFromNative(reportType, reportId, data); } else { Log.wtfStack(TAG, "FATAL: onSetReport() " + "is called from the stack while service is not available."); } } private synchronized void onSetProtocol(byte protocol) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onSetProtocolFromNative(protocol); } else { Log.wtfStack(TAG, "FATAL: onSetProtocol() " + "is called from the stack while service is not available."); } } private synchronized void onIntrData(byte reportId, byte[] data) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onIntrDataFromNative(reportId, data); } else { Log.wtfStack(TAG, "FATAL: onIntrData() " + "is called from the stack while service is not available."); } } private synchronized void onVirtualCableUnplug() { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onVirtualCableUnplugFromNative(); } else { Log.wtfStack(TAG, "FATAL: onVirtualCableUnplug() " + "is called from the stack while service is not available."); } } private BluetoothDevice getDevice(byte[] address) { if (address == null) { return null; } return mAdapter.getRemoteDevice(address); } private byte[] getByteAddress(BluetoothDevice device) { return Utils.getBytesFromAddress(device.getAddress()); } private static native void classInitNative(); private native void initNative(); private native void cleanupNative(); private native boolean registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos); private native boolean unregisterAppNative(); private native boolean sendReportNative(int id, byte[] data); private native boolean replyReportNative(byte type, byte id, byte[] data); private native boolean unplugNative(); private native boolean connectNative(byte[] btAddress); private native boolean disconnectNative(); private native boolean reportErrorNative(byte error); } android/app/src/com/android/bluetooth/hid/HidDeviceService.java +76 −63 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ProfileService; import com.android.internal.annotations.VisibleForTesting; import java.nio.ByteBuffer; import java.util.ArrayList; Loading @@ -54,24 +55,29 @@ public class HidDeviceService extends ProfileService { private static final int MESSAGE_INTR_DATA = 6; private static final int MESSAGE_VC_UNPLUG = 7; private static HidDeviceService sHidDeviceService; private HidDeviceNativeInterface mHidDeviceNativeInterface; private boolean mNativeAvailable = false; private BluetoothDevice mHidDevice = null; private BluetoothDevice mHidDevice; private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED; private BluetoothHidDeviceAppConfiguration mAppConfig = null; private BluetoothHidDeviceAppConfiguration mAppConfig; private IBluetoothHidDeviceCallback mCallback = null; private IBluetoothHidDeviceCallback mCallback; private BluetoothHidDeviceDeathRecipient mDeathRcpt; static { classInitNative(); } private HidDeviceServiceHandler mHandler; private final Handler mHandler = new Handler() { public HidDeviceService() { mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance(); } private class HidDeviceServiceHandler extends Handler { @Override public void handleMessage(Message msg) { if (DBG) { Loading @@ -80,10 +86,11 @@ public class HidDeviceService extends ProfileService { switch (msg.what) { case MESSAGE_APPLICATION_STATE_CHANGED: { BluetoothDevice device = msg.obj != null ? getDevice((byte[]) msg.obj) : null; BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null; boolean success = (msg.arg1 != 0); if (success) { Log.d(TAG, "App registered, set device to: " + device); mHidDevice = device; } else { mHidDevice = null; Loading Loading @@ -135,7 +142,7 @@ public class HidDeviceService extends ProfileService { } case MESSAGE_CONNECT_STATE_CHANGED: { BluetoothDevice device = getDevice((byte[]) msg.obj); BluetoothDevice device = (BluetoothDevice) msg.obj; int halState = msg.arg1; int state = convertHalState(halState); Loading @@ -143,7 +150,7 @@ public class HidDeviceService extends ProfileService { mHidDevice = device; } broadcastConnectionState(device, state); setAndBroadcastConnectionState(device, state); try { if (mCallback != null) { Loading Loading @@ -245,7 +252,8 @@ public class HidDeviceService extends ProfileService { } } private static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub @VisibleForTesting static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub implements IProfileServiceBinder { private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName(); Loading @@ -256,6 +264,14 @@ public class HidDeviceService extends ProfileService { mService = service; } @VisibleForTesting HidDeviceService getServiceForTesting() { if (mService != null && mService.isAvailable()) { return mService; } return null; } @Override public boolean cleanup() { mService = null; Loading Loading @@ -456,8 +472,8 @@ public class HidDeviceService extends ProfileService { mAppConfig = config; mCallback = callback; return registerAppNative(sdp.name, sdp.description, sdp.provider, sdp.subclass, sdp.descriptors, inQos == null ? null : inQos.toArray(), return mHidDeviceNativeInterface.registerApp(sdp.name, sdp.description, sdp.provider, sdp.subclass, sdp.descriptors, inQos == null ? null : inQos.toArray(), outQos == null ? null : outQos.toArray()); } Loading @@ -475,7 +491,7 @@ public class HidDeviceService extends ProfileService { return false; } return unregisterAppNative(); return mHidDeviceNativeInterface.unregisterApp(); } synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) { Loading @@ -487,7 +503,7 @@ public class HidDeviceService extends ProfileService { return false; } return sendReportNative(id, data); return mHidDeviceNativeInterface.sendReport(id, data); } synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { Loading @@ -499,7 +515,7 @@ public class HidDeviceService extends ProfileService { return false; } return replyReportNative(type, id, data); return mHidDeviceNativeInterface.replyReport(type, id, data); } synchronized boolean unplug(BluetoothDevice device) { Loading @@ -511,7 +527,7 @@ public class HidDeviceService extends ProfileService { return false; } return unplugNative(); return mHidDeviceNativeInterface.unplug(); } synchronized boolean connect(BluetoothDevice device) { Loading @@ -519,7 +535,7 @@ public class HidDeviceService extends ProfileService { Log.d(TAG, "connect(): device=" + device); } return connectNative(Utils.getByteAddress(device)); return mHidDeviceNativeInterface.connect(device); } synchronized boolean disconnect(BluetoothDevice device) { Loading @@ -531,7 +547,7 @@ public class HidDeviceService extends ProfileService { return false; } return disconnectNative(); return mHidDeviceNativeInterface.disconnect(); } synchronized boolean reportError(BluetoothDevice device, byte error) { Loading @@ -543,7 +559,7 @@ public class HidDeviceService extends ProfileService { return false; } return reportErrorNative(error); return mHidDeviceNativeInterface.reportError(error); } @Override Loading @@ -552,9 +568,10 @@ public class HidDeviceService extends ProfileService { Log.d(TAG, "start()"); } initNative(); mHandler = new HidDeviceServiceHandler(); setHidDeviceService(this); mHidDeviceNativeInterface.init(); mNativeAvailable = true; return true; } Loading @@ -574,7 +591,7 @@ public class HidDeviceService extends ProfileService { } if (mNativeAvailable) { cleanupNative(); mHidDeviceNativeInterface.cleanup(); mNativeAvailable = false; } Loading @@ -588,6 +605,26 @@ public class HidDeviceService extends ProfileService { return super.onUnbind(intent); } /** * Get the HID Device Service instance * @return HID Device Service instance */ public static synchronized HidDeviceService getHidDeviceService() { if (sHidDeviceService == null) { Log.d(TAG, "getHidDeviceService(): service is NULL"); return null; } if (!sHidDeviceService.isAvailable()) { Log.d(TAG, "getHidDeviceService(): service is not available"); return null; } return sHidDeviceService; } private static synchronized void setHidDeviceService(HidDeviceService instance) { sHidDeviceService = instance; } int getConnectionState(BluetoothDevice device) { if (mHidDevice != null && mHidDevice.equals(device)) { return mHidDeviceState; Loading @@ -610,30 +647,31 @@ public class HidDeviceService extends ProfileService { return inputDevices; } private synchronized void onApplicationStateChanged(byte[] address, boolean registered) { synchronized void onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered) { if (DBG) { Log.d(TAG, "onApplicationStateChanged(): registered=" + registered); } Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED); msg.obj = address; msg.obj = device; msg.arg1 = registered ? 1 : 0; mHandler.sendMessage(msg); } private synchronized void onConnectStateChanged(byte[] address, int state) { synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) { if (DBG) { Log.d(TAG, "onConnectStateChanged(): address=" + Arrays.toString(address) + " state=" + state); Log.d(TAG, "onConnectStateChanged(): device=" + device + " state=" + state); } Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); msg.obj = address; msg.obj = device; msg.arg1 = state; mHandler.sendMessage(msg); } private synchronized void onGetReport(byte type, byte id, short bufferSize) { synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) { if (DBG) { Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize); } Loading @@ -645,7 +683,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onSetReport(byte reportType, byte reportId, byte[] data) { synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) { if (DBG) { Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId); } Loading @@ -659,7 +697,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onSetProtocol(byte protocol) { synchronized void onSetProtocolFromNative(byte protocol) { if (DBG) { Log.d(TAG, "onSetProtocol(): protocol=" + protocol); } Loading @@ -669,7 +707,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onIntrData(byte reportId, byte[] data) { synchronized void onIntrDataFromNative(byte reportId, byte[] data) { if (DBG) { Log.d(TAG, "onIntrData(): reportId=" + reportId); } Loading @@ -682,7 +720,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onVirtualCableUnplug() { synchronized void onVirtualCableUnplugFromNative() { if (DBG) { Log.d(TAG, "onVirtualCableUnplug()"); } Loading @@ -691,10 +729,10 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private void broadcastConnectionState(BluetoothDevice device, int newState) { private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) { if (DBG) { Log.d(TAG, "broadcastConnectionState(): device=" + device.getAddress() + " newState=" + newState); Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress() + " oldState=" + mHidDeviceState + " newState=" + newState); } if (mHidDevice != null && !mHidDevice.equals(device)) { Loading @@ -705,10 +743,8 @@ public class HidDeviceService extends ProfileService { int prevState = mHidDeviceState; mHidDeviceState = newState; Log.i(TAG, "connection state for " + device.getAddress() + ": " + prevState + " -> " + newState); if (prevState == newState) { Log.w(TAG, "Connection state is unchanged, ignoring"); return; } Loading Loading @@ -739,27 +775,4 @@ public class HidDeviceService extends ProfileService { private static final int CONN_STATE_CONNECTING = 1; private static final int CONN_STATE_DISCONNECTED = 2; private static final int CONN_STATE_DISCONNECTING = 3; private static native void classInitNative(); private native void initNative(); private native void cleanupNative(); private native boolean registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos); private native boolean unregisterAppNative(); private native boolean sendReportNative(int id, byte[] data); private native boolean replyReportNative(byte type, byte id, byte[] data); private native boolean unplugNative(); private native boolean connectNative(byte[] btAddress); private native boolean disconnectNative(); private native boolean reportErrorNative(byte error); } android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java 0 → 100644 +183 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
android/app/jni/com_android_bluetooth_hid_device.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -474,8 +474,8 @@ static JNINativeMethod sMethods[] = { }; int register_com_android_bluetooth_hid_device(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/bluetooth/hid/HidDeviceService", sMethods, NELEM(sMethods)); return jniRegisterNativeMethods( env, "com/android/bluetooth/hid/HidDeviceNativeInterface", sMethods, NELEM(sMethods)); } } // namespace android
android/app/src/com/android/bluetooth/btservice/ServiceFactory.java +5 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.bluetooth.btservice; import com.android.bluetooth.a2dp.A2dpService; import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.hid.HidDeviceService; import com.android.bluetooth.hid.HidHostService; import com.android.bluetooth.pan.PanService; Loading @@ -35,6 +36,10 @@ public class ServiceFactory { return HidHostService.getHidHostService(); } public HidDeviceService getHidDeviceService() { return HidDeviceService.getHidDeviceService(); } public PanService getPanService() { return PanService.getPanService(); } Loading
android/app/src/com/android/bluetooth/hid/HidDeviceNativeInterface.java 0 → 100644 +281 −0 Original line number Diff line number Diff line /* * Copyright 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Defines the native inteface that is used by HID Device service to * send or receive messages from the native stack. This file is registered * for the native methods in the corresponding JNI C++ file. */ package com.android.bluetooth.hid; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.support.annotation.VisibleForTesting; import android.util.Log; import com.android.bluetooth.Utils; import com.android.internal.annotations.GuardedBy; /** * HID Device Native Interface to/from JNI. */ public class HidDeviceNativeInterface { private static final String TAG = "HidDeviceNativeInterface"; private BluetoothAdapter mAdapter; @GuardedBy("INSTANCE_LOCK") private static HidDeviceNativeInterface sInstance; private static final Object INSTANCE_LOCK = new Object(); static { classInitNative(); } @VisibleForTesting private HidDeviceNativeInterface() { mAdapter = BluetoothAdapter.getDefaultAdapter(); if (mAdapter == null) { Log.wtfStack(TAG, "No Bluetooth Adapter Available"); } } /** * Get the singleton instance. */ public static HidDeviceNativeInterface getInstance() { synchronized (INSTANCE_LOCK) { if (sInstance == null) { setInstance(new HidDeviceNativeInterface()); } return sInstance; } } /** * Set the singleton instance. * * @param nativeInterface native interface */ private static void setInstance(HidDeviceNativeInterface nativeInterface) { sInstance = nativeInterface; } /** * Initializes the native interface. */ public void init() { initNative(); } /** * Cleanup the native interface. */ public void cleanup() { cleanupNative(); } /** * Registers the application * * @param name name of the HID Device application * @param description description of the HID Device application * @param provider provider of the HID Device application * @param subclass subclass of the HID Device application * @param descriptors HID descriptors * @param inQos incoming QoS settings * @param outQos outgoing QoS settings * @return the result of the native call */ public boolean registerApp(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos) { return registerAppNative(name, description, provider, subclass, descriptors, inQos, outQos); } /** * Unregisters the application * * @return the result of the native call */ public boolean unregisterApp() { return unregisterAppNative(); } /** * Send report to the remote host * * @param id report ID * @param data report data array * @return the result of the native call */ public boolean sendReport(int id, byte[] data) { return sendReportNative(id, data); } /** * Reply report to the remote host * * @param type report type * @param id report ID * @param data report data array * @return the result of the native call */ public boolean replyReport(byte type, byte id, byte[] data) { return replyReportNative(type, id, data); } /** * Send virtual unplug to the remote host * * @return the result of the native call */ public boolean unplug() { return unplugNative(); } /** * Connect to the remote host * * @param device remote host device * @return the result of the native call */ public boolean connect(BluetoothDevice device) { return connectNative(getByteAddress(device)); } /** * Disconnect from the remote host * * @return the result of the native call */ public boolean disconnect() { return disconnectNative(); } /** * Report error to the remote host * * @param error error byte * @return the result of the native call */ public boolean reportError(byte error) { return reportErrorNative(error); } private synchronized void onApplicationStateChanged(byte[] address, boolean registered) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onApplicationStateChangedFromNative(getDevice(address), registered); } else { Log.wtfStack(TAG, "FATAL: onApplicationStateChanged() " + "is called from the stack while service is not available."); } } private synchronized void onConnectStateChanged(byte[] address, int state) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onConnectStateChangedFromNative(getDevice(address), state); } else { Log.wtfStack(TAG, "FATAL: onConnectStateChanged() " + "is called from the stack while service is not available."); } } private synchronized void onGetReport(byte type, byte id, short bufferSize) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onGetReportFromNative(type, id, bufferSize); } else { Log.wtfStack(TAG, "FATAL: onGetReport() " + "is called from the stack while service is not available."); } } private synchronized void onSetReport(byte reportType, byte reportId, byte[] data) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onSetReportFromNative(reportType, reportId, data); } else { Log.wtfStack(TAG, "FATAL: onSetReport() " + "is called from the stack while service is not available."); } } private synchronized void onSetProtocol(byte protocol) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onSetProtocolFromNative(protocol); } else { Log.wtfStack(TAG, "FATAL: onSetProtocol() " + "is called from the stack while service is not available."); } } private synchronized void onIntrData(byte reportId, byte[] data) { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onIntrDataFromNative(reportId, data); } else { Log.wtfStack(TAG, "FATAL: onIntrData() " + "is called from the stack while service is not available."); } } private synchronized void onVirtualCableUnplug() { HidDeviceService service = HidDeviceService.getHidDeviceService(); if (service != null) { service.onVirtualCableUnplugFromNative(); } else { Log.wtfStack(TAG, "FATAL: onVirtualCableUnplug() " + "is called from the stack while service is not available."); } } private BluetoothDevice getDevice(byte[] address) { if (address == null) { return null; } return mAdapter.getRemoteDevice(address); } private byte[] getByteAddress(BluetoothDevice device) { return Utils.getBytesFromAddress(device.getAddress()); } private static native void classInitNative(); private native void initNative(); private native void cleanupNative(); private native boolean registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos); private native boolean unregisterAppNative(); private native boolean sendReportNative(int id, byte[] data); private native boolean replyReportNative(byte type, byte id, byte[] data); private native boolean unplugNative(); private native boolean connectNative(byte[] btAddress); private native boolean disconnectNative(); private native boolean reportErrorNative(byte error); }
android/app/src/com/android/bluetooth/hid/HidDeviceService.java +76 −63 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ import android.util.Log; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.ProfileService; import com.android.internal.annotations.VisibleForTesting; import java.nio.ByteBuffer; import java.util.ArrayList; Loading @@ -54,24 +55,29 @@ public class HidDeviceService extends ProfileService { private static final int MESSAGE_INTR_DATA = 6; private static final int MESSAGE_VC_UNPLUG = 7; private static HidDeviceService sHidDeviceService; private HidDeviceNativeInterface mHidDeviceNativeInterface; private boolean mNativeAvailable = false; private BluetoothDevice mHidDevice = null; private BluetoothDevice mHidDevice; private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED; private BluetoothHidDeviceAppConfiguration mAppConfig = null; private BluetoothHidDeviceAppConfiguration mAppConfig; private IBluetoothHidDeviceCallback mCallback = null; private IBluetoothHidDeviceCallback mCallback; private BluetoothHidDeviceDeathRecipient mDeathRcpt; static { classInitNative(); } private HidDeviceServiceHandler mHandler; private final Handler mHandler = new Handler() { public HidDeviceService() { mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance(); } private class HidDeviceServiceHandler extends Handler { @Override public void handleMessage(Message msg) { if (DBG) { Loading @@ -80,10 +86,11 @@ public class HidDeviceService extends ProfileService { switch (msg.what) { case MESSAGE_APPLICATION_STATE_CHANGED: { BluetoothDevice device = msg.obj != null ? getDevice((byte[]) msg.obj) : null; BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null; boolean success = (msg.arg1 != 0); if (success) { Log.d(TAG, "App registered, set device to: " + device); mHidDevice = device; } else { mHidDevice = null; Loading Loading @@ -135,7 +142,7 @@ public class HidDeviceService extends ProfileService { } case MESSAGE_CONNECT_STATE_CHANGED: { BluetoothDevice device = getDevice((byte[]) msg.obj); BluetoothDevice device = (BluetoothDevice) msg.obj; int halState = msg.arg1; int state = convertHalState(halState); Loading @@ -143,7 +150,7 @@ public class HidDeviceService extends ProfileService { mHidDevice = device; } broadcastConnectionState(device, state); setAndBroadcastConnectionState(device, state); try { if (mCallback != null) { Loading Loading @@ -245,7 +252,8 @@ public class HidDeviceService extends ProfileService { } } private static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub @VisibleForTesting static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub implements IProfileServiceBinder { private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName(); Loading @@ -256,6 +264,14 @@ public class HidDeviceService extends ProfileService { mService = service; } @VisibleForTesting HidDeviceService getServiceForTesting() { if (mService != null && mService.isAvailable()) { return mService; } return null; } @Override public boolean cleanup() { mService = null; Loading Loading @@ -456,8 +472,8 @@ public class HidDeviceService extends ProfileService { mAppConfig = config; mCallback = callback; return registerAppNative(sdp.name, sdp.description, sdp.provider, sdp.subclass, sdp.descriptors, inQos == null ? null : inQos.toArray(), return mHidDeviceNativeInterface.registerApp(sdp.name, sdp.description, sdp.provider, sdp.subclass, sdp.descriptors, inQos == null ? null : inQos.toArray(), outQos == null ? null : outQos.toArray()); } Loading @@ -475,7 +491,7 @@ public class HidDeviceService extends ProfileService { return false; } return unregisterAppNative(); return mHidDeviceNativeInterface.unregisterApp(); } synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) { Loading @@ -487,7 +503,7 @@ public class HidDeviceService extends ProfileService { return false; } return sendReportNative(id, data); return mHidDeviceNativeInterface.sendReport(id, data); } synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { Loading @@ -499,7 +515,7 @@ public class HidDeviceService extends ProfileService { return false; } return replyReportNative(type, id, data); return mHidDeviceNativeInterface.replyReport(type, id, data); } synchronized boolean unplug(BluetoothDevice device) { Loading @@ -511,7 +527,7 @@ public class HidDeviceService extends ProfileService { return false; } return unplugNative(); return mHidDeviceNativeInterface.unplug(); } synchronized boolean connect(BluetoothDevice device) { Loading @@ -519,7 +535,7 @@ public class HidDeviceService extends ProfileService { Log.d(TAG, "connect(): device=" + device); } return connectNative(Utils.getByteAddress(device)); return mHidDeviceNativeInterface.connect(device); } synchronized boolean disconnect(BluetoothDevice device) { Loading @@ -531,7 +547,7 @@ public class HidDeviceService extends ProfileService { return false; } return disconnectNative(); return mHidDeviceNativeInterface.disconnect(); } synchronized boolean reportError(BluetoothDevice device, byte error) { Loading @@ -543,7 +559,7 @@ public class HidDeviceService extends ProfileService { return false; } return reportErrorNative(error); return mHidDeviceNativeInterface.reportError(error); } @Override Loading @@ -552,9 +568,10 @@ public class HidDeviceService extends ProfileService { Log.d(TAG, "start()"); } initNative(); mHandler = new HidDeviceServiceHandler(); setHidDeviceService(this); mHidDeviceNativeInterface.init(); mNativeAvailable = true; return true; } Loading @@ -574,7 +591,7 @@ public class HidDeviceService extends ProfileService { } if (mNativeAvailable) { cleanupNative(); mHidDeviceNativeInterface.cleanup(); mNativeAvailable = false; } Loading @@ -588,6 +605,26 @@ public class HidDeviceService extends ProfileService { return super.onUnbind(intent); } /** * Get the HID Device Service instance * @return HID Device Service instance */ public static synchronized HidDeviceService getHidDeviceService() { if (sHidDeviceService == null) { Log.d(TAG, "getHidDeviceService(): service is NULL"); return null; } if (!sHidDeviceService.isAvailable()) { Log.d(TAG, "getHidDeviceService(): service is not available"); return null; } return sHidDeviceService; } private static synchronized void setHidDeviceService(HidDeviceService instance) { sHidDeviceService = instance; } int getConnectionState(BluetoothDevice device) { if (mHidDevice != null && mHidDevice.equals(device)) { return mHidDeviceState; Loading @@ -610,30 +647,31 @@ public class HidDeviceService extends ProfileService { return inputDevices; } private synchronized void onApplicationStateChanged(byte[] address, boolean registered) { synchronized void onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered) { if (DBG) { Log.d(TAG, "onApplicationStateChanged(): registered=" + registered); } Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED); msg.obj = address; msg.obj = device; msg.arg1 = registered ? 1 : 0; mHandler.sendMessage(msg); } private synchronized void onConnectStateChanged(byte[] address, int state) { synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) { if (DBG) { Log.d(TAG, "onConnectStateChanged(): address=" + Arrays.toString(address) + " state=" + state); Log.d(TAG, "onConnectStateChanged(): device=" + device + " state=" + state); } Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); msg.obj = address; msg.obj = device; msg.arg1 = state; mHandler.sendMessage(msg); } private synchronized void onGetReport(byte type, byte id, short bufferSize) { synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) { if (DBG) { Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize); } Loading @@ -645,7 +683,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onSetReport(byte reportType, byte reportId, byte[] data) { synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) { if (DBG) { Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId); } Loading @@ -659,7 +697,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onSetProtocol(byte protocol) { synchronized void onSetProtocolFromNative(byte protocol) { if (DBG) { Log.d(TAG, "onSetProtocol(): protocol=" + protocol); } Loading @@ -669,7 +707,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onIntrData(byte reportId, byte[] data) { synchronized void onIntrDataFromNative(byte reportId, byte[] data) { if (DBG) { Log.d(TAG, "onIntrData(): reportId=" + reportId); } Loading @@ -682,7 +720,7 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private synchronized void onVirtualCableUnplug() { synchronized void onVirtualCableUnplugFromNative() { if (DBG) { Log.d(TAG, "onVirtualCableUnplug()"); } Loading @@ -691,10 +729,10 @@ public class HidDeviceService extends ProfileService { mHandler.sendMessage(msg); } private void broadcastConnectionState(BluetoothDevice device, int newState) { private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) { if (DBG) { Log.d(TAG, "broadcastConnectionState(): device=" + device.getAddress() + " newState=" + newState); Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress() + " oldState=" + mHidDeviceState + " newState=" + newState); } if (mHidDevice != null && !mHidDevice.equals(device)) { Loading @@ -705,10 +743,8 @@ public class HidDeviceService extends ProfileService { int prevState = mHidDeviceState; mHidDeviceState = newState; Log.i(TAG, "connection state for " + device.getAddress() + ": " + prevState + " -> " + newState); if (prevState == newState) { Log.w(TAG, "Connection state is unchanged, ignoring"); return; } Loading Loading @@ -739,27 +775,4 @@ public class HidDeviceService extends ProfileService { private static final int CONN_STATE_CONNECTING = 1; private static final int CONN_STATE_DISCONNECTED = 2; private static final int CONN_STATE_DISCONNECTING = 3; private static native void classInitNative(); private native void initNative(); private native void cleanupNative(); private native boolean registerAppNative(String name, String description, String provider, byte subclass, byte[] descriptors, int[] inQos, int[] outQos); private native boolean unregisterAppNative(); private native boolean sendReportNative(int id, byte[] data); private native boolean replyReportNative(byte type, byte id, byte[] data); private native boolean unplugNative(); private native boolean connectNative(byte[] btAddress); private native boolean disconnectNative(); private native boolean reportErrorNative(byte error); }
android/app/tests/unit/src/com/android/bluetooth/hid/HidDeviceTest.java 0 → 100644 +183 −0 File added.Preview size limit exceeded, changes collapsed. Show changes