blob: 1ed4afe1962ec4b7c6a65e0aa779ab529539cb08 [file] [log] [blame]
package com.android.bluetooth.tests;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.bluetooth.SdpMasRecord;
import android.bluetooth.SdpMnsRecord;
import android.bluetooth.SdpOppOpsRecord;
import android.bluetooth.SdpPseRecord;
import android.bluetooth.SdpSapsRecord;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.ParcelUuid;
import android.util.Log;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.sdp.SdpManager;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import javax.obex.HeaderSet;
import javax.obex.Operation;
import javax.obex.ResponseCodes;
import javax.obex.ServerRequestHandler;
import junit.framework.Assert;
/**
* We use an OBEX server to execute SDP search operations, and validate results.
* @author cbonde
*
*/
public class SdpManagerTestServer extends ServerRequestHandler {
private static final String TAG = "SdpManagerTestServer";
private static final boolean V = true;
int mOperationIndex = 0;
int mResult = ResponseCodes.OBEX_HTTP_OK;
final Context mContext;
final CountDownLatch mStopLatch;
final BluetoothDevice mDevice;
public SdpManagerTestServer(CountDownLatch stopLatch, Context context,
BluetoothDevice device) {
super();
mStopLatch = stopLatch;
mContext = context;
mDevice = device;
Log.i(TAG, "created.");
}
/* OBEX operation handlers */
@Override
public int onConnect(HeaderSet request, HeaderSet reply) {
Log.i(TAG,"onConnect()");
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onConnect - aborting...");
result = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
// A read from null will produce exception to end the test.
}
return result;
}
@Override
public void onDisconnect(HeaderSet request, HeaderSet reply) {
Log.i(TAG,"onDisconnect()");
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onDisconnect...");
result = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
// A read from null will produce exception to end the test.
}
if(mOperationIndex == 0) {
/* End of test, signal test runner thread */
Log.i(TAG, "Sending latch close signal...");
mStopLatch.countDown();
} else {
Log.i(TAG, "Got disconnect with mOperationCounter = " + mOperationIndex);
}
reply.responseCode = result;
}
/**
* Currently not used
*/
@Override
public int onPut(Operation operation) {
Log.i(TAG,"onPut()");
int result = ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED;
return result;
}
/**
* Used to execute SDP search operations.
*/
@Override
public int onGet(Operation operation) {
Log.i(TAG,"onGet()");
/* - Use the name header to transfer a ';' separated list of UUID's to search for.
* - For each UUID:
* - start a search
* - validate each result received
* - ensure all records gets received (use CountDownLatch)
* */
mResult = ResponseCodes.OBEX_HTTP_OK;
try{
HeaderSet reqHeaders = operation.getReceivedHeader();
int index = ((Long)reqHeaders.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
/* Get the expected number of records to read. */
int count = ((Long)reqHeaders.getHeader(HeaderSet.COUNT)).intValue();
String name = (String)reqHeaders.getHeader(HeaderSet.NAME);
String[] uuids = name.split(";");
// Initiate search operations, Wait for results and validate
searchAwaitAndValidate(uuids, mDevice, count);
} catch (IOException e) {
Log.e(TAG, "Exception in onPut - aborting...");
mResult = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
} finally {
}
if(mResult == ResponseCodes.OBEX_HTTP_OK) {
Log.i(TAG, "OBEX-HANDLER: operation complete success");
} else {
Log.e(TAG, "OBEX-HANDLER: operation complete FAILED!");
}
return mResult;
}
class SdpBroadcastReceiver extends BroadcastReceiver {
boolean hasMas = false;
boolean hasMns = false;
boolean hasOppServer = false;
boolean hasSapServer = false;
boolean hasPse = false;
final CountDownLatch mLatch;
public SdpBroadcastReceiver(String[] uuids, CountDownLatch latch) {
for(String uuid : uuids) {
if(uuid.toString().equals(BluetoothUuid.MAS.toString()))
hasMas = true;
if(uuid.toString().equals(BluetoothUuid.MNS.toString()))
hasMns = true;
if(uuid.toString().equals(BluetoothUuid.PBAP_PSE.toString()))
hasPse = true;
if(uuid.toString().equals(BluetoothUuid.ObexObjectPush.toString()))
hasOppServer = true;
if(uuid.toString().equals(BluetoothUuid.SAP.toString()))
hasSapServer = true;
}
mLatch = latch;
}
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive");
String action = intent.getAction();
if (action.equals(BluetoothDevice.ACTION_SDP_RECORD)){
Log.v(TAG, "Received ACTION_SDP_RECORD.");
ParcelUuid uuid = intent.getParcelableExtra(BluetoothDevice.EXTRA_UUID);
Log.v(TAG, "Received UUID: " + uuid.toString());
if(hasMas && uuid.toString().equals(BluetoothUuid.MAS.toString())) {
Log.v(TAG, " -> MAS UUID in result.");
int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
Assert.assertEquals(AbstractionLayer.BT_STATUS_SUCCESS, status); /* BT_STATUS_SUCCESS == 0 - but status is not documented... */
Log.v(TAG, " -> status: "+status);
SdpMasRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
Assert.assertNotNull(record);
Log.v(TAG, " -> Record: " + record);
/* As the normal profiles are also running, we filter out these records */
if(record.getServiceName().equals(SdpManagerTest.SDP_SERVER_NAME)) {
Assert.assertEquals(((long)record.getSupportedFeatures())&0xffffffffL, SdpManagerTest.SDP_FEATURES);
Assert.assertEquals(record.getSupportedMessageTypes(), SdpManagerTest.SDP_MSG_TYPES);
Assert.assertEquals(record.getProfileVersion(), SdpManagerTest.SDP_VERSION);
Assert.assertEquals(record.getServiceName(), SdpManagerTest.SDP_SERVER_NAME);
Assert.assertEquals(record.getMasInstanceId(), SdpManagerTest.SDP_MAS_ID);
int rfcommChannel = record.getRfcommCannelNumber();
int l2capPsm = record.getL2capPsm();
/* We set RFCOMM-channel to record_id and the l2cap PSM to iteration*record_id */
Assert.assertEquals(mOperationIndex+rfcommChannel,l2capPsm);
mLatch.countDown();
} else {
Log.i(TAG, "Wrong service name (" + record.getServiceName()
+ ") received, still waiting...");
}
} else if(hasMns && uuid.toString().equals(BluetoothUuid.MNS.toString())) {
Log.v(TAG, " -> MAP_MNS UUID in result.");
int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
Assert.assertEquals(0, status); /* BT_STATUS_SUCCESS == 0 - but status is not documented... */
Log.v(TAG, " -> status: "+status);
SdpMnsRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
Assert.assertNotNull(record);
Log.v(TAG, " -> Record: " + record);
/* As the normal profiles are also running, we filter out these records */
if(record.getServiceName().equals(SdpManagerTest.SDP_SERVER_NAME)) {
Assert.assertEquals(((long)record.getSupportedFeatures())&0xffffffffL, SdpManagerTest.SDP_FEATURES);
Assert.assertEquals(record.getProfileVersion(), SdpManagerTest.SDP_VERSION);
Assert.assertEquals(record.getServiceName(), SdpManagerTest.SDP_SERVER_NAME);
int rfcommChannel = record.getRfcommChannelNumber();
int l2capPsm = record.getL2capPsm();
/* We set RFCOMM-channel to record_id and the l2cap PSM to iteration*record_id */
Assert.assertEquals(mOperationIndex+rfcommChannel,l2capPsm);
mLatch.countDown();
} else {
Log.i(TAG, "Wrong service name (" + record.getServiceName()
+ ") received, still waiting...");
}
} else if(hasPse && uuid.toString().equals(BluetoothUuid.PBAP_PSE.toString())) {
Log.v(TAG, " -> PBAP_PSE UUID in result.");
int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
Assert.assertEquals(0, status); /* BT_STATUS_SUCCESS == 0 - but status is not documented... */
Log.v(TAG, " -> status: "+status);
SdpPseRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
Assert.assertNotNull(record);
Log.v(TAG, " -> Record: " + record);
/* As the normal profiles are also running, we filter out these records */
if(record.getServiceName().equals(SdpManagerTest.SDP_SERVER_NAME)) {
Assert.assertEquals(((long)record.getSupportedFeatures())&0xffffffffL, SdpManagerTest.SDP_FEATURES);
Assert.assertEquals(((long)record.getSupportedRepositories())&0xffffffffL, SdpManagerTest.SDP_REPOS);
Assert.assertEquals(record.getProfileVersion(), SdpManagerTest.SDP_VERSION);
Assert.assertEquals(record.getServiceName(), SdpManagerTest.SDP_SERVER_NAME);
int rfcommChannel = record.getRfcommChannelNumber();
int l2capPsm = record.getL2capPsm();
/* We set RFCOMM-channel to record_id and the l2cap PSM to iteration*record_id */
Assert.assertEquals(mOperationIndex+rfcommChannel,l2capPsm);
mLatch.countDown();
} else {
Log.i(TAG, "Wrong service name (" + record.getServiceName()
+ ") received, still waiting...");
}
} else if(hasOppServer && uuid.toString().equals(BluetoothUuid.ObexObjectPush.toString())) {
Log.v(TAG, " -> OPP Server UUID in result.");
int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
Assert.assertEquals(0, status); /* BT_STATUS_SUCCESS == 0 - but status is not documented... */
Log.v(TAG, " -> status: "+status);
SdpOppOpsRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
Assert.assertNotNull(record);
Log.v(TAG, " -> Record: " + record);
/* As the normal profiles are also running, we filter out these records */
if(record.getServiceName().equals(SdpManagerTest.SDP_SERVER_NAME)) {
Assert.assertEquals(record.getProfileVersion(), SdpManagerTest.SDP_VERSION);
Assert.assertEquals(record.getServiceName(), SdpManagerTest.SDP_SERVER_NAME);
Assert.assertTrue(Arrays.equals(record.getFormatsList(),SdpManager.OPP_FORMAT_ALL));
int rfcommChannel = record.getRfcommChannel();
int l2capPsm = record.getL2capPsm();
/* We set RFCOMM-channel to record_id and the l2cap PSM to iteration*record_id */
Assert.assertEquals(mOperationIndex+rfcommChannel,l2capPsm);
mLatch.countDown();
} else {
Log.i(TAG, "Wrong service name (" + record.getServiceName()
+ ") received, still waiting...");
}
} else if (hasSapServer && uuid.toString().equals(BluetoothUuid.SAP.toString())) {
Log.v(TAG, " -> SAP Server UUID in result.");
int status = intent.getIntExtra(BluetoothDevice.EXTRA_SDP_SEARCH_STATUS, -1);
Assert.assertEquals(AbstractionLayer.BT_STATUS_SUCCESS, status); /* BT_STATUS_SUCCESS == 0 - but status is not documented... */
Log.v(TAG, " -> status: "+status);
SdpSapsRecord record = intent.getParcelableExtra(BluetoothDevice.EXTRA_SDP_RECORD);
Assert.assertNotNull(record);
Log.v(TAG, " -> Record: " + record);
/* As the normal profiles are also running, we filter out these records */
if (record.getServiceName().equals(SdpManagerTest.SDP_SERVER_NAME)) {
Assert.assertEquals(record.getProfileVersion(), SdpManagerTest.SDP_VERSION);
Assert.assertEquals(record.getServiceName(), SdpManagerTest.SDP_SERVER_NAME);
int rfcommChannel = record.getRfcommCannelNumber();
/* We set RFCOMM-channel to record_id and the l2cap PSM to
* iteration*record_id.
* As SAP does not carry a L2CAP PSM, we cannot validate the RFCOMM value
Assert.assertEquals(mOperationIndex+rfcommChannel, l2capPsm); */
mLatch.countDown();
} else {
Log.i(TAG, "Wrong service name (" + record.getServiceName()
+ ") received, still waiting...");
}
} else {
Log.i(TAG, "Wrong UUID received, still waiting...");
}
} else {
Assert.fail("Unexpected intent received???");
}
}
};
private void searchAwaitAndValidate(final String[] uuids, BluetoothDevice serverDevice, int count) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_SDP_RECORD);
final CountDownLatch latch = new CountDownLatch(count);
SdpBroadcastReceiver broadcastReceiver = new SdpBroadcastReceiver(uuids, latch);
// Register receiver
mContext.registerReceiver(broadcastReceiver, filter);
// Initiate searches
for(String uuid : uuids) {
if(uuid.toString().equals(BluetoothUuid.MAS.toString()))
serverDevice.sdpSearch(BluetoothUuid.MAS);
if(uuid.toString().equals(BluetoothUuid.MNS.toString()))
serverDevice.sdpSearch(BluetoothUuid.MNS);
if(uuid.toString().equals(BluetoothUuid.PBAP_PSE.toString()))
serverDevice.sdpSearch(BluetoothUuid.PBAP_PSE);
if(uuid.toString().equals(BluetoothUuid.ObexObjectPush.toString()))
serverDevice.sdpSearch(BluetoothUuid.ObexObjectPush);
if(uuid.toString().equals(BluetoothUuid.SAP.toString()))
serverDevice.sdpSearch(BluetoothUuid.SAP);
}
// Await results
boolean waiting = true;
while(waiting == true) {
try {
Log.i(TAG, "SDP Search requested - awaiting result...");
latch.await();
Log.i(TAG, "SDP Search reresult received - continueing.");
waiting = false;
} catch (InterruptedException e) {
Log.w(TAG, "Interrupted witle waiting - keep waiting.", e);
waiting = true;
}
}
mContext.unregisterReceiver(broadcastReceiver);
}
}