Skip to content

Commit

Permalink
OBEX: Implementation of MAP and PBAP client role on Bluedroid
Browse files Browse the repository at this point in the history
Implementation changes to support MAP client and PBAP client
role on Bluedroid stack.

Change-Id: Ic75e0bea10b8420aef928d868cc25acd769d5620
CRs-fixed: 530274
  • Loading branch information
Ashwini Munigala authored and hyperb1iss committed Sep 20, 2013
1 parent dcf75fb commit a238389
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 9 deletions.
23 changes: 23 additions & 0 deletions core/java/android/bluetooth/BluetoothDevice.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2013 The Linux Foundation. All rights reserved
* Not a Contribution.
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -296,6 +298,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 =
"org.codeaurora.bluetooth.device.action.MAS_INSTANCE";

/**
* Broadcast Action: Indicates a failure to retrieve the name of a remote
* device.
Expand Down Expand Up @@ -498,6 +505,10 @@ public final class BluetoothDevice implements Parcelable {
*/
public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";

/** @hide */
public static final String EXTRA_MAS_INSTANCE =
"org.codeaurora.bluetooth.device.extra.MAS_INSTANCE";

/**
* Lazy initialization. Guaranteed final after first object constructed, or
* getService() called.
Expand Down Expand Up @@ -945,6 +956,18 @@ public boolean fetchUuidsWithSdp() {
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)
Expand Down
116 changes: 116 additions & 0 deletions core/java/android/bluetooth/BluetoothMasInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of The Linux Foundation nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


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;
}
}
3 changes: 3 additions & 0 deletions core/java/android/bluetooth/IBluetooth.aidl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2013 The Linux Foundation. All rights reserved
* Not a Contribution.
* Copyright (C) 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -68,6 +70,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[]
Expand Down
49 changes: 40 additions & 9 deletions obex/javax/obex/ClientOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ public final class ClientOperation implements Operation, BaseStream {

private boolean mGetOperation;

private boolean mGetFinalFlag;

private HeaderSet mRequestHeader;

private HeaderSet mReplyHeader;
Expand All @@ -91,6 +93,7 @@ public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean t
mOperationDone = false;
mMaxPacketSize = maxSize;
mGetOperation = type;
mGetFinalFlag = false;

mPrivateInputOpen = false;
mPrivateOutputOpen = false;
Expand Down Expand Up @@ -124,6 +127,15 @@ public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean t
}
}

/**
* 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
Expand Down Expand Up @@ -545,15 +557,25 @@ private synchronized void startProcessing() throws IOException {

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;
}
}
Expand Down Expand Up @@ -607,7 +629,16 @@ public synchronized boolean continueOperation(boolean sendEmpty, boolean inStrea
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) {
Expand Down
24 changes: 24 additions & 0 deletions obex/javax/obex/HeaderSet.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2013 The Linux Foundation. All rights reserved
* Not a Contribution.
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
Expand Down Expand Up @@ -181,6 +183,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
Expand Down Expand Up @@ -234,6 +238,25 @@ public HeaderSet() {
mRandom = new SecureRandom();
}

/**
* 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
Expand Down Expand Up @@ -269,6 +292,7 @@ public void setHeader(int headerID, Object headerValue) {
if ((headerValue != null) && (!(headerValue instanceof String))) {
throw new IllegalArgumentException("Name must be a String");
}
mEmptyName = false;
mName = (String)headerValue;
break;
case TYPE:
Expand Down
7 changes: 7 additions & 0 deletions obex/javax/obex/ObexHelper.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/*
* Copyright (C) 2013 The Linux Foundation. All rights reserved
* Not a Contribution.
* Copyright (c) 2008-2009, Motorola, Inc.
*
* All rights reserved.
Expand Down Expand Up @@ -387,6 +389,11 @@ public static byte[] createHeader(HeaderSet head, boolean nullOut) {
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
Expand Down

0 comments on commit a238389

Please sign in to comment.