diff options
13 files changed, 1014 insertions, 1 deletions
diff --git a/Android.mk b/Android.mk index 36c9b596848c..cf4930271576 100644 --- a/Android.mk +++ b/Android.mk @@ -124,6 +124,8 @@ LOCAL_SRC_FILES += \ core/java/android/bluetooth/IBluetoothSap.aidl \ core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \ core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \ + core/java/android/bluetooth/IBluetoothHidDevice.aidl \ + core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl \ core/java/android/bluetooth/IBluetoothGatt.aidl \ core/java/android/bluetooth/IBluetoothGattCallback.aidl \ core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \ diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 6c1e2a932700..1f7d92942162 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -1940,6 +1940,9 @@ public final class BluetoothAdapter { } else if (profile == BluetoothProfile.MAP_CLIENT) { BluetoothMapClient mapClient = new BluetoothMapClient(context, listener); return true; + } else if (profile == BluetoothProfile.HID_DEVICE) { + BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener); + return true; } else { return false; } @@ -2016,6 +2019,10 @@ public final class BluetoothAdapter { BluetoothMapClient mapClient = (BluetoothMapClient)proxy; mapClient.close(); break; + case BluetoothProfile.HID_DEVICE: + BluetoothHidDevice hidd = (BluetoothHidDevice) proxy; + hidd.close(); + break; } } diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java new file mode 100644 index 000000000000..3e6a07866075 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.Arrays; +import java.util.List; + +/** + * @hide + */ +public final class BluetoothHidDevice implements BluetoothProfile { + + private static final String TAG = BluetoothHidDevice.class.getSimpleName(); + + public static final String ACTION_CONNECTION_STATE_CHANGED = + "android.bluetooth.hid.profile.action.CONNECTION_STATE_CHANGED"; + + /** + * Constants representing device subclass. + * + * @see #registerApp(String, String, String, byte, byte[], + * BluetoothHidDeviceCallback) + */ + public static final byte SUBCLASS1_NONE = (byte) 0x00; + public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40; + public static final byte SUBCLASS1_MOUSE = (byte) 0x80; + public static final byte SUBCLASS1_COMBO = (byte) 0xC0; + + public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00; + public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01; + public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02; + public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03; + public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04; + public static final byte SUBCLASS2_DIGITIZER_TABLED = (byte) 0x05; + public static final byte SUBCLASS2_CARD_READER = (byte) 0x06; + + /** + * Constants representing report types. + * + * @see BluetoothHidDeviceCallback#onGetReport(byte, byte, int) + * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[]) + * @see BluetoothHidDeviceCallback#onIntrData(byte, byte[]) + */ + public static final byte REPORT_TYPE_INPUT = (byte) 1; + public static final byte REPORT_TYPE_OUTPUT = (byte) 2; + public static final byte REPORT_TYPE_FEATURE = (byte) 3; + + /** + * Constants representing error response for Set Report. + * + * @see BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[]) + */ + public static final byte ERROR_RSP_SUCCESS = (byte) 0; + public static final byte ERROR_RSP_NOT_READY = (byte) 1; + public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2; + public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3; + public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4; + public static final byte ERROR_RSP_UNKNOWN = (byte) 14; + + /** + * Constants representing protocol mode used set by host. Default is always + * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise. + * + * @see BluetoothHidDeviceCallback#onSetProtocol(byte) + */ + public static final byte PROTOCOL_BOOT_MODE = (byte) 0; + public static final byte PROTOCOL_REPORT_MODE = (byte) 1; + + private Context mContext; + + private ServiceListener mServiceListener; + + private IBluetoothHidDevice mService; + + private BluetoothAdapter mAdapter; + + private static class BluetoothHidDeviceCallbackWrapper extends IBluetoothHidDeviceCallback.Stub { + + private BluetoothHidDeviceCallback mCallback; + + public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) { + mCallback = callback; + } + + @Override + public void onAppStatusChanged(BluetoothDevice pluggedDevice, + BluetoothHidDeviceAppConfiguration config, boolean registered) { + mCallback.onAppStatusChanged(pluggedDevice, config, registered); + } + + @Override + public void onConnectionStateChanged(BluetoothDevice device, int state) { + mCallback.onConnectionStateChanged(device, state); + } + + @Override + public void onGetReport(byte type, byte id, int bufferSize) { + mCallback.onGetReport(type, id, bufferSize); + } + + @Override + public void onSetReport(byte type, byte id, byte[] data) { + mCallback.onSetReport(type, id, data); + } + + @Override + public void onSetProtocol(byte protocol) { + mCallback.onSetProtocol(protocol); + } + + @Override + public void onIntrData(byte reportId, byte[] data) { + mCallback.onIntrData(reportId, data); + } + + @Override + public void onVirtualCableUnplug() { + mCallback.onVirtualCableUnplug(); + } + } + + final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = + new IBluetoothStateChangeCallback.Stub() { + + public void onBluetoothStateChange(boolean up) { + Log.d(TAG, "onBluetoothStateChange: up=" + up); + synchronized (mConnection) { + if (!up) { + Log.d(TAG,"Unbinding service..."); + if (mService != null) { + mService = null; + try { + mContext.unbindService(mConnection); + } catch (IllegalArgumentException e) { + Log.e(TAG,"onBluetoothStateChange: could not unbind service:", e); + } + } + } else { + try { + if (mService == null) { + Log.d(TAG,"Binding HID Device service..."); + doBind(); + } + } catch (IllegalStateException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e); + } catch (SecurityException e) { + Log.e(TAG,"onBluetoothStateChange: could not bind to HID Dev service: ", e); + } + } + } + } + }; + + private ServiceConnection mConnection = new ServiceConnection() { + + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "onServiceConnected()"); + + mService = IBluetoothHidDevice.Stub.asInterface(service); + + if (mServiceListener != null) { + mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE, + BluetoothHidDevice.this); + } + } + + public void onServiceDisconnected(ComponentName className) { + Log.d(TAG, "onServiceDisconnected()"); + + mService = null; + + if (mServiceListener != null) { + mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE); + } + } + }; + + BluetoothHidDevice(Context context, ServiceListener listener) { + Log.v(TAG, "BluetoothHidDevice"); + + mContext = context; + mServiceListener = listener; + mAdapter = BluetoothAdapter.getDefaultAdapter(); + + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + doBind(); + } + + boolean doBind() { + Intent intent = new Intent(IBluetoothHidDevice.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0, + android.os.Process.myUserHandle())) { + Log.e(TAG, "Could not bind to Bluetooth HID Device Service with " + intent); + return false; + } + Log.d(TAG, "Bound to HID Device Service"); + return true; + } + + void close() { + Log.v(TAG, "close()"); + + IBluetoothManager mgr = mAdapter.getBluetoothManager(); + if (mgr != null) { + try { + mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback); + } catch (RemoteException e) { + e.printStackTrace(); + } + } + + synchronized (mConnection) { + if (mService != null) { + mService = null; + try { + mContext.unbindService(mConnection); + } catch (IllegalArgumentException e) { + Log.e(TAG,"close: could not unbind HID Dev service: ", e); + } + } + } + + mServiceListener = null; + } + + @Override + public List<BluetoothDevice> getConnectedDevices() { + Log.v(TAG, "getConnectedDevices()"); + return null; + } + + @Override + public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { + Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); + return null; + } + + @Override + public int getConnectionState(BluetoothDevice device) { + Log.v(TAG, "getConnectionState(): device=" + device.getAddress()); + + return STATE_DISCONNECTED; + } + + /** + * Registers application to be used for HID device. Connections to HID + * Device are only possible when application is registered. Only one + * application can be registered at time. When no longer used, application + * should be unregistered using + * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}. + * + * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of + * HID Device SDP record. + * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of + * Incoming QoS Settings. + * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of + * Outgoing QoS Settings. + * @param callback {@link BluetoothHidDeviceCallback} object to which + * callback messages will be sent. + * @return + */ + public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, + BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, + BluetoothHidDeviceCallback callback) { + Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos + + " callback=" + callback); + + boolean result = false; + + if (sdp == null || callback == null) { + return false; + } + + if (mService != null) { + try { + BluetoothHidDeviceAppConfiguration config = + new BluetoothHidDeviceAppConfiguration(); + BluetoothHidDeviceCallbackWrapper cbw = + new BluetoothHidDeviceCallbackWrapper(callback); + result = mService.registerApp(config, sdp, inQos, outQos, cbw); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Unregisters application. Active connection will be disconnected and no + * new connections will be allowed until registered again using + * {@link #registerApp(String, String, String, byte, byte[], BluetoothHidDeviceCallback)} + * + * @param config {@link BluetoothHidDeviceAppConfiguration} object as + * obtained from + * {@link BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice, + * BluetoothHidDeviceAppConfiguration, boolean)} + * + * @return + */ + public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) { + Log.v(TAG, "unregisterApp()"); + + boolean result = false; + + if (mService != null) { + try { + result = mService.unregisterApp(config); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Sends report to remote host using interrupt channel. + * + * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id + * are not defined in descriptor. + * @param data Report data, not including Report Id. + * @return + */ + public boolean sendReport(int id, byte[] data) { + Log.v(TAG, "sendReport(): id=" + id); + + boolean result = false; + + if (mService != null) { + try { + result = mService.sendReport(id, data); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Sends report to remote host as reply for GET_REPORT request from + * {@link BluetoothHidDeviceCallback#onGetReport(byte, byte, int)}. + * + * @param type Report Type, as in request. + * @param id Report Id, as in request. + * @param data Report data, not including Report Id. + * @return + */ + public boolean replyReport(byte type, byte id, byte[] data) { + Log.v(TAG, "replyReport(): type=" + type + " id=" + id); + + boolean result = false; + + if (mService != null) { + try { + result = mService.replyReport(type, id, data); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Sends error handshake message as reply for invalid SET_REPORT request + * from {@link BluetoothHidDeviceCallback#onSetReport(byte, byte, byte[])}. + * + * @param error Error to be sent for SET_REPORT via HANDSHAKE. + * @return + */ + public boolean reportError(byte error) { + Log.v(TAG, "reportError(): error = " + error); + + boolean result = false; + + if (mService != null) { + try { + result = mService.reportError(error); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Sends Virtual Cable Unplug to currently connected host. + * + * @return + */ + public boolean unplug() { + Log.v(TAG, "unplug()"); + + boolean result = false; + + if (mService != null) { + try { + result = mService.unplug(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Initiates connection to host which currently has Virtual Cable + * established with device. + * + * @return + */ + public boolean connect() { + Log.v(TAG, "connect()"); + + boolean result = false; + + if (mService != null) { + try { + result = mService.connect(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } + + /** + * Disconnects from currently connected host. + * + * @return + */ + public boolean disconnect() { + Log.v(TAG, "disconnect()"); + + boolean result = false; + + if (mService != null) { + try { + result = mService.disconnect(); + } catch (RemoteException e) { + Log.e(TAG, e.toString()); + } + } else { + Log.w(TAG, "Proxy not attached to service"); + } + + return result; + } +} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl new file mode 100644 index 000000000000..283a71790d3d --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2016, 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. +*/ + +package android.bluetooth; + +parcelable BluetoothHidDeviceAppConfiguration; diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java new file mode 100644 index 000000000000..05ba64e981f1 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Random; + +/** @hide */ +public final class BluetoothHidDeviceAppConfiguration implements Parcelable { + private final long mHash; + + BluetoothHidDeviceAppConfiguration() { + Random rnd = new Random(); + mHash = rnd.nextLong(); + } + + BluetoothHidDeviceAppConfiguration(long hash) { + mHash = hash; + } + + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothHidDeviceAppConfiguration) { + BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o; + return mHash == config.mHash; + } + return false; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR = + new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() { + + @Override + public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) { + long hash = in.readLong(); + return new BluetoothHidDeviceAppConfiguration(hash); + } + + @Override + public BluetoothHidDeviceAppConfiguration[] newArray(int size) { + return new BluetoothHidDeviceAppConfiguration[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeLong(mHash); + } +} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl new file mode 100644 index 000000000000..14f91140af2b --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2016, 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. +*/ + +package android.bluetooth; + +parcelable BluetoothHidDeviceAppQosSettings; diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java new file mode 100644 index 000000000000..0d6530c11a91 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Random; + +/** @hide */ +public final class BluetoothHidDeviceAppQosSettings implements Parcelable { + + final public int serviceType; + final public int tokenRate; + final public int tokenBucketSize; + final public int peakBandwidth; + final public int latency; + final public int delayVariation; + + final static public int SERVICE_NO_TRAFFIC = 0x00; + final static public int SERVICE_BEST_EFFORT = 0x01; + final static public int SERVICE_GUARANTEED = 0x02; + + final static public int MAX = (int) 0xffffffff; + + public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize, + int peakBandwidth, + int latency, int delayVariation) { + this.serviceType = serviceType; + this.tokenRate = tokenRate; + this.tokenBucketSize = tokenBucketSize; + this.peakBandwidth = peakBandwidth; + this.latency = latency; + this.delayVariation = delayVariation; + } + + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothHidDeviceAppQosSettings) { + BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o; + return false; + } + return false; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothHidDeviceAppQosSettings> CREATOR = + new Parcelable.Creator<BluetoothHidDeviceAppQosSettings>() { + + @Override + public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) { + + return new BluetoothHidDeviceAppQosSettings(in.readInt(), in.readInt(), in.readInt(), + in.readInt(), + in.readInt(), in.readInt()); + } + + @Override + public BluetoothHidDeviceAppQosSettings[] newArray(int size) { + return new BluetoothHidDeviceAppQosSettings[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(serviceType); + out.writeInt(tokenRate); + out.writeInt(tokenBucketSize); + out.writeInt(peakBandwidth); + out.writeInt(latency); + out.writeInt(delayVariation); + } + + public int[] toArray() { + return new int[] { + serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation + }; + } +} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl new file mode 100644 index 000000000000..87dd10ee15f4 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.aidl @@ -0,0 +1,19 @@ +/* +** Copyright 2016, 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. +*/ + +package android.bluetooth; + +parcelable BluetoothHidDeviceAppSdpSettings; diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java new file mode 100644 index 000000000000..f9a224581953 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Random; + +/** @hide */ +public final class BluetoothHidDeviceAppSdpSettings implements Parcelable { + + final public String name; + final public String description; + final public String provider; + final public byte subclass; + final public byte[] descriptors; + + public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider, + byte subclass, byte[] descriptors) { + this.name = name; + this.description = description; + this.provider = provider; + this.subclass = subclass; + this.descriptors = descriptors.clone(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothHidDeviceAppSdpSettings) { + BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o; + return false; + } + return false; + } + + @Override + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothHidDeviceAppSdpSettings> CREATOR = + new Parcelable.Creator<BluetoothHidDeviceAppSdpSettings>() { + + @Override + public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) { + + return new BluetoothHidDeviceAppSdpSettings(in.readString(), in.readString(), + in.readString(), in.readByte(), in.createByteArray()); + } + + @Override + public BluetoothHidDeviceAppSdpSettings[] newArray(int size) { + return new BluetoothHidDeviceAppSdpSettings[size]; + } + }; + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeString(name); + out.writeString(description); + out.writeString(provider); + out.writeByte(subclass); + out.writeByteArray(descriptors); + } +} diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java new file mode 100644 index 000000000000..0f0e050a1f40 --- /dev/null +++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.util.Log; + +/** @hide */ +public abstract class BluetoothHidDeviceCallback { + + private static final String TAG = BluetoothHidDeviceCallback.class.getSimpleName(); + + /** + * Callback called when application registration state changes. Usually it's + * called due to either + * {@link BluetoothHidDevice#registerApp(String, String, String, byte, byte[], + * BluetoothHidDeviceCallback)} + * or + * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)} + * , but can be also unsolicited in case e.g. Bluetooth was turned off in + * which case application is unregistered automatically. + * + * @param pluggedDevice {@link BluetoothDevice} object which represents host + * that currently has Virtual Cable established with device. Only + * valid when application is registered, can be <code>null</code> + * . + * @param config {@link BluetoothHidDeviceAppConfiguration} object which + * represents token required to unregister application using + * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)} + * . + * @param registered <code>true</code> if application is registered, + * <code>false</code> otherwise. + */ + public void onAppStatusChanged(BluetoothDevice pluggedDevice, + BluetoothHidDeviceAppConfiguration config, boolean registered) { + Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + (pluggedDevice == null ? + null : pluggedDevice.toString()) + " registered=" + registered); + } + + /** + * Callback called when connection state with remote host was changed. + * Application can assume than Virtual Cable is established when called with + * {@link BluetoothProfile#STATE_CONNECTED} <code>state</code>. + * + * @param device {@link BluetoothDevice} object representing host device + * which connection state was changed. + * @param state Connection state as defined in {@link BluetoothProfile}. + */ + public void onConnectionStateChanged(BluetoothDevice device, int state) { + Log.d(TAG, "onConnectionStateChanged: device=" + device.toString() + " state=" + state); + } + + /** + * Callback called when GET_REPORT is received from remote host. Should be + * replied by application using + * {@link BluetoothHidDevice#replyReport(byte, byte, byte[])}. + * + * @param type Requested Report Type. + * @param id Requested Report Id, can be 0 if no Report Id are defined in + * descriptor. + * @param bufferSize Requested buffer size, application shall respond with + * at least given number of bytes. + */ + public void onGetReport(byte type, byte id, int bufferSize) { + Log.d(TAG, "onGetReport: type=" + type + " id=" + id + " bufferSize=" + bufferSize); + } + + /** + * Callback called when SET_REPORT is received from remote host. In case + * received data are invalid, application shall respond with + * {@link BluetoothHidDevice#reportError()}. + * + * @param type Report Type. + * @param id Report Id. + * @param data Report data. + */ + public void onSetReport(byte type, byte id, byte[] data) { + Log.d(TAG, "onSetReport: type=" + type + " id=" + id); + } + + /** + * Callback called when SET_PROTOCOL is received from remote host. + * Application shall use this information to send only reports valid for + * given protocol mode. By default, + * {@link BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed. + * + * @param protocol Protocol Mode. + */ + public void onSetProtocol(byte protocol) { + Log.d(TAG, "onSetProtocol: protocol=" + protocol); + } + + /** + * Callback called when report data is received over interrupt channel. + * Report Type is assumed to be + * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}. + * + * @param reportId Report Id. + * @param data Report data. + */ + public void onIntrData(byte reportId, byte[] data) { + Log.d(TAG, "onIntrData: reportId=" + reportId); + } + + /** + * Callback called when Virtual Cable is removed. This can be either due to + * {@link BluetoothHidDevice#unplug()} or request from remote side. After + * this callback is received connection will be disconnected automatically. + */ + public void onVirtualCableUnplug() { + Log.d(TAG, "onVirtualCableUnplug"); + } +} diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index f3636070fa5c..6a009a9ba282 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -143,11 +143,17 @@ public interface BluetoothProfile { public static final int MAP_CLIENT = 18; /** + * HID device + * @hide + */ + static public final int HID_DEVICE = 19; + + /** * Max profile ID. This value should be updated whenever a new profile is added to match * the largest value assigned to a profile. * @hide */ - public static final int MAX_PROFILE_ID = 17; + public static final int MAX_PROFILE_ID = 19; /** * Default priority for devices that we try to auto-connect to and diff --git a/core/java/android/bluetooth/IBluetoothHidDevice.aidl b/core/java/android/bluetooth/IBluetoothHidDevice.aidl new file mode 100644 index 000000000000..15f73138e2cb --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothHidDevice.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 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. + */ + +package android.bluetooth; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidDeviceAppConfiguration; +import android.bluetooth.IBluetoothHidDeviceCallback; +import android.bluetooth.BluetoothHidDeviceAppSdpSettings; +import android.bluetooth.BluetoothHidDeviceAppQosSettings; + +/** @hide */ +interface IBluetoothHidDevice { + boolean registerApp(in BluetoothHidDeviceAppConfiguration config, + in BluetoothHidDeviceAppSdpSettings sdp, in BluetoothHidDeviceAppQosSettings inQos, + in BluetoothHidDeviceAppQosSettings outQos, in IBluetoothHidDeviceCallback callback); + boolean unregisterApp(in BluetoothHidDeviceAppConfiguration config); + boolean sendReport(in int id, in byte[] data); + boolean replyReport(in byte type, in byte id, in byte[] data); + boolean reportError(byte error); + boolean unplug(); + boolean connect(); + boolean disconnect(); +} diff --git a/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl new file mode 100644 index 000000000000..125287696585 --- /dev/null +++ b/core/java/android/bluetooth/IBluetoothHidDeviceCallback.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016, 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. + */ + +package android.bluetooth; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHidDeviceAppConfiguration; + +/** @hide */ +interface IBluetoothHidDeviceCallback { + void onAppStatusChanged(in BluetoothDevice device, in BluetoothHidDeviceAppConfiguration config, boolean registered); + void onConnectionStateChanged(in BluetoothDevice device, in int state); + void onGetReport(in byte type, in byte id, in int bufferSize); + void onSetReport(in byte type, in byte id, in byte[] data); + void onSetProtocol(in byte protocol); + void onIntrData(in byte reportId, in byte[] data); + void onVirtualCableUnplug(); +} |