| package com.android.bluetooth.tests; |
| |
| 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; |
| 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; |
| |
| /** |
| * 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); |
| } |
| |
| } |