diff options
author | Hemant Gupta <hemantg@codeaurora.org> | 2013-08-16 14:57:55 +0530 |
---|---|---|
committer | Mike Lockwood <lockwood@google.com> | 2014-07-01 18:01:27 +0000 |
commit | 8949bfb90c415629dbd0e30d25003fb3e0375fb5 (patch) | |
tree | a11a128c60d3301f41419e1ef9598d3a1bc28cc5 | |
parent | e19a4fe32fd87a6c819f15155bb43d9fbe67607a (diff) | |
download | frameworks_base-8949bfb90c415629dbd0e30d25003fb3e0375fb5.zip frameworks_base-8949bfb90c415629dbd0e30d25003fb3e0375fb5.tar.gz frameworks_base-8949bfb90c415629dbd0e30d25003fb3e0375fb5.tar.bz2 |
Bluetooth: Support MAP Client role on Bluedroid.
Implementation changes to support MAP client and PBAP client
role on Bluedroid stack.
Change-Id: I1733a67bf5256bd7b181bd5e68e40b476994ebfd
-rw-r--r-- | core/java/android/bluetooth/BluetoothDevice.java | 24 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothMasInstance.java | 103 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetooth.aidl | 1 | ||||
-rw-r--r-- | core/res/AndroidManifest.xml | 10 | ||||
-rw-r--r-- | core/res/res/values/strings.xml | 7 | ||||
-rw-r--r-- | obex/javax/obex/ClientOperation.java | 50 | ||||
-rw-r--r-- | obex/javax/obex/HeaderSet.java | 23 | ||||
-rw-r--r-- | obex/javax/obex/ObexHelper.java | 6 |
8 files changed, 213 insertions, 11 deletions
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 64d80a0..a94bc41 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -306,6 +306,11 @@ public final class BluetoothDevice implements Parcelable { public static final String ACTION_UUID = "android.bluetooth.device.action.UUID"; + /** @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_MAS_INSTANCE = + "android.bluetooth.device.action.MAS_INSTANCE"; + /** * Broadcast Action: Indicates a failure to retrieve the name of a remote * device. @@ -522,14 +527,17 @@ public final class BluetoothDevice implements Parcelable { * Prefer BR/EDR transport for GATT connections to remote dual-mode devices * @hide */ - public static final int TRANSPORT_BREDR = 1; + public static final int TRANSPORT_BREDR = 1; /** * Prefer LE transport for GATT connections to remote dual-mode devices * @hide */ - public static final int TRANSPORT_LE = 2; + public static final int TRANSPORT_LE = 2; + /** @hide */ + public static final String EXTRA_MAS_INSTANCE = + "android.bluetooth.device.extra.MAS_INSTANCE"; /** * Lazy initialization. Guaranteed final after first object constructed, or @@ -995,6 +1003,18 @@ public final class BluetoothDevice implements Parcelable { return false; } + /** @hide */ + public boolean fetchMasInstances() { + if (sService == null) { + Log.e(TAG, "BT not enabled. Cannot query remote device for MAS instances"); + return false; + } + try { + return sService.fetchRemoteMasInstances(this); + } catch (RemoteException e) {Log.e(TAG, "", e);} + return false; + } + /** @hide */ public int getServiceChannel(ParcelUuid uuid) { //TODO(BT) diff --git a/core/java/android/bluetooth/BluetoothMasInstance.java b/core/java/android/bluetooth/BluetoothMasInstance.java new file mode 100644 index 0000000..4459e2c --- /dev/null +++ b/core/java/android/bluetooth/BluetoothMasInstance.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014 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; + +/** @hide */ +public final class BluetoothMasInstance implements Parcelable { + private final int mId; + private final String mName; + private final int mChannel; + private final int mMsgTypes; + + public BluetoothMasInstance(int id, String name, int channel, int msgTypes) { + mId = id; + mName = name; + mChannel = channel; + mMsgTypes = msgTypes; + } + + @Override + public boolean equals(Object o) { + if (o instanceof BluetoothMasInstance) { + return mId == ((BluetoothMasInstance)o).mId; + } + return false; + } + + @Override + public int hashCode() { + return mId + (mChannel << 8) + (mMsgTypes << 16); + } + + @Override + public String toString() { + return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":" + + Integer.toHexString(mMsgTypes); + } + + public int describeContents() { + return 0; + } + + public static final Parcelable.Creator<BluetoothMasInstance> CREATOR = + new Parcelable.Creator<BluetoothMasInstance>() { + public BluetoothMasInstance createFromParcel(Parcel in) { + return new BluetoothMasInstance(in.readInt(), in.readString(), + in.readInt(), in.readInt()); + } + public BluetoothMasInstance[] newArray(int size) { + return new BluetoothMasInstance[size]; + } + }; + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mId); + out.writeString(mName); + out.writeInt(mChannel); + out.writeInt(mMsgTypes); + } + + public static final class MessageType { + public static final int EMAIL = 0x01; + public static final int SMS_GSM = 0x02; + public static final int SMS_CDMA = 0x04; + public static final int MMS = 0x08; + } + + public int getId() { + return mId; + } + + public String getName() { + return mName; + } + + public int getChannel() { + return mChannel; + } + + public int getMsgTypes() { + return mMsgTypes; + } + + public boolean msgSupported(int msg) { + return (mMsgTypes & msg) != 0; + } +} diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index a45c6b8..df6037e 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -67,6 +67,7 @@ interface IBluetooth int getRemoteClass(in BluetoothDevice device); ParcelUuid[] getRemoteUuids(in BluetoothDevice device); boolean fetchRemoteUuids(in BluetoothDevice device); + boolean fetchRemoteMasInstances(in BluetoothDevice device); boolean setPin(in BluetoothDevice device, boolean accept, int len, in byte[] pinCode); boolean setPasskey(in BluetoothDevice device, boolean accept, int len, in byte[] diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7db478d..450a889 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -99,6 +99,7 @@ <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.UUID" /> + <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" /> <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" /> <protected-broadcast android:name="android.bluetooth.device.action.FOUND" /> <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" /> @@ -396,6 +397,15 @@ android:label="@string/permlab_receiveWapPush" android:description="@string/permdesc_receiveWapPush" /> + <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record + or perform processing on them. --> + <!-- @hide --> + <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP" + android:permissionGroup="android.permission-group.MESSAGES" + android:protectionLevel="dangerous" + android:label="@string/permlab_receiveBluetoothMap" + android:description="@string/permdesc_receiveBluetoothMap" /> + <!-- =============================================================== --> <!-- Permissions for accessing social info (contacts and social) --> <!-- =============================================================== --> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a3262ed..a71ed47 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -761,6 +761,13 @@ messages sent to you without showing them to you.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_receiveBluetoothMap">receive Bluetooth messages (MAP)</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_receiveBluetoothMap">Allows the app to receive and process Bluetooth MAP + messages. This means the app could monitor or delete messages sent to your + device without showing them to you.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_getTasks">retrieve running apps</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_getTasks">Allows the app to retrieve information diff --git a/obex/javax/obex/ClientOperation.java b/obex/javax/obex/ClientOperation.java index 0c65283..75278b5 100644 --- a/obex/javax/obex/ClientOperation.java +++ b/obex/javax/obex/ClientOperation.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014 The Android Open Source Project * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. @@ -66,6 +67,8 @@ public final class ClientOperation implements Operation, BaseStream { private boolean mGetOperation; + private boolean mGetFinalFlag; + private HeaderSet mRequestHeader; private HeaderSet mReplyHeader; @@ -90,6 +93,7 @@ public final class ClientOperation implements Operation, BaseStream { mOperationDone = false; mMaxPacketSize = maxSize; mGetOperation = type; + mGetFinalFlag = false; mPrivateInputOpen = false; mPrivateOutputOpen = false; @@ -131,6 +135,15 @@ public final class ClientOperation implements Operation, BaseStream { } /** + * Allows to set flag which will force GET to be always sent as single packet request with + * final flag set. This is to improve compatibility with some profiles, i.e. PBAP which + * require requests to be sent this way. + */ + public void setGetFinalFlag(boolean flag) { + mGetFinalFlag = flag; + } + + /** * Sends an ABORT message to the server. By calling this method, the * corresponding input and output streams will be closed along with this * object. @@ -551,15 +564,25 @@ public final class ClientOperation implements Operation, BaseStream { if (mGetOperation) { if (!mOperationDone) { - mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE; - while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) { - more = sendRequest(0x03); - } + if (!mGetFinalFlag) { + mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE; + while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) { + more = sendRequest(0x03); + } + + if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) { + mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput); + } + if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) { + mOperationDone = true; + } + } else { + more = sendRequest(0x83); + + if (more) { + throw new IOException("FINAL_GET forced but data did not fit into single packet!"); + } - if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) { - mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput); - } - if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) { mOperationDone = true; } } @@ -613,7 +636,16 @@ public final class ClientOperation implements Operation, BaseStream { if (mPrivateInput == null) { mPrivateInput = new PrivateInputStream(this); } - sendRequest(0x03); + + if (!mGetFinalFlag) { + sendRequest(0x03); + } else { + sendRequest(0x83); + + if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) { + mOperationDone = true; + } + } return true; } else if (mOperationDone) { diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java index 2b3066f..51b560a 100644 --- a/obex/javax/obex/HeaderSet.java +++ b/obex/javax/obex/HeaderSet.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014 The Android Open Source Project * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. @@ -181,6 +182,8 @@ public final class HeaderSet { private String mName; // null terminated Unicode text string + private boolean mEmptyName; + private String mType; // null terminated ASCII text string private Long mLength; // 4 byte unsigend integer @@ -235,6 +238,25 @@ public final class HeaderSet { } /** + * Sets flag for special "value" of NAME header which should be empty. This + * is not the same as NAME header with empty string in which case it will + * have length of 5 bytes. It should be 3 bytes with only header id and + * length field. + */ + public void setEmptyNameHeader() { + mName = null; + mEmptyName = true; + } + + /** + * Gets flag for special "value" of NAME header which should be empty. See + * above. + */ + public boolean getEmptyNameHeader() { + return mEmptyName; + } + + /** * Sets the value of the header identifier to the value provided. The type * of object must correspond to the Java type defined in the description of * this interface. If <code>null</code> is passed as the @@ -269,6 +291,7 @@ public final class HeaderSet { if ((headerValue != null) && (!(headerValue instanceof String))) { throw new IllegalArgumentException("Name must be a String"); } + mEmptyName = false; mName = (String)headerValue; break; case TYPE: diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java index 8c12a20..0a06709 100644 --- a/obex/javax/obex/ObexHelper.java +++ b/obex/javax/obex/ObexHelper.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2014 The Android Open Source Project * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. @@ -387,6 +388,11 @@ public final class ObexHelper { if (nullOut) { headImpl.setHeader(HeaderSet.NAME, null); } + } else if (headImpl.getEmptyNameHeader()) { + out.write((byte) HeaderSet.NAME); + lengthArray[0] = (byte) 0x00; + lengthArray[1] = (byte) 0x03; + out.write(lengthArray); } // Type Header |