summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorkschulz <k.schulz@samsung.com>2015-03-17 11:47:46 +0100
committerAndre Eisenbach <eisenbach@google.com>2015-04-10 19:43:37 -0700
commit5a60e47497f21f64e6d79420dc4c56c1907df22a (patch)
tree68a80ce2c49692ab9b50204ba8ee8a6aa238df02 /tests
parent0dcecb2cfd921916ed586183d64ec9fd250a6e4c (diff)
downloadandroid_packages_apps_Bluetooth-5a60e47497f21f64e6d79420dc4c56c1907df22a.tar.gz
android_packages_apps_Bluetooth-5a60e47497f21f64e6d79420dc4c56c1907df22a.tar.bz2
android_packages_apps_Bluetooth-5a60e47497f21f64e6d79420dc4c56c1907df22a.zip
Update to Bluetooth MAP 1.2 (server)
- Change folder name lookup to a map Replaced the arrays used to convert mailbox ID/msg type to a folder name with a static map. This is to avoid null pointer exception for unknown values, and to catch any changes in the ID/type values at compile time in stead of runtime. Bug-id:16874441 - Added Instance Information support and Extended Event support. Still missing integration wiht SDP MAP feature bit mask support - Adding Abstract implementation to support conversations - added IM account handling, IM type definition, Application paramenters. - addedgetConversactionList functionality - added method to strip encoding in headers - Fixed messagelist showing both email address and name in the name fields. - Fixed Index out of bounds exception was hit when the subject contained invalid chars. - Added functionality to support the getConversationListReq Works for SMS/MMS, Email and IM For Email/IM it depends on the convoContact table in the contract. For SMS/MMS it uses the contact number+ name if available in contact database. - Added new parameters to msgListing also in contract class - Added Test framework for "near system level" tests Currently only includes an entry point for single device tests. - Added support for setOwnerStatus - Added support for vcard type X-BT-UID - Introduced type SignedLongLong to handle 128 bit values which needs to be handled as hex-strings. - Added convocontact notification events for IM - Added support for IM getMessage - Added setEventFilter function. - Added event filtering before enquing an event to be send. - Added selective observers, depending on the active filter. - Fixed timestamp to be from seconds to seconds (not from milisec) - Fixed version number in bMessage if remote featurebit is set for v 1.1 - Added content encoding to QP for text that are not USACII - Corrected the addresses in to/from for IM messages - Added btuid and btuci to vcard - Fixed (some) longlines - Added extendedData support (empty when sending, just logging when receiving) - Fixed Email folderName compairison changed to ignore case - Fixed problem with names containing "null" - BluetoothMapbMessageMms changed to BluetoothMapbMessageMime - Fixrf addOriginator in getMessage request - Add missing subjects in events for SMS - Don't send ReadStatusChanged when pushing a message - Temp way of adding names/uci to IM msg listing - Added messageHandle filtering in msgListing - Convolisting parameter mask support - Added support for using handle when filtering in root folder during msgLising - Added subject to event in sms - Fixed so attribute_mime_type is only sent when parameter is requested - Fixed feature bit check to messageListing version - Fixed leaking cursors - Added support for database identifier - Added folder and conversation version counters Change-Id: I4d2954b795aa7ed2a41dd034384da30f240b518f
Diffstat (limited to 'tests')
-rwxr-xr-xtests/Android.mk2
-rwxr-xr-xtests/AndroidManifest.xml1
-rw-r--r--tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java909
-rw-r--r--tests/src/com/android/bluetooth/tests/BluetoothMapIMContentTest.java171
-rw-r--r--tests/src/com/android/bluetooth/tests/BluetoothMapUtilsTest.java116
-rwxr-xr-xtests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java115
-rw-r--r--tests/src/com/android/bluetooth/tests/BluetoothTestUtils.java54
-rw-r--r--tests/src/com/android/bluetooth/tests/ISeqStepAction.java13
-rw-r--r--tests/src/com/android/bluetooth/tests/ISeqStepValidator.java15
-rw-r--r--tests/src/com/android/bluetooth/tests/ITestSequenceBuilder.java11
-rw-r--r--tests/src/com/android/bluetooth/tests/ITestSequenceConfigurator.java17
-rw-r--r--tests/src/com/android/bluetooth/tests/MapObexLevelTest.java286
-rw-r--r--tests/src/com/android/bluetooth/tests/MapObexTestServer.java188
-rw-r--r--tests/src/com/android/bluetooth/tests/MapStepsConvo.java240
-rw-r--r--tests/src/com/android/bluetooth/tests/MapStepsFolder.java159
-rw-r--r--tests/src/com/android/bluetooth/tests/MapTestData.java286
-rw-r--r--tests/src/com/android/bluetooth/tests/MockMasInstance.java30
-rw-r--r--tests/src/com/android/bluetooth/tests/ObexPipeTransport.java17
-rw-r--r--tests/src/com/android/bluetooth/tests/ObexTest.java566
-rw-r--r--tests/src/com/android/bluetooth/tests/ObexTestServer.java10
-rw-r--r--tests/src/com/android/bluetooth/tests/SdpManagerTest.java14
-rw-r--r--tests/src/com/android/bluetooth/tests/SdpManagerTestServer.java19
-rw-r--r--tests/src/com/android/bluetooth/tests/SeqStep.java88
-rw-r--r--tests/src/com/android/bluetooth/tests/TestSequencer.java284
24 files changed, 3110 insertions, 501 deletions
diff --git a/tests/Android.mk b/tests/Android.mk
index ca30b0848..612cb990e 100755
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -5,7 +5,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_CERTIFICATE := platform
-LOCAL_JAVA_LIBRARIES := javax.obex android.test.runner
+LOCAL_JAVA_LIBRARIES := javax.obex android.test.runner telephony-common mms-common
LOCAL_STATIC_JAVA_LIBRARIES := com.android.emailcommon
# Include all test java files.
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 657c85840..cf128db84 100755
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java
index 9e318c63d..15e1bdca8 100644
--- a/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapContentTest.java
@@ -1,102 +1,887 @@
package com.android.bluetooth.tests;
-import android.test.AndroidTestCase;
-import android.util.Log;
-import android.database.Cursor;
-import android.content.Context;
-import android.content.ContentResolver;
-
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.LinkedHashMap;
-import com.android.bluetooth.map.BluetoothMapContent;
-import com.android.bluetooth.map.BluetoothMapContentObserver;
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.ParcelFileDescriptor;
+import android.provider.BaseColumns;
+import android.provider.Telephony.Mms;
+import android.provider.Telephony.MmsSms;
+import android.provider.Telephony.Threads;
+import android.test.AndroidTestCase;
+import android.util.Log;
-import com.android.emailcommon.provider.EmailContent;
-import com.android.emailcommon.provider.EmailContent.Message;
-import com.android.emailcommon.provider.EmailContent.MessageColumns;
-import com.android.emailcommon.provider.EmailContent.SyncColumns;
+import com.android.bluetooth.map.BluetoothMapMasInstance;
+import com.android.bluetooth.map.BluetoothMapAccountItem;
+import com.android.bluetooth.map.BluetoothMapAccountLoader;
+import com.android.bluetooth.map.BluetoothMapAppParams;
+import com.android.bluetooth.map.BluetoothMapContent;
+import com.android.bluetooth.map.BluetoothMapFolderElement;
+import com.android.bluetooth.map.BluetoothMapMessageListing;
+import com.android.bluetooth.map.BluetoothMapUtils;
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
+import com.android.bluetooth.map.MapContact;
+import com.android.bluetooth.map.SmsMmsContacts;
+import com.android.bluetooth.mapapi.BluetoothMapContract;
+@TargetApi(19)
public class BluetoothMapContentTest extends AndroidTestCase {
+
private static final String TAG = "BluetoothMapContentTest";
private static final boolean D = true;
- private static final boolean V = true;
private Context mContext;
private ContentResolver mResolver;
+ private SmsMmsContacts mContacts = new SmsMmsContacts();
+
+ private BluetoothMapFolderElement mCurrentFolder;
+ private BluetoothMapAccountItem mAccount = null;
+
+ private static final int MAS_ID = 0;
+ private static final int REMOTE_FEATURE_MASK = 0x07FFFFFF;
+ private static final BluetoothMapMasInstance mMasInstance =
+ new MockMasInstance(MAS_ID, REMOTE_FEATURE_MASK);
+
- static final String[] EMAIL_PROJECTION = new String[] {
- EmailContent.RECORD_ID,
- MessageColumns.DISPLAY_NAME, MessageColumns.TIMESTAMP,
- MessageColumns.SUBJECT, MessageColumns.FLAG_READ,
- MessageColumns.FLAG_ATTACHMENT, MessageColumns.FLAGS,
- SyncColumns.SERVER_ID, MessageColumns.DRAFT_INFO,
- MessageColumns.MESSAGE_ID, MessageColumns.MAILBOX_KEY,
- MessageColumns.ACCOUNT_KEY, MessageColumns.FROM_LIST,
- MessageColumns.TO_LIST, MessageColumns.CC_LIST,
- MessageColumns.BCC_LIST, MessageColumns.REPLY_TO_LIST,
- SyncColumns.SERVER_TIMESTAMP, MessageColumns.MEETING_INFO,
- MessageColumns.SNIPPET, MessageColumns.PROTOCOL_SEARCH_INFO,
- MessageColumns.THREAD_TOPIC
+ private Uri mEmailUri = null;
+ private Uri mEmailMessagesUri = null;
+ private Uri mEmailFolderUri = null;
+ private Uri mEmailAccountUri = null;
+
+ static final String[] EMAIL_ACCOUNT_PROJECTION = new String[] {
+ BluetoothMapContract.MessageColumns.FOLDER_ID,
+ BluetoothMapContract.MessageColumns.ACCOUNT_ID,
+ };
+
+ private void printAccountInfo(Cursor c) {
+ if (D) Log.d(TAG, BluetoothMapContract.MessageColumns.ACCOUNT_ID + " : " +
+ c.getInt(c.getColumnIndex(BluetoothMapContract.MessageColumns.ACCOUNT_ID)) );
+ }
+
+ static final String[] BT_MESSAGE_ID_PROJECTION = new String[] {
+ BluetoothMapContract.MessageColumns._ID,
+ BluetoothMapContract.MessageColumns.DATE,
};
+ static final String[] BT_MESSAGE_PROJECTION = BluetoothMapContract.BT_MESSAGE_PROJECTION;
+
+ static final String[] BT_ACCOUNT_PROJECTION = BluetoothMapContract.BT_ACCOUNT_PROJECTION;
+
+ static final String[] BT_FOLDER_PROJECTION = BluetoothMapContract.BT_FOLDER_PROJECTION;
+
+ BluetoothMapAccountLoader loader;
+ LinkedHashMap<BluetoothMapAccountItem, ArrayList<BluetoothMapAccountItem>> mFullList;
+
+ public BluetoothMapContentTest() {
+ super();
+ }
+
+ private void initTestSetup(){
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+
+ // find enabled account
+ loader = new BluetoothMapAccountLoader(mContext);
+ mFullList = loader.parsePackages(false);
+ String accountId = getEnabledAccount();
+ Uri tmpEmailUri = Uri.parse("content://com.android.email.bluetoothprovider/");
+
+ mEmailUri = Uri.withAppendedPath(tmpEmailUri, accountId + "/");
+ mEmailMessagesUri = Uri.parse(mEmailUri + BluetoothMapContract.TABLE_MESSAGE);
+ mEmailFolderUri = Uri.parse(mEmailUri + BluetoothMapContract.TABLE_FOLDER);
+ mEmailAccountUri = Uri.parse(tmpEmailUri + BluetoothMapContract.TABLE_ACCOUNT);
+
+ buildFolderStructure();
+
+ }
+
+ public String getEnabledAccount(){
+ if(D)Log.d(TAG,"getEnabledAccountItems()\n");
+ String account = null;
+ for(BluetoothMapAccountItem app:mFullList.keySet()){
+ ArrayList<BluetoothMapAccountItem> accountList = mFullList.get(app);
+ for(BluetoothMapAccountItem acc: accountList){
+ mAccount = acc;
+ account = acc.getId();
+ break;
+ }
+ }
+ return account;
+ }
+
+ private void buildFolderStructure(){
+ mCurrentFolder = new BluetoothMapFolderElement("root", null); // This will be the root element
+ BluetoothMapFolderElement tmpFolder;
+ tmpFolder = mCurrentFolder.addFolder("telecom"); // root/telecom
+ tmpFolder = tmpFolder.addFolder("msg"); // root/telecom/msg
+ if(mEmailFolderUri != null) {
+ addEmailFolders(tmpFolder);
+ }
+ }
+
+ private void addEmailFolders(BluetoothMapFolderElement parentFolder) {
+ BluetoothMapFolderElement newFolder;
+ String where = BluetoothMapContract.FolderColumns.PARENT_FOLDER_ID +
+ " = " + parentFolder.getFolderId();
+ Cursor c = mContext.getContentResolver().query(mEmailFolderUri,
+ BluetoothMapContract.BT_FOLDER_PROJECTION, where, null, null);
+ if (c != null) {
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ String name = c.getString(c.getColumnIndex(BluetoothMapContract.FolderColumns.NAME));
+ long id = c.getLong(c.getColumnIndex(BluetoothMapContract.FolderColumns._ID));
+ newFolder = parentFolder.addEmailFolder(name, id);
+ addEmailFolders(newFolder); // Use recursion to add any sub folders
+ }
+ c.close();
+ } else {
+ if (D) Log.d(TAG, "addEmailFolders(): no elements found");
+ }
+ }
+
+ private BluetoothMapFolderElement getInbox() {
+ BluetoothMapFolderElement tmpFolderElement = null;
+
+ tmpFolderElement = mCurrentFolder.getSubFolder("telecom");
+ tmpFolderElement = tmpFolderElement.getSubFolder("msg");
+ tmpFolderElement = tmpFolderElement.getSubFolder("inbox");
+ return tmpFolderElement;
+ }
+
+ private BluetoothMapFolderElement getOutbox() {
+ BluetoothMapFolderElement tmpFolderElement = null;
+
+ tmpFolderElement = mCurrentFolder.getSubFolder("telecom");
+ tmpFolderElement = tmpFolderElement.getSubFolder("msg");
+ tmpFolderElement = tmpFolderElement.getSubFolder("outbox");
+ return tmpFolderElement;
+ }
+
+
private String getDateTimeString(long timestamp) {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
Date date = new Date(timestamp);
return format.format(date); // Format to YYYYMMDDTHHMMSS local time
}
- private void printEmail(Cursor c) {
- if (D) Log.d(TAG, "printEmail " +
- c.getLong(c.getColumnIndex(EmailContent.RECORD_ID)) +
- "\n " + MessageColumns.DISPLAY_NAME + " : " + c.getString(c.getColumnIndex(MessageColumns.DISPLAY_NAME)) +
- "\n " + MessageColumns.TIMESTAMP + " : " + getDateTimeString(c.getLong(c.getColumnIndex(MessageColumns.TIMESTAMP))) +
- "\n " + MessageColumns.SUBJECT + " : " + c.getString(c.getColumnIndex(MessageColumns.SUBJECT)) +
- "\n " + MessageColumns.FLAG_READ + " : " + c.getString(c.getColumnIndex(MessageColumns.FLAG_READ)) +
- "\n " + MessageColumns.FLAG_ATTACHMENT + " : " + c.getInt(c.getColumnIndex(MessageColumns.FLAG_ATTACHMENT)) +
- "\n " + MessageColumns.FLAGS + " : " + c.getInt(c.getColumnIndex(MessageColumns.FLAGS)) +
- "\n " + SyncColumns.SERVER_ID + " : " + c.getInt(c.getColumnIndex(SyncColumns.SERVER_ID)) +
- "\n " + MessageColumns.DRAFT_INFO + " : " + c.getInt(c.getColumnIndex(MessageColumns.DRAFT_INFO)) +
- "\n " + MessageColumns.MESSAGE_ID + " : " + c.getInt(c.getColumnIndex(MessageColumns.MESSAGE_ID)) +
- "\n " + MessageColumns.MAILBOX_KEY + " : " + c.getInt(c.getColumnIndex(MessageColumns.MAILBOX_KEY)) +
- "\n " + MessageColumns.ACCOUNT_KEY + " : " + c.getInt(c.getColumnIndex(MessageColumns.ACCOUNT_KEY)) +
- "\n " + MessageColumns.FROM_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.FROM_LIST)) +
- "\n " + MessageColumns.TO_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.TO_LIST)) +
- "\n " + MessageColumns.CC_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.CC_LIST)) +
- "\n " + MessageColumns.BCC_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.BCC_LIST)) +
- "\n " + MessageColumns.REPLY_TO_LIST + " : " + c.getString(c.getColumnIndex(MessageColumns.REPLY_TO_LIST)) +
- "\n " + SyncColumns.SERVER_TIMESTAMP + " : " + getDateTimeString(c.getLong(c.getColumnIndex(SyncColumns.SERVER_TIMESTAMP))) +
- "\n " + MessageColumns.MEETING_INFO + " : " + c.getString(c.getColumnIndex(MessageColumns.MEETING_INFO)) +
- "\n " + MessageColumns.SNIPPET + " : " + c.getString(c.getColumnIndex(MessageColumns.SNIPPET)) +
- "\n " + MessageColumns.PROTOCOL_SEARCH_INFO + " : " + c.getString(c.getColumnIndex(MessageColumns.PROTOCOL_SEARCH_INFO)) +
- "\n " + MessageColumns.THREAD_TOPIC + " : " + c.getString(c.getColumnIndex(MessageColumns.THREAD_TOPIC)));
- }
-
- public void dumpEmailMessageTable() {
- Log.d(TAG, "**** Dump of email message table ****");
-
- Cursor c = mResolver.query(Message.CONTENT_URI,
- EMAIL_PROJECTION, null, null, "_id DESC");
+ private void printCursor(Cursor c) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\nprintCursor:\n");
+ for(int i = 0; i < c.getColumnCount(); i++) {
+ if(c.getColumnName(i).equals(BluetoothMapContract.MessageColumns.DATE)){
+ sb.append(" ").append(c.getColumnName(i))
+ .append(" : ").append(getDateTimeString(c.getLong(i))).append("\n");
+ } else {
+ sb.append(" ").append(c.getColumnName(i))
+ .append(" : ").append(c.getString(i)).append("\n");
+ }
+ }
+ Log.d(TAG, sb.toString());
+ }
+
+ private void dumpMessageContent(Cursor c) {
+ long id = c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns._ID));
+ Uri uri = Uri.parse(mEmailMessagesUri + "/" + id
+ + "/" + BluetoothMapContract.FILE_MSG_NO_ATTACHMENTS);
+ FileInputStream is = null;
+ ParcelFileDescriptor fd = null;
+ int count;
+ try {
+ fd = mResolver.openFileDescriptor(uri, "r");
+ is = new FileInputStream(fd.getFileDescriptor());
+ byte[] buffer = new byte[1024];
+
+ while((count = is.read(buffer)) != -1) {
+ Log.d(TAG, new String(buffer,0, count));
+ }
+
+
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, e);
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ }
+ finally {
+ try {
+ if(is != null)
+ is.close();
+ } catch (IOException e) {}
+ try {
+ if(fd != null)
+ fd.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ /**
+ * Create a new message in the database outbox, based on the content of c.
+ * @param c
+ */
+ private void writeMessageContent(Cursor c) {
+ long id = c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns._ID));
+ Uri uri = Uri.parse(mEmailMessagesUri + "/" + id + "/"
+ + BluetoothMapContract.FILE_MSG_NO_ATTACHMENTS);
+ FileInputStream is = null;
+ ParcelFileDescriptor fd = null;
+ FileOutputStream os = null;
+ ParcelFileDescriptor fdOut = null;
+
+ ContentValues newMessage = new ContentValues();
+ BluetoothMapFolderElement outFolder = getOutbox();
+ newMessage.put(BluetoothMapContract.MessageColumns.FOLDER_ID, outFolder.getFolderId());
+ // Now insert the empty message into outbox (Maybe it should be draft first, and then a move?)
+ // TODO: Examine if we need to set some additional flags, e.g. visable?
+ Uri uriOut = mResolver.insert(mEmailMessagesUri, newMessage);
+ int count;
+ try {
+ fd = mResolver.openFileDescriptor(uri, "r");
+ is = new FileInputStream(fd.getFileDescriptor());
+ fdOut = mResolver.openFileDescriptor(uri, "w");
+ os = new FileOutputStream(fdOut.getFileDescriptor());
+ byte[] buffer = new byte[1024];
+
+ while((count = is.read(buffer)) != -1) {
+ Log.d(TAG, new String(buffer,0, count));
+ os.write(buffer, 0, count);
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, e);
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ }
+ finally {
+ try {
+ if(is != null)
+ is.close();
+ } catch (IOException e) {}
+ try {
+ if(fd != null)
+ fd.close();
+ } catch (IOException e) {}
+ try {
+ if(os != null)
+ os.close();
+ } catch (IOException e) {}
+ try {
+ if(fdOut != null)
+ fdOut.close();
+ } catch (IOException e) {}
+ }
+ }
+
+ private void writeMessage(Cursor c) {
+ Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ if (c.moveToNext()) {
+ writeMessageContent(c);
+ }
+ c.close();
+ }
+
+
+ private void dumpCursor(Cursor c) {
+ Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printCursor(c);
+ }
+ c.close();
+ }
+
+ private void callBluetoothProvider() {
+ Log.d(TAG, "**** Test call into email provider ****");
+ int accountId = 0;
+ int mailboxId = 0;
+
+ Log.d(TAG, "contentUri = " + mEmailMessagesUri);
+
+ Cursor c = mResolver.query(mEmailMessagesUri, EMAIL_ACCOUNT_PROJECTION,
+ null, null, "_id DESC");
if (c != null) {
Log.d(TAG, "c.getCount() = " + c.getCount());
c.moveToPosition(-1);
while (c.moveToNext()) {
- printEmail(c);
+ printAccountInfo(c);
+ mailboxId = c.getInt(c.getColumnIndex(
+ BluetoothMapContract.MessageColumns.FOLDER_ID));
+ accountId = c.getInt(c.getColumnIndex(
+ BluetoothMapContract.MessageColumns.ACCOUNT_ID));
}
+ c.close();
} else {
Log.d(TAG, "query failed");
- c.close();
}
+
+ final Bundle extras = new Bundle(2);
+ /* TODO: find mailbox from DB */
+ extras.putLong(BluetoothMapContract.EXTRA_UPDATE_FOLDER_ID, mailboxId);
+ extras.putLong(BluetoothMapContract.EXTRA_UPDATE_ACCOUNT_ID, accountId);
+ Bundle myBundle = mResolver.call(mEmailUri, BluetoothMapContract.METHOD_UPDATE_FOLDER,
+ null, extras);
}
- public BluetoothMapContentTest() {
- super();
+
+ public void testMsgListing() {
+ initTestSetup();
+ BluetoothMapContent mBtMapContent = new BluetoothMapContent(mContext, mAccount,
+ mMasInstance);
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ Log.d(TAG, "**** testMsgListing **** ");
+ BluetoothMapFolderElement fe = getInbox();
+
+ if (fe != null) {
+ if (D) Log.d(TAG, "folder name=" + fe.getName());
+
+ appParams.setFilterMessageType(0x0B);
+ appParams.setMaxListCount(1024);
+ appParams.setStartOffset(0);
+
+ BluetoothMapMessageListing msgListing = mBtMapContent.msgListing(fe, appParams);
+ int listCount = msgListing.getCount();
+ int msgListingSize = mBtMapContent.msgListingSize(fe, appParams);
+
+ if (listCount == msgListingSize) {
+ Log.d(TAG, "testMsgListing - " + listCount );
+ }
+ else {
+ Log.d(TAG, "testMsgListing - None");
+ }
+ }
+ else {
+ Log.d(TAG, "testMsgListing - failed ");
+ }
+
+ }
+
+ public void testMsgListingUnread() {
+ initTestSetup();
+ BluetoothMapContent mBtMapContent = new BluetoothMapContent(mContext, mAccount,
+ mMasInstance);
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ Log.d(TAG, "**** testMsgListingUnread **** ");
+ BluetoothMapFolderElement fe = getInbox();
+
+ if (fe != null) {
+
+ appParams.setFilterReadStatus(0x01);
+ appParams.setFilterMessageType(0x0B);
+ appParams.setMaxListCount(1024);
+ appParams.setStartOffset(0);
+
+ BluetoothMapMessageListing msgListing = mBtMapContent.msgListing(fe, appParams);
+
+ int listCount = msgListing.getCount();
+ if (msgListing.getCount() > 0) {
+ Log.d(TAG, "testMsgListingUnread - " + listCount );
+ }
+ else {
+ Log.d(TAG, "testMsgListingUnread - None");
+ }
+ }
+ else {
+ Log.d(TAG, "testMsgListingUnread - getInbox failed ");
+ }
+ }
+
+ public void testMsgListingWithOriginator() {
+ initTestSetup();
+ BluetoothMapContent mBtMapContent = new BluetoothMapContent(mContext, mAccount,
+ mMasInstance);
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ Log.d(TAG, "**** testMsgListingUnread **** ");
+ BluetoothMapFolderElement fe = getInbox();
+
+ if (fe != null) {
+
+ appParams.setFilterOriginator("*scsc.*");
+ appParams.setFilterMessageType(0x0B);
+ appParams.setMaxListCount(1024);
+ appParams.setStartOffset(0);
+
+ BluetoothMapMessageListing msgListing = mBtMapContent.msgListing(fe, appParams);
+
+ int listCount = msgListing.getCount();
+ if (msgListing.getCount() > 0) {
+ Log.d(TAG, "testMsgListingWithOriginator - " + listCount );
+ }
+ else {
+ Log.d(TAG, "testMsgListingWithOriginator - None");
+ }
+ } else {
+ Log.d(TAG, "testMsgListingWithOriginator - getInbox failed ");
+ }
+ }
+
+ public void testGetMessages() {
+ initTestSetup();
+ BluetoothMapContent mBtMapContent = new BluetoothMapContent(mContext, mAccount,
+ mMasInstance);
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ Log.d(TAG, "**** testGetMessages **** ");
+ BluetoothMapFolderElement fe = getInbox();
+
+ if (fe != null) {
+ appParams.setAttachment(0);
+ appParams.setCharset(BluetoothMapContent.MAP_MESSAGE_CHARSET_UTF8);
+
+ //get message handles
+ Cursor c = mResolver.query(mEmailMessagesUri, BT_MESSAGE_ID_PROJECTION,
+ null, null, "_id DESC");
+ if (c != null) {
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ Long id = c.getLong(c.getColumnIndex(BluetoothMapContract.MessageColumns._ID));
+ String handle = BluetoothMapUtils.getMapHandle(id, TYPE.EMAIL);
+ try {
+ // getMessage
+ byte[] bytes = mBtMapContent.getMessage(handle, appParams, fe, "1.1");
+ Log.d(TAG, "testGetMessages id=" + id + ", handle=" + handle +
+ ", length=" + bytes.length );
+ String testPrint = new String(bytes);
+ Log.d(TAG, "testGetMessage (only dump first part):\n" + testPrint );
+ } catch (UnsupportedEncodingException e) {
+ Log.w(TAG, e);
+ } finally {
+
+ }
+ }
+ } else {
+ Log.d(TAG, "testGetMessages - no cursor ");
+ }
+ } else {
+ Log.d(TAG, "testGetMessages - getInbox failed ");
+ }
+
+ }
+
+ public void testDumpAccounts() {
+ initTestSetup();
+ Log.d(TAG, "**** testDumpAccounts **** \n from: " + mEmailAccountUri.toString());
+ Cursor c = mResolver.query(mEmailAccountUri, BT_ACCOUNT_PROJECTION, null, null, "_id DESC");
+ if (c != null) {
+ dumpCursor(c);
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ Log.w(TAG, "testDumpAccounts(): ThreadId: " + Thread.currentThread().getId());
+
+ }
+
+ public void testAccountUpdate() {
+ initTestSetup();
+ Log.d(TAG, "**** testAccountUpdate **** \n of: " + mEmailAccountUri.toString());
+ Cursor c = mResolver.query(mEmailAccountUri, BT_ACCOUNT_PROJECTION, null, null, "_id DESC");
+
+ if (c != null) {
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printCursor(c);
+ Long id = c.getLong(c.getColumnIndex(BluetoothMapContract.AccountColumns._ID));
+ int exposeFlag = c.getInt(
+ c.getColumnIndex(BluetoothMapContract.AccountColumns.FLAG_EXPOSE));
+ String where = BluetoothMapContract.AccountColumns._ID + " = " + id;
+ ContentValues values = new ContentValues();
+ if(exposeFlag == 1) {
+ values.put(BluetoothMapContract.AccountColumns.FLAG_EXPOSE, (int) 0);
+ } else {
+ values.put(BluetoothMapContract.AccountColumns.FLAG_EXPOSE, (int) 1);
+ }
+ Log.i(TAG, "Calling update() with selection: " + where +
+ "values(exposeFlag): " +
+ values.getAsInteger(BluetoothMapContract.AccountColumns.FLAG_EXPOSE));
+ mResolver.update(mEmailAccountUri, values, where, null);
+ }
+ c.close();
+ }
+
}
public void testDumpMessages() {
+ initTestSetup();
+
+ if (D) Log.d(TAG, "**** testDumpMessages **** \n uri=" + mEmailMessagesUri.toString());
+ BluetoothMapFolderElement fe = getInbox();
+ if (fe != null)
+ {
+ String where ="";
+ //where = BluetoothMapContract.MessageColumns.FOLDER_ID + " = " + fe.getEmailFolderId();
+ Cursor c = mResolver.query(mEmailMessagesUri, BT_MESSAGE_PROJECTION,
+ where, null, "_id DESC");
+ if (c != null) {
+ dumpCursor(c);
+ } else {
+ if (D) Log.d(TAG, "query failed");
+ }
+ if (D) Log.w(TAG, "dumpMessage(): ThreadId: " + Thread.currentThread().getId());
+ } else {
+ if (D) Log.w(TAG, "dumpMessage(): ThreadId: " + Thread.currentThread().getId());
+ }
+ }
+
+ public void testDumpMessageContent() {
+ initTestSetup();
+
+ Log.d(TAG, "**** testDumpMessageContent **** from: " + mEmailMessagesUri.toString());
+// BluetoothMapFolderElement fe = getInbox();
+// String where = BluetoothMapContract.MessageColumns.FOLDER_ID + " = " + fe.getEmailFolderId();
+// where += " AND " + BluetoothMapContract.MessageColumns.FLAG_HIGH_PRIORITY + " = 0";
+
+ Cursor c = mResolver.query(mEmailMessagesUri, BT_MESSAGE_PROJECTION, null, null, "_id DESC");
+ if (c != null && c.moveToNext()) {
+ dumpMessageContent(c);
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ Log.w(TAG, "dumpMessage(): ThreadId: " + Thread.currentThread().getId());
+ }
+
+ public void testWriteMessageContent() {
+ initTestSetup();
+ Log.d(TAG, "**** testWriteMessageContent **** from: " + mEmailMessagesUri.toString());
+ BluetoothMapFolderElement fe = getInbox();
+ String where = BluetoothMapContract.MessageColumns.FOLDER_ID + " = " + fe.getFolderId();
+// where += " AND " + BluetoothMapContract.MessageColumns.HIGH_PRIORITY + " = 0";
+ Cursor c = mResolver.query(mEmailMessagesUri, BT_MESSAGE_PROJECTION, where, null, "_id DESC");
+ if (c != null) {
+ writeMessage(c);
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ Log.w(TAG, "writeMessage(): ThreadId: " + Thread.currentThread().getId());
+ }
+
+ /*
+ * Handle test cases
+ */
+ private static final long HANDLE_TYPE_SMS_CDMA_MASK = (((long)0x1)<<60);
+
+ public void testHandle() {
+ String handleStr = null;
+ Debug.startMethodTracing("str_format");
+ for(long i = 0; i < 10000; i++) {
+ handleStr = String.format("%016X",(i | HANDLE_TYPE_SMS_CDMA_MASK));
+ }
+ Debug.stopMethodTracing();
+ Debug.startMethodTracing("getHandleString");
+ for(long i = 0; i < 10000; i++) {
+ handleStr = BluetoothMapUtils.getLongAsString(i | HANDLE_TYPE_SMS_CDMA_MASK);
+ }
+ Debug.stopMethodTracing();
+ }
+
+ /*
+ * Folder test cases
+ */
+
+ public void testDumpEmailFolders() {
+ initTestSetup();
+ Debug.startMethodTracing();
+ String where = null;
+ Cursor c = mResolver.query(mEmailFolderUri, BT_FOLDER_PROJECTION, where, null, "_id DESC");
+ if (c != null) {
+ dumpCursor(c);
+ c.close();
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ Debug.stopMethodTracing();
+ }
+
+ public void testFolderPath() {
+ initTestSetup();
+ Log.d(TAG, "**** testFolderPath **** ");
+ BluetoothMapFolderElement fe = getInbox();
+ BluetoothMapFolderElement folder = fe.getFolderById(fe.getFolderId());
+ if(folder == null) {
+ Log.d(TAG, "**** testFolderPath unable to find the folder with id: " +
+ fe.getFolderId());
+ }
+ else {
+ Log.d(TAG, "**** testFolderPath found the folder with id: " +
+ fe.getFolderId() + "\nFull path: " +
+ folder.getFullPath());
+ }
+ }
+
+ public void testFolderElement() {
+ Log.d(TAG, "**** testFolderElement **** ");
+ BluetoothMapFolderElement fe = new BluetoothMapFolderElement("root", null);
+ fe = fe.addEmailFolder("MsG", 1);
+ fe.addEmailFolder("Outbox", 100);
+ fe.addEmailFolder("Sent", 200);
+ BluetoothMapFolderElement inbox = fe.addEmailFolder("Inbox", 300);
+ fe.addEmailFolder("Draft", 400);
+ fe.addEmailFolder("Deleted", 500);
+ inbox.addEmailFolder("keep", 301);
+ inbox.addEmailFolder("private", 302);
+ inbox.addEmailFolder("junk", 303);
+
+ BluetoothMapFolderElement folder = fe.getFolderById(400);
+ assertEquals("draft", folder.getName());
+ assertEquals("private", fe.getFolderById(302).getName());
+ assertEquals("junk", fe.getRoot().getFolderById(303).getName());
+ assertEquals("msg/inbox/keep", fe.getFolderById(301).getFullPath());
+ }
+
+ /*
+ * SMS test cases
+ */
+ public void testAddSmsEntries() {
+ int count = 1000;
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ ContentValues values[] = new ContentValues[count];
+ long date = System.currentTimeMillis();
+ Log.i(TAG, "Preparing messages...");
+ for (int x=0;x<count;x++){
+ //if (D) Log.d(TAG, "*** Adding dummy sms #"+x);
+
+ ContentValues item = new ContentValues(4);
+ item.put("address", "1234");
+ item.put("body", "test message "+x);
+ item.put("date", date);
+ item.put("read", "0");
+
+ values[x] = item;
+ // Uri mUri = mResolver.insert(Uri.parse("content://sms"), item);
+ }
+ Log.i(TAG, "Starting bulk insert...");
+ mResolver.bulkInsert(Uri.parse("content://sms"), values);
+ Log.i(TAG, "Bulk insert done.");
+ }
+
+ public void testAddSms() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ if (D) Log.d(TAG, "*** Adding dummy sms #");
+
+ ContentValues item = new ContentValues();
+ item.put("address", "1234");
+ item.put("body", "test message");
+ item.put("date", System.currentTimeMillis());
+ item.put("read", "0");
+
+ Uri mUri = mResolver.insert(Uri.parse("content://sms"), item);
+ }
+
+ public void testServiceSms() {
mContext = this.getContext();
mResolver = mContext.getContentResolver();
- dumpEmailMessageTable();
+ if (D) Log.d(TAG, "*** Adding dummy sms #");
+
+ ContentValues item = new ContentValues();
+ item.put("address", "C-Bonde");
+ item.put("body", "test message");
+ item.put("date", System.currentTimeMillis());
+ item.put("read", "0");
+
+ Uri mUri = mResolver.insert(Uri.parse("content://sms"), item);
+ }
+
+ /*
+ * MMS content test cases
+ */
+ public static final int MMS_FROM = 0x89;
+ public static final int MMS_TO = 0x97;
+ public static final int MMS_BCC = 0x81;
+ public static final int MMS_CC = 0x82;
+
+ private void printMmsAddr(long id) {
+ final String[] projection = null;
+ String selection = new String("msg_id=" + id);
+ String uriStr = String.format("content://mms/%d/addr", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(uriAddress, projection, selection, null, null);
+
+ if (c.moveToFirst()) {
+ do {
+ String add = c.getString(c.getColumnIndex("address"));
+ Integer type = c.getInt(c.getColumnIndex("type"));
+ if (type == MMS_TO) {
+ if (D) Log.d(TAG, " recipient: " + add + " (type: " + type + ")");
+ } else if (type == MMS_FROM) {
+ if (D) Log.d(TAG, " originator: " + add + " (type: " + type + ")");
+ } else {
+ if (D) Log.d(TAG, " address other: " + add + " (type: " + type + ")");
+ }
+ printCursor(c);
+
+ } while(c.moveToNext());
+ }
+ }
+
+ private void printMmsPartImage(long partid) {
+ String uriStr = String.format("content://mms/part/%d", partid);
+ Uri uriAddress = Uri.parse(uriStr);
+ int ch;
+ StringBuffer sb = new StringBuffer("");
+ InputStream is = null;
+
+ try {
+ is = mResolver.openInputStream(uriAddress);
+
+ while ((ch = is.read()) != -1) {
+ sb.append((char)ch);
+ }
+ if (D) Log.d(TAG, sb.toString());
+
+ } catch (IOException e) {
+ // do nothing for now
+ e.printStackTrace();
+ }
+ }
+
+ private void printMmsParts(long id) {
+ final String[] projection = null;
+ String selection = new String("mid=" + id);
+ String uriStr = String.format("content://mms/%d/part", id);
+ Uri uriAddress = Uri.parse(uriStr);
+ Cursor c = mResolver.query(uriAddress, projection, selection, null, null);
+
+ if (c.moveToFirst()) {
+ int i = 0;
+ do {
+ if (D) Log.d(TAG, " part " + i++);
+ printCursor(c);
+
+ /* if (ct.equals("image/jpeg")) { */
+ /* printMmsPartImage(partid); */
+ /* } */
+ } while(c.moveToNext());
+ }
}
+
+ public void dumpMmsTable() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+
+ if (D) Log.d(TAG, "**** Dump of mms table ****");
+ Cursor c = mResolver.query(Mms.CONTENT_URI,
+ null, null, null, "_id DESC");
+ if (c != null) {
+ if (D) Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ Log.d(TAG,"Message:");
+ printCursor(c);
+ long id = c.getLong(c.getColumnIndex(BaseColumns._ID));
+ Log.d(TAG,"Address:");
+ printMmsAddr(id);
+ Log.d(TAG,"Parts:");
+ printMmsParts(id);
+ }
+ c.close();
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ }
+
+ /**
+ * This dumps the thread database.
+ * Interesting how useful this is.
+ * - DATE is described to be the creation date of the thread. But it actually
+ * contains the time-date of the last activity of the thread.
+ * - RECIPIENTS is a list of the contacts related to the thread. The number can
+ * be found for both MMS and SMS in the "canonical-addresses" table.
+ * - The READ column tells if the thread have been read. (read = 1: no unread messages)
+ * - The snippet is a small piece of text from the last message, and could be used as thread
+ * name. Please however note that if we do this, the version-counter should change each
+ * time a message is added to the thread. But since it changes the read attribute and
+ * last activity, it changes anyway.
+ * -
+ */
+
+
+ public void dumpThreadsTable() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ mContacts.clearCache();
+ Uri uri = Threads.CONTENT_URI.buildUpon().appendQueryParameter("simple", "true").build();
+
+ if (D) Log.d(TAG, "**** Dump of Threads table ****\nUri: " + uri);
+ Cursor c = mResolver.query(uri,
+ null, null, null, "_id DESC");
+ if (c != null) {
+ if (D) Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ Log.d(TAG,"Threads:");
+ printCursor(c);
+ String ids = c.getString(c.getColumnIndex(Threads.RECIPIENT_IDS));
+ Log.d(TAG,"Address:");
+ printAddresses(ids);
+/* Log.d(TAG,"Parts:");
+ printMmsParts(id);*/
+ }
+ c.close();
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ }
+
+ /**
+ * This test shows the content of the canonicalAddresses table.
+ * Conclusion:
+ * The _id column matches the id's from the RECIPIENT_IDS column
+ * in the Threads table, hence are to be used to map from an id to
+ * a phone number, which then can be matched to a contact.
+ */
+ public void dumpCanAddrTable() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ Uri uri = Uri.parse("content://mms-sms/canonical-addresses");
+ uri = MmsSms.CONTENT_URI.buildUpon().appendPath("canonical-addresses").build();
+ dumpUri(uri);
+ }
+
+ public void dumpUri(Uri uri) {
+ if (D) Log.d(TAG, "**** Dump of table ****\nUri: " + uri);
+ Cursor c = mResolver.query(uri, null, null, null, null);
+ if (c != null) {
+ if (D) Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ Log.d(TAG,"Entry: " + c.getPosition());
+ printCursor(c);
+ }
+ c.close();
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ }
+
+ private void printAddresses(String idsStr) {
+ String[] ids = idsStr.split(" ");
+ for (String id : ids) {
+ long longId;
+ try {
+ longId = Long.parseLong(id);
+ String addr = mContacts.getPhoneNumber(mResolver, longId);
+ MapContact contact = mContacts.getContactNameFromPhone(addr, mResolver);
+ Log.d(TAG, " id " + id + ": " + addr + " - " + contact.getName()
+ + " X-BT-UID: " + contact.getXBtUidString());
+ } catch (NumberFormatException ex) {
+ // skip this id
+ continue;
+ }
+ }
+ }
+
}
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapIMContentTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapIMContentTest.java
new file mode 100644
index 000000000..2d100e4a7
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapIMContentTest.java
@@ -0,0 +1,171 @@
+package com.android.bluetooth.tests;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.BaseColumns;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.android.bluetooth.mapapi.BluetoothMapContract;
+import com.android.bluetooth.mapapi.BluetoothMapContract.ConversationColumns;
+
+//import info.guardianproject.otr.app.im.provider.Imps;
+//import info.guardianproject.otr.app.im.provider.ImpsBluetoothProvider;
+
+public class BluetoothMapIMContentTest extends AndroidTestCase {
+ private static final String TAG = "BluetoothMapIMContentTest";
+
+ private static final boolean D = true;
+ private static final boolean V = true;
+
+ private Context mContext;
+ private ContentResolver mResolver;
+
+ private String getDateTimeString(long timestamp) {
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
+ Date date = new Date(timestamp);
+ return format.format(date); // Format to YYYYMMDDTHHMMSS local time
+ }
+
+ private void printCursor(Cursor c) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\nprintCursor:\n");
+ for(int i = 0; i < c.getColumnCount(); i++) {
+ if(c.getColumnName(i).equals(BluetoothMapContract.MessageColumns.DATE) ||
+ c.getColumnName(i).equals(BluetoothMapContract.ConversationColumns.LAST_THREAD_ACTIVITY) ||
+ c.getColumnName(i).equals(BluetoothMapContract.ChatStatusColumns.LAST_ACTIVE) ||
+ c.getColumnName(i).equals(BluetoothMapContract.PresenceColumns.LAST_ONLINE) ){
+ sb.append(" ").append(c.getColumnName(i)).append(" : ").append(getDateTimeString(c.getLong(i))).append("\n");
+ } else {
+ sb.append(" ").append(c.getColumnName(i)).append(" : ").append(c.getString(i)).append("\n");
+ }
+ }
+ Log.d(TAG, sb.toString());
+ }
+
+ private void dumpImMessageTable() {
+ Log.d(TAG, "**** Dump of im message table ****");
+
+ Cursor c = mResolver.query(
+ BluetoothMapContract.buildMessageUri("info.guardianproject.otr.app.im.provider.bluetoothprovider"),
+ BluetoothMapContract.BT_INSTANT_MESSAGE_PROJECTION, null, null, "_id DESC");
+ if (c != null) {
+ Log.d(TAG, "c.getCount() = " + c.getCount());
+ c.moveToPosition(-1);
+ while (c.moveToNext()) {
+ printCursor(c);
+ }
+ } else {
+ Log.d(TAG, "query failed");
+ c.close();
+ }
+
+ }
+
+ private void insertImMessage( ) {
+ Log.d(TAG, "**** Insert message in im message table ****");
+ ContentValues cv = new ContentValues();
+ cv.put(BluetoothMapContract.MessageColumns.BODY, "This is a test to insert a message");
+ cv.put(BluetoothMapContract.MessageColumns.DATE, System.currentTimeMillis());
+ cv.put(BluetoothMapContract.MessageColumns.THREAD_ID, 2);
+ Uri uri = BluetoothMapContract.buildMessageUri("info.guardianproject.otr.app.im.provider.bluetoothprovider");
+ Uri uriWithId = mResolver.insert(uri, cv);
+ if (uriWithId != null) {
+ Log.d(TAG, "uriWithId = " + uriWithId.toString());
+ } else {
+ Log.d(TAG, "query failed");
+ }
+
+ }
+
+ private void dumpImConversationTable() {
+ Log.d(TAG, "**** Dump of conversation message table ****");
+
+ Uri uri = BluetoothMapContract.buildConversationUri(
+ "info.guardianproject.otr.app.im.provider.bluetoothprovider", "1");
+ uri = uri.buildUpon().appendQueryParameter(BluetoothMapContract.FILTER_ORIGINATOR_SUBSTRING,
+ "asp").build();
+
+ Cursor convo = mResolver.query(
+ uri,
+ BluetoothMapContract.BT_CONVERSATION_PROJECTION, null, null,
+ null);
+
+ if (convo != null) {
+ Log.d(TAG, "c.getCount() = " + convo.getCount());
+
+ while(convo.moveToNext()) {
+ printCursor(convo);
+ }
+ convo.close();
+ } else {
+ Log.d(TAG, "query failed");
+ }
+ }
+
+
+ private void dumpImContactsTable() {
+ Log.d(TAG, "**** Dump of contacts message table ****");
+ Cursor cContact = mResolver.query(
+ BluetoothMapContract.buildConvoContactsUri("info.guardianproject.otr.app.im.provider.bluetoothprovider","1"),
+ BluetoothMapContract.BT_CONTACT_CHATSTATE_PRESENCE_PROJECTION, null, null, "_id DESC");
+
+ if (cContact != null && cContact.moveToFirst()) {
+ Log.d(TAG, "c.getCount() = " + cContact.getCount());
+ do {
+ printCursor(cContact);
+ } while(cContact.moveToNext());
+
+ } else {
+ Log.d(TAG, "query failed");
+ cContact.close();
+ }
+ }
+
+ private void dumpImAccountsTable() {
+ Log.d(TAG, "**** Dump of accounts table ****");
+ Cursor cContact = mResolver.query(
+ BluetoothMapContract.buildAccountUri("info.guardianproject.otr.app.im.provider.bluetoothprovider"),
+ BluetoothMapContract.BT_ACCOUNT_PROJECTION, null, null, "_id DESC");
+
+ if (cContact != null && cContact.moveToFirst()) {
+ Log.d(TAG, "c.getCount() = " + cContact.getCount());
+ do {
+ printCursor(cContact);
+ } while(cContact.moveToNext());
+
+ } else {
+ Log.d(TAG, "query failed");
+ cContact.close();
+ }
+ }
+
+
+ public BluetoothMapIMContentTest() {
+ super();
+ }
+
+ public void testDumpMessages() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ dumpImMessageTable();
+ dumpImConversationTable();
+ dumpImContactsTable();
+ dumpImAccountsTable();
+
+ insertImMessage();
+
+ }
+
+ public void testDumpConversations() {
+ mContext = this.getContext();
+ mResolver = mContext.getContentResolver();
+ dumpImConversationTable();
+ }
+} \ No newline at end of file
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapUtilsTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapUtilsTest.java
new file mode 100644
index 000000000..788b36f2a
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapUtilsTest.java
@@ -0,0 +1,116 @@
+
+package com.android.bluetooth.tests;
+
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.util.Base64;
+
+import java.io.UnsupportedEncodingException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import com.android.bluetooth.SignedLongLong;
+import com.android.bluetooth.map.BluetoothMapUtils;
+
+public class BluetoothMapUtilsTest extends AndroidTestCase {
+ private static final String TAG = "BluetoothMapUtilsTest";
+
+ private static final boolean D = true;
+ private static final boolean V = true;
+ private static final String encText1 = "=?UTF-8?b?w6bDuMOlw4bDmMOF?="; //æøåÆØÅ base64
+ private static final String encText2 = "=?UTF-8?B?w6bDuMOlw4bDmMOF?="; //æøåÆØÅ base64
+ private static final String encText3 = "=?UTF-8?q?=C3=A6=C3=B8=C3=A5=C3=86=C3=98=C3=85?="; //æøåÆØÅ QP
+ private static final String encText4 = "=?UTF-8?Q?=C3=A6=C3=B8=C3=A5=C3=86=C3=98=C3=85?="; //æøåÆØÅ QP
+ private static final String encText5 = "=?UTF-8?B?=C3=A6=C3=B8=C3=A5=C3=86=C3=98=C3=85?="; //QP in base64 string - should not compute
+ private static final String encText6 = "=?UTF-8?Q?w6bDuMOlw4bDmMOF?="; //æøåÆØÅ base64 in QP stirng - should not compute
+ private static final String encText7 = "this is a split =?UTF-8?Q?=C3=A6=C3=B8=C3=A5 ###123?= with more =?UTF-8?Q?=C3=A6=C3=B8=C3=A5 ###123?= inside"; // mix of QP and normal
+ private static final String encText8 = "this is a split =?UTF-8?B?w6bDuMOlICMjIzEyMw==?= with more =?UTF-8?Q?=C3=A6=C3=B8=C3=A5 ###123?= inside"; // mix of normal, QP and Base64
+ private static final String encText9 = "=?UTF-8?Q??=";
+ private static final String encText10 = "=?UTF-8?Q??=";
+ private static final String encText11 = "=?UTF-8?Q??=";
+
+ private static final String decText1 = "æøåÆØÅ";
+ private static final String decText2 = "æøåÆØÅ";
+ private static final String decText3 = "æøåÆØÅ";
+ private static final String decText4 = "æøåÆØÅ";
+ private static final String decText5 = encText5;
+ private static final String decText6 = "w6bDuMOlw4bDmMOF";
+ private static final String decText7 = "this is a split æøå ###123 with more æøå ###123 inside";
+ private static final String decText8 = "this is a split æøå ###123 with more æøå ###123 inside";
+
+ public BluetoothMapUtilsTest() {
+ super();
+
+ }
+
+
+ public void testEncoder(){
+ assertTrue(BluetoothMapUtils.stripEncoding(encText1).equals(decText1));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText2).equals(decText2));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText3).equals(decText3));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText4).equals(decText4));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText5).equals(decText5));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText6).equals(decText6));
+ Log.i(TAG,"##############################enc7:" +
+ BluetoothMapUtils.stripEncoding(encText7));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText7).equals(decText7));
+ assertTrue(BluetoothMapUtils.stripEncoding(encText8).equals(decText8));
+ }
+
+ public void testXBtUid() throws UnsupportedEncodingException {
+ {
+ SignedLongLong expected = new SignedLongLong(0x12345678L, 0x90abcdefL);
+ /* this will cause an exception, since the value is too big... */
+ SignedLongLong value;
+ value = SignedLongLong.fromString("90abcdef0000000012345678");
+ assertTrue("expected: " + expected + " value = " + value,
+ 0 == value.compareTo(expected));
+ assertEquals("expected: " + expected + " value = " + value,
+ expected.toHexString(), value.toHexString());
+ Log.i(TAG,"Succesfully compared : " + value);
+ }
+ {
+ SignedLongLong expected = new SignedLongLong(0x12345678L, 0xfedcba9890abcdefL);
+ /* this will cause an exception, since the value is too big... */
+ SignedLongLong value;
+ value = SignedLongLong.fromString("fedcba9890abcdef0000000012345678");
+ assertTrue("expected: " + expected + " value = " + value,
+ 0 == value.compareTo(expected));
+ assertEquals("expected: " + expected + " value = " + value,
+ expected.toHexString(), value.toHexString());
+ Log.i(TAG,"Succesfully compared : " + value);
+ }
+ {
+ SignedLongLong expected = new SignedLongLong(0x12345678L, 0);
+ SignedLongLong value = SignedLongLong.fromString("000012345678");
+ assertTrue("expected: " + expected + " value = " + value,
+ 0 == value.compareTo(expected));
+ assertEquals("expected: " + expected + " value = " + value,
+ expected.toHexString(), value.toHexString());
+ Log.i(TAG,"Succesfully compared : " + value);
+ }
+ {
+ SignedLongLong expected = new SignedLongLong(0x12345678L, 0);
+ SignedLongLong value = SignedLongLong.fromString("12345678");
+ assertTrue("expected: " + expected + " value = " + value,
+ 0 == value.compareTo(expected));
+ assertEquals("expected: " + expected + " value = " + value,
+ expected.toHexString(), value.toHexString());
+ Log.i(TAG,"Succesfully compared : " + value);
+ }
+ {
+ SignedLongLong expected = new SignedLongLong(0x123456789abcdef1L, 0x9L);
+ SignedLongLong value = SignedLongLong.fromString("0009123456789abcdef1");
+ assertTrue("expected: " + expected + " value = " + value,
+ 0 == value.compareTo(expected));
+ assertEquals("expected: " + expected + " value = " + value,
+ expected.toHexString(), value.toHexString());
+ Log.i(TAG,"Succesfully compared : " + value);
+ }
+ {
+ long expected = 0x123456789abcdefL;
+ long value = BluetoothMapUtils.getLongFromString(" 1234 5678 9abc-def");
+ assertTrue("expected: " + expected + " value = " + value, value == expected);
+ }
+ }
+}
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java b/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java
index 1fcec4e66..8724e9fb0 100755
--- a/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java
+++ b/tests/src/com/android/bluetooth/tests/BluetoothMapbMessageTest.java
@@ -8,22 +8,19 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
+import org.apache.http.message.BasicHeaderElement;
import org.apache.http.message.BasicHeaderValueFormatter;
-import android.preference.PreferenceFragment;
import android.test.AndroidTestCase;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
import com.android.bluetooth.map.BluetoothMapAppParams;
-import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.android.bluetooth.map.BluetoothMapSmsPdu;
+import com.android.bluetooth.map.BluetoothMapUtils;
+import com.android.bluetooth.map.BluetoothMapUtils.TYPE;
import com.android.bluetooth.map.BluetoothMapbMessage;
-import com.android.bluetooth.map.BluetoothMapbMessageMms;
+import com.android.bluetooth.map.BluetoothMapbMessageMime;
import com.android.bluetooth.map.BluetoothMapbMessageSms;
-import org.apache.http.message.BasicHeaderValueFormatter;
-import org.apache.http.message.BasicHeaderElement;
/***
*
@@ -58,6 +55,15 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
"EMAIL:casper@email.add\r\n" +
"EMAIL:bonde@email.add\r\n" +
"END:VCARD\r\n" +
+ "BEGIN:VCARD\r\n" +
+ "VERSION:3.0\r\n" +
+ "FN:Casper Bonde\r\n" +
+ "N:Bonde,Casper\r\n" +
+ "TEL:+4512345678\r\n" +
+ "TEL:+4587654321\r\n" +
+ "EMAIL:casper@email.add\r\n" +
+ "EMAIL:bonde@email.add\r\n" +
+ "END:VCARD\r\n" +
"BEGIN:BENV\r\n" +
"BEGIN:VCARD\r\n" +
"VERSION:3.0\r\n" +
@@ -68,6 +74,15 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
"EMAIL:casper@email.add\r\n" +
"EMAIL:bonde@email.add\r\n" +
"END:VCARD\r\n" +
+ "BEGIN:VCARD\r\n" +
+ "VERSION:3.0\r\n" +
+ "FN:Jens Hansen\r\n" +
+ "N:\r\n" +
+ "TEL:+4512345678\r\n" +
+ "TEL:+4587654321\r\n" +
+ "EMAIL:casper@email.add\r\n" +
+ "EMAIL:bonde@email.add\r\n" +
+ "END:VCARD\r\n" +
"BEGIN:BBODY\r\n" +
"CHARSET:UTF-8\r\n" +
"LENGTH:45\r\n" +
@@ -81,8 +96,10 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
String encoded;
String[] phone = {"+4512345678", "+4587654321"};
String[] email = {"casper@email.add", "bonde@email.add"};
- msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email);
- msg.addRecipient("", "Jens Hansen", phone, email);
+ msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email, null, null);
+ msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email, null, null);
+ msg.addRecipient("", "Jens Hansen", phone, email, null, null);
+ msg.addRecipient("", "Jens Hansen", phone, email, null, null);
msg.setFolder("inbox");
msg.setSmsBody("This is a short message");
msg.setStatus(false);
@@ -182,8 +199,8 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
String encoded;
String[] phone = {"00498912345678", "+4587654321"};
String[] email = {"casper@email.add", "bonde@email.add"};
- msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email);
- msg.addRecipient("", "Jens Hansen", phone, email);
+ msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email, null, null);
+ msg.addRecipient("", "Jens Hansen", phone, email, null, null);
msg.setFolder("inbox");
/* TODO: extract current time, and build the expected string */
msg.setSmsBodyPdus(BluetoothMapSmsPdu.getDeliverPdus("Let's go fishing!", "00498912345678", date.getTime()));
@@ -252,8 +269,8 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
String encoded;
String[] phone = {"00498912345678", "+4587654321"};
String[] email = {"casper@email.add", "bonde@email.add"};
- msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email);
- msg.addRecipient("", "Jens Hansen", phone, email);
+ msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email, null, null);
+ msg.addRecipient("", "Jens Hansen", phone, email, null, null);
msg.setFolder("outbox");
/* TODO: extract current time, and build the expected string */
msg.setSmsBodyPdus(BluetoothMapSmsPdu.getSubmitPdus("Let's go fishing!", "00498912345678"));
@@ -421,7 +438,7 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
* Test encoding of a simple MMS text message (UTF8). This validates most parameters.
*/
public void testMmsEncodeText() {
- BluetoothMapbMessageMms msg = new BluetoothMapbMessageMms();
+ BluetoothMapbMessageMime msg = new BluetoothMapbMessageMime ();
String str1 =
"BEGIN:BMSG\r\n" +
"VERSION:1.0\r\n" +
@@ -449,9 +466,16 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
"END:VCARD\r\n" +
"BEGIN:BBODY\r\n" +
"CHARSET:UTF-8\r\n" +
- "LENGTH:45\r\n" +
+ "LENGTH:184\r\n" +
"BEGIN:MSG\r\n" +
- "This is a short message\r\n" +
+ "From: \"Jørn Hansen\" <bonde@email.add>;\r\n" +
+ "To: \"Jørn Hansen\" <bonde@email.add>;\r\n" +
+ "Cc: Jens Hansen <bonde@email.add>;\r\n" +
+ "\r\n" +
+ "This is a short message\r\n" +
+ "\r\n" +
+ "<partNameimage>\r\n" +
+ "\r\n" +
"END:MSG\r\n" +
"END:BBODY\r\n" +
"END:BENV\r\n" +
@@ -460,14 +484,14 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
String encoded;
String[] phone = {"+4512345678", "+4587654321"};
String[] email = {"casper@email.add", "bonde@email.add"};
- msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email);
- msg.addRecipient("", "Jørn Hansen", phone, email);
+ msg.addOriginator("Bonde,Casper", "Casper Bonde", phone, email, null, null);
+ msg.addRecipient("", "Jørn Hansen", phone, email, null, null);
msg.setFolder("inbox");
msg.setIncludeAttachments(false);
msg.addTo("Jørn Hansen", "bonde@email.add");
msg.addCc("Jens Hansen", "bonde@email.add");
msg.addFrom("Jørn Hansen", "bonde@email.add");
- BluetoothMapbMessageMms.MimePart part = msg.addMimePart();
+ BluetoothMapbMessageMime .MimePart part = msg.addMimePart();
part.mPartName = "partNameText";
part.mContentType ="dsfajfdlk/text/asdfafda";
try {
@@ -485,6 +509,8 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
msg.setStatus(false);
msg.setType(TYPE.MMS);
+ msg.updateCharset();
+
try {
encoded = new String(msg.encode());
if(D) Log.d(TAG, encoded);
@@ -501,5 +527,56 @@ public class BluetoothMapbMessageTest extends AndroidTestCase {
if(D) Log.i(TAG, "The encoded header: " + headerStr);
}
+ public void testQuotedPrintable() {
+ testQuotedPrintableIso8859_1();
+ testQuotedPrintableUTF_8();
+ }
+
+ public void testQuotedPrintableIso8859_1() {
+ String charset = "iso-8859-1";
+ String input = "Hello, here are some danish letters: =E6=F8=E5.\r\n" +
+ "Please check that you are able to remove soft " +
+ "line breaks and handle '=3D' =\r\ncharacters within the text. \r\n" +
+ "Just a sequence of non optimal characters to make " +
+ "it complete: !\"#$@[\\]^{|}=\r\n~\r\n\r\n" +
+ "Thanks\r\n" +
+ "Casper";
+ String expected = "Hello, here are some danish letters: æøå.\r\n" +
+ "Please check that you are able to remove soft " +
+ "line breaks and handle '=' characters within the text. \r\n" +
+ "Just a sequence of non optimal characters to make " +
+ "it complete: !\"#$@[\\]^{|}~\r\n\r\n" +
+ "Thanks\r\n" +
+ "Casper";
+ String output;
+ output = new String(BluetoothMapUtils.quotedPrintableToUtf8(input, charset));
+ if(D) Log.d(TAG, "\nExpected: \n" + expected);
+ if(D) Log.d(TAG, "\nOutput: \n" + output);
+ assertTrue(output.equals(expected));
+ }
+
+ public void testQuotedPrintableUTF_8() {
+ String charset = "utf-8";
+ String input = "Hello, here are some danish letters: =C3=A6=C3=B8=C3=A5.\r\n" +
+ "Please check that you are able to remove soft " +
+ "line breaks and handle '=3D' =\r\ncharacters within the text. \r\n" +
+ "Just a sequence of non optimal characters to make " +
+ "it complete: !\"#$@[\\]^{|}=\r\n~\r\n\r\n" +
+ "Thanks\r\n" +
+ "Casper";
+ String expected = "Hello, here are some danish letters: æøå.\r\n" +
+ "Please check that you are able to remove soft " +
+ "line breaks and handle '=' characters within the text. \r\n" +
+ "Just a sequence of non optimal characters to make " +
+ "it complete: !\"#$@[\\]^{|}~\r\n\r\n" +
+ "Thanks\r\n" +
+ "Casper";
+ String output;
+ output = new String(BluetoothMapUtils.quotedPrintableToUtf8(input, charset));
+ if(D) Log.d(TAG, "\nExpected: \n" + expected);
+ if(D) Log.d(TAG, "\nOutput: \n" + output);
+ assertTrue(output.equals(expected));
+ }
+
}
diff --git a/tests/src/com/android/bluetooth/tests/BluetoothTestUtils.java b/tests/src/com/android/bluetooth/tests/BluetoothTestUtils.java
new file mode 100644
index 000000000..4ef89e176
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/BluetoothTestUtils.java
@@ -0,0 +1,54 @@
+package com.android.bluetooth.tests;
+
+import android.annotation.TargetApi;
+import android.bluetooth.BluetoothAdapter;
+import android.os.Build;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+
+@TargetApi(Build.VERSION_CODES.ECLAIR)
+public class BluetoothTestUtils extends AndroidTestCase {
+
+ protected static String TAG = "BluetoothTestUtils";
+ protected static final boolean D = true;
+
+ static final int POLL_TIME = 500;
+ static final int ENABLE_TIMEOUT = 5000;
+
+ /** Helper to turn BT on.
+ * This method will either fail on an assert, or return with BT turned on.
+ * Behavior of getState() and isEnabled() are validated along the way.
+ */
+ public static void enableBt(BluetoothAdapter adapter) {
+ if (adapter.getState() == BluetoothAdapter.STATE_ON) {
+ assertTrue(adapter.isEnabled());
+ return;
+ }
+ assertEquals(BluetoothAdapter.STATE_OFF, adapter.getState());
+ assertFalse(adapter.isEnabled());
+ adapter.enable();
+ for (int i=0; i<ENABLE_TIMEOUT/POLL_TIME; i++) {
+ int state = adapter.getState();
+ switch (state) {
+ case BluetoothAdapter.STATE_ON:
+ assertTrue(adapter.isEnabled());
+ Log.i(TAG, "Bluetooth enabled...");
+ return;
+ case BluetoothAdapter.STATE_OFF:
+ Log.i(TAG, "STATE_OFF: Still waiting for enable to begin...");
+ break;
+ default:
+ Log.i(TAG, "Status is: " + state);
+ assertEquals(BluetoothAdapter.STATE_TURNING_ON, adapter.getState());
+ assertFalse(adapter.isEnabled());
+ break;
+ }
+ try {
+ Thread.sleep(POLL_TIME);
+ } catch (InterruptedException e) {}
+ }
+ fail("enable() timeout");
+ }
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/ISeqStepAction.java b/tests/src/com/android/bluetooth/tests/ISeqStepAction.java
new file mode 100644
index 000000000..db66af2d3
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/ISeqStepAction.java
@@ -0,0 +1,13 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+
+public interface ISeqStepAction {
+
+ void execute(SeqStep step, HeaderSet request, Operation op)
+ throws IOException;
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/ISeqStepValidator.java b/tests/src/com/android/bluetooth/tests/ISeqStepValidator.java
new file mode 100644
index 000000000..5819f06e7
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/ISeqStepValidator.java
@@ -0,0 +1,15 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+
+/**
+ * Interface to validate test step result
+ */
+public interface ISeqStepValidator {
+ boolean validate(SeqStep step, HeaderSet response, Operation op)
+ throws IOException;
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/ITestSequenceBuilder.java b/tests/src/com/android/bluetooth/tests/ITestSequenceBuilder.java
new file mode 100644
index 000000000..3314fd6c5
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/ITestSequenceBuilder.java
@@ -0,0 +1,11 @@
+package com.android.bluetooth.tests;
+
+public interface ITestSequenceBuilder {
+
+ /**
+ * Add steps to a sequencer
+ * @param sequencer The sequencer the steps will be added to.
+ */
+ public void build(TestSequencer sequencer);
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/ITestSequenceConfigurator.java b/tests/src/com/android/bluetooth/tests/ITestSequenceConfigurator.java
new file mode 100644
index 000000000..d260d8b28
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/ITestSequenceConfigurator.java
@@ -0,0 +1,17 @@
+package com.android.bluetooth.tests;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+
+import javax.obex.ServerRequestHandler;
+
+public interface ITestSequenceConfigurator {
+
+ /** Use this to customize a serverRequestHandler
+ * @param sequence A reference to the sequence to handle
+ * @param stopLatch a reference to a latch that must be count down, when test completes.
+ * @return Reference to the ServerRequestHandler.
+ */
+ public ServerRequestHandler getObexServer(ArrayList<SeqStep> sequence,
+ CountDownLatch stopLatch);
+}
diff --git a/tests/src/com/android/bluetooth/tests/MapObexLevelTest.java b/tests/src/com/android/bluetooth/tests/MapObexLevelTest.java
new file mode 100644
index 000000000..fb5de24bd
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MapObexLevelTest.java
@@ -0,0 +1,286 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+import javax.obex.ServerRequestHandler;
+
+import junit.framework.Assert;
+import android.annotation.TargetApi;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.os.Build;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.bluetooth.BluetoothObexTransport;
+import com.android.bluetooth.tests.TestSequencer.OPTYPE;
+
+@TargetApi(Build.VERSION_CODES.KITKAT)
+public class MapObexLevelTest extends AndroidTestCase implements ITestSequenceConfigurator {
+ protected static String TAG = "MapObexLevelTest";
+ protected static final boolean D = true;
+ protected static final boolean TRACE = false;
+ protected static final boolean DELAY_PASS_30_SEC = true;
+
+ // 128 bit UUID for MAP MAS
+ static final byte[] MAS_TARGET = new byte[] {
+ (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x40,
+ (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB,
+ (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00,
+ (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66
+ };
+
+ // 128 bit UUID for MAP MNS
+ static final byte[] MNS_TARGET = new byte[] {
+ (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x41,
+ (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB,
+ (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00,
+ (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66
+ };
+
+ /* Message types */
+ static final String TYPE_GET_FOLDER_LISTING = "x-obex/folder-listing";
+ static final String TYPE_GET_MESSAGE_LISTING = "x-bt/MAP-msg-listing";
+ static final String TYPE_GET_CONVO_LISTING = "x-bt/MAP-convo-listing";
+ static final String TYPE_MESSAGE = "x-bt/message";
+ static final String TYPE_SET_MESSAGE_STATUS = "x-bt/messageStatus";
+ static final String TYPE_SET_NOTIFICATION_REGISTRATION = "x-bt/MAP-NotificationRegistration";
+ static final String TYPE_MESSAGE_UPDATE = "x-bt/MAP-messageUpdate";
+ static final String TYPE_GET_MAS_INSTANCE_INFORMATION = "x-bt/MASInstanceInformation";
+
+ public void testFolder() {
+ testLocalSockets(new buildFolderTestSeq());
+ }
+
+ public void testFolderServer() {
+ testServer(new buildFolderTestSeq());
+ }
+
+ public void testFolderClient() {
+ testClient(new buildFolderTestSeq());
+ }
+
+ protected class buildFolderTestSeq implements ITestSequenceBuilder {
+ @Override
+ public void build(TestSequencer sequencer) {
+ addConnectStep(sequencer);
+
+ MapStepsFolder.addGoToMsgFolderSteps(sequencer);
+
+ // MAP DISCONNECT Step
+ addDisconnectStep(sequencer);
+ }
+ }
+
+
+ public void testConvo() {
+ testLocalSockets(new buildConvoTestSeq());
+ }
+
+ public void testConvoServer() {
+ testServer(new buildConvoTestSeq());
+ }
+
+ public void testConvoClient() {
+ testClient(new buildConvoTestSeq());
+ }
+
+ class buildConvoTestSeq implements ITestSequenceBuilder {
+ @Override
+ public void build(TestSequencer sequencer) {
+ addConnectStep(sequencer);
+
+ MapStepsFolder.addGoToMsgFolderSteps(sequencer);
+
+ MapStepsConvo.addConvoListingSteps(sequencer);
+
+ // MAP DISCONNECT Step
+ addDisconnectStep(sequencer);
+ }
+ }
+
+ /**
+ * Run the test sequence using a local socket on a single device.
+ * Throughput around 4000 kbyte/s - with a larger OBEX package size.
+ *
+ * Downside: Unable to get a BT-snoop file...
+ */
+ protected void testLocalSockets(ITestSequenceBuilder builder) {
+ mContext = this.getContext();
+ MapTestData.init(mContext);
+ Log.i(TAG,"Setting up sockets...");
+
+ try {
+ /* Create and interconnect local pipes for transport */
+ LocalServerSocket serverSock = new LocalServerSocket("com.android.bluetooth.tests.sock");
+ LocalSocket clientSock = new LocalSocket();
+ LocalSocket acceptSock;
+
+ clientSock.connect(serverSock.getLocalSocketAddress());
+
+ acceptSock = serverSock.accept();
+
+ /* Create the OBEX transport objects to wrap the pipes - enable SRM */
+ ObexPipeTransport clientTransport = new ObexPipeTransport(clientSock.getInputStream(),
+ clientSock.getOutputStream(), true);
+ ObexPipeTransport serverTransport = new ObexPipeTransport(acceptSock.getInputStream(),
+ acceptSock.getOutputStream(), true);
+
+ TestSequencer sequencer = new TestSequencer(clientTransport, serverTransport, this);
+
+ builder.build(sequencer);
+
+ //Debug.startMethodTracing("ObexTrace");
+ assertTrue(sequencer.run(mContext));
+ //Debug.stopMethodTracing();
+
+ clientSock.close();
+ acceptSock.close();
+ serverSock.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException", e);
+ }
+ }
+
+ /**
+ * Server side of a dual device test using a Bluetooth Socket.
+ * Enables the possibility to get a BT-snoop file.
+ * If you need the btsnoop from the device which completes the test with success
+ * you need to add a delay after the test ends, and fetch the file before this delay
+ * expires. When the test completes, the Bluetooth subsystem will be restarted, causing
+ * a new bt-snoop to overwrite the one used in test.
+ */
+ public void testServer(ITestSequenceBuilder builder) {
+ mContext = this.getContext();
+ MapTestData.init(mContext);
+ Log.i(TAG,"Setting up sockets...");
+
+ try {
+ /* This will turn on BT and create a server socket on which accept can be called. */
+ BluetoothServerSocket serverSocket=ObexTest.createServerSocket(BluetoothSocket.TYPE_L2CAP, true);
+
+ Log.i(TAG, "Waiting for client to connect...");
+ BluetoothSocket socket = serverSocket.accept();
+ Log.i(TAG, "Client connected...");
+
+ BluetoothObexTransport serverTransport = new BluetoothObexTransport(socket);
+
+ TestSequencer sequencer = new TestSequencer(null, serverTransport, this);
+
+ builder.build(sequencer);
+
+ //Debug.startMethodTracing("ObexTrace");
+ assertTrue(sequencer.run(mContext));
+ //Debug.stopMethodTracing();
+
+ serverSocket.close();
+ socket.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException", e);
+ }
+ if(DELAY_PASS_30_SEC) {
+ Log.i(TAG, "\n\n\nTest done - please fetch logs within 30 seconds...\n\n\n");
+ try {
+ Thread.sleep(30000);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ /**
+ * Server side of a dual device test using a Bluetooth Socket.
+ * Enables the possibility to get a BT-snoop file.
+ * If you need the btsnoop from the device which completes the test with success
+ * you need to add a delay after the test ends, and fetch the file before this delay
+ * expires. When the test completes, the Bluetooth subsystem will be restarted, causing
+ * a new bt-snoop to overwrite the one used in test.
+ */
+ public void testClient(ITestSequenceBuilder builder) {
+ mContext = this.getContext();
+ MapTestData.init(mContext);
+ Log.i(TAG, "Setting up sockets...");
+
+ try {
+ /* This will turn on BT and connect */
+ BluetoothSocket clientSock =
+ ObexTest.connectClientSocket(BluetoothSocket.TYPE_L2CAP, true, mContext);
+
+ BluetoothObexTransport clientTransport = new BluetoothObexTransport(clientSock);
+
+ TestSequencer sequencer = new TestSequencer(clientTransport, null, this);
+
+ builder.build(sequencer);
+
+ //Debug.startMethodTracing("ObexTrace");
+ assertTrue(sequencer.run(mContext));
+ //Debug.stopMethodTracing();
+
+ clientSock.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException", e);
+ }
+ if(DELAY_PASS_30_SEC) {
+ Log.i(TAG, "\n\n\nTest done - please fetch logs within 30 seconds...\n\n\n");
+ try {
+ Thread.sleep(30000);
+ } catch (InterruptedException e) {}
+ }
+ }
+
+ protected void addConnectStep(TestSequencer sequencer) {
+ SeqStep step;
+
+ // MAP CONNECT Step
+ step = sequencer.addStep(OPTYPE.CONNECT, null);
+ HeaderSet hs = new HeaderSet();
+ hs.setHeader(HeaderSet.TARGET, MAS_TARGET);
+ step.mReqHeaders = hs;
+ step.mValidator = new MapConnectValidator();
+ //step.mServerPreAction = new MapAddSmsMessages(); // could take in parameters
+ }
+
+ protected void addDisconnectStep(TestSequencer sequencer) {
+ sequencer.addStep(OPTYPE.DISCONNECT, ObexTest.getResponsecodevalidator());
+ }
+
+ /* Functions to validate results */
+
+ private class MapConnectValidator implements ISeqStepValidator {
+ @Override
+ public boolean validate(SeqStep step, HeaderSet response, Operation notUsed)
+ throws IOException {
+ Assert.assertNotNull(response);
+ byte[] who = (byte[])response.getHeader(HeaderSet.WHO);
+ Assert.assertNotNull(who);
+ Assert.assertTrue(Arrays.equals(who, MAS_TARGET));
+ Assert.assertNotNull(response.getHeader(HeaderSet.CONNECTION_ID));
+ return true;
+ }
+ }
+
+ /**
+ * This is the function creating the Obex Server to be used in this class.
+ * Here we use a mocked version of the MapObexServer class
+ */
+ @Override
+ public ServerRequestHandler getObexServer(ArrayList<SeqStep> sequence,
+ CountDownLatch stopLatch) {
+ try {
+ return new MapObexTestServer(mContext, sequence, stopLatch);
+ } catch (RemoteException e) {
+ Log.e(TAG, "exception", e);
+ fail("Unable to create MapObexTestServer");
+ }
+ return null;
+ }
+
+
+}
+
diff --git a/tests/src/com/android/bluetooth/tests/MapObexTestServer.java b/tests/src/com/android/bluetooth/tests/MapObexTestServer.java
new file mode 100644
index 000000000..4fb6ba65d
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MapObexTestServer.java
@@ -0,0 +1,188 @@
+package com.android.bluetooth.tests;
+
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+import javax.obex.ResponseCodes;
+
+import junit.framework.Assert;
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapAccountItem;
+import com.android.bluetooth.map.BluetoothMapContentObserver;
+import com.android.bluetooth.map.BluetoothMapMasInstance;
+import com.android.bluetooth.map.BluetoothMapObexServer;
+import com.android.bluetooth.map.BluetoothMapUtils;
+import com.android.bluetooth.map.BluetoothMnsObexClient;
+
+public class MapObexTestServer extends BluetoothMapObexServer {
+
+ private static final String TAG = "MapObexTestServer";
+ private static final boolean V = true;
+
+ ArrayList<SeqStep> mSequence;
+ CountDownLatch mStopLatch;
+
+ ObexTestDataHandler mDataHandler;
+ int mOperationIndex = 0;
+
+ /* This needs to be static, as calling the super-constructor must be the first step.
+ * Alternatively add the account as constructor parameter, and create a builder
+ * function - factory pattern. */
+// private static BluetoothMapAccountItem mAccountMock = new BluetoothMapAccountItem("1",
+// "TestAccount",
+// "do.not.exist.package.name.and.never.used.anyway:-)",
+// "info.guardianproject.otr.app.im.provider.bluetoothprovider",
+// null,
+// BluetoothMapUtils.TYPE.IM,
+// null,
+// null);
+ private static BluetoothMapAccountItem mAccountMock = null;
+
+ /* MAP Specific instance variables
+ private final BluetoothMapContentObserver mObserver = null;
+ private final BluetoothMnsObexClient mMnsClient = null;*/
+
+ /* Test values, consider gathering somewhere else */
+ private static final int MAS_ID = 0;
+ private static final int REMOTE_FEATURE_MASK = 0x07FFFFFF;
+ private static final BluetoothMapMasInstance mMasInstance =
+ new MockMasInstance(MAS_ID, REMOTE_FEATURE_MASK);
+
+ public MapObexTestServer(final Context context, ArrayList<SeqStep> sequence,
+ CountDownLatch stopLatch) throws RemoteException {
+
+ super(null, context,
+ new BluetoothMapContentObserver(context,
+ new BluetoothMnsObexClient(
+ BluetoothAdapter.getDefaultAdapter().
+ getRemoteDevice("12:23:34:45:56:67"), null, null),
+ /* TODO: this will not work for single device test... */
+ mMasInstance,
+ mAccountMock, /* Account */
+ true) /* Enable SMS/MMS*/,
+ mMasInstance,
+ mAccountMock /* Account */,
+ true /* SMS/MMS enabled*/);
+ mSequence = sequence;
+ mDataHandler = new ObexTestDataHandler("(Server)");
+ mStopLatch = stopLatch;
+ }
+
+ /* 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;
+ SeqStep step = mSequence.get(mOperationIndex);
+ Assert.assertNotNull("invalid step index!", step);
+ if(step.mServerPreAction != null) {
+ step.mServerPreAction.execute(step, request, null);
+ }
+ result = super.onConnect(request, reply);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in onConnect - aborting...", e);
+ 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()");
+ /* TODO: validate request headers, and set response headers */
+ int index;
+ int result = ResponseCodes.OBEX_HTTP_OK;
+ try {
+ index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
+ mOperationIndex = index;
+ SeqStep step = mSequence.get(mOperationIndex);
+ Assert.assertNotNull("invalid step index!", step);
+ if(step.mServerPreAction != null) {
+ step.mServerPreAction.execute(step, request, null);
+ }
+ super.onDisconnect(request, reply);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in onDisconnect - aborting...", e);
+ result = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ // A read from null will produce exception to end the test.
+ }
+ if(mOperationIndex >= (mSequence.size()-1)) {
+ /* 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;
+ }
+
+ @Override
+ public int onPut(Operation operation) {
+ Log.i(TAG,"onPut()");
+ int result = ResponseCodes.OBEX_HTTP_OK;
+ try{
+ HeaderSet reqHeaders = operation.getReceivedHeader();
+ int index = ((Long)reqHeaders.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
+ mOperationIndex = index;
+ SeqStep step = mSequence.get(mOperationIndex);
+ Assert.assertNotNull("invalid step index!", step);
+ if(step.mServerPreAction != null) {
+ step.mServerPreAction.execute(step, reqHeaders, operation);
+ }
+ super.onPut(operation);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in onPut - aborting...", e);
+ result = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ // A read from null will produce exception to end the test.
+ }
+ if(result == ResponseCodes.OBEX_HTTP_OK) {
+ Log.i(TAG, "OBEX-HANDLER: operation complete success");
+ } else {
+ Log.e(TAG, "OBEX-HANDLER: operation complete FAILED!");
+ }
+ return result;
+ }
+
+ @Override
+ public int onGet(Operation operation) {
+ Log.i(TAG,"onGet()");
+ int result = ResponseCodes.OBEX_HTTP_OK;
+ try{
+ HeaderSet reqHeaders = operation.getReceivedHeader();
+ int index = ((Long)reqHeaders.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
+ mOperationIndex = index;
+ SeqStep step = mSequence.get(mOperationIndex);
+ Assert.assertNotNull("invalid step index!", step);
+ if(step.mServerPreAction != null) {
+ step.mServerPreAction.execute(step, reqHeaders, operation);
+ }
+ super.onGet(operation);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in onGet - aborting...", e);
+ result = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
+ // A read from null will produce exception to end the test.
+ }
+ if(result == ResponseCodes.OBEX_HTTP_OK) {
+ Log.i(TAG, "OBEX-HANDLER: operation complete success");
+ } else {
+ Log.e(TAG, "OBEX-HANDLER: operation complete FAILED!");
+ }
+ return result;
+ }
+
+
+
+}
+
diff --git a/tests/src/com/android/bluetooth/tests/MapStepsConvo.java b/tests/src/com/android/bluetooth/tests/MapStepsConvo.java
new file mode 100644
index 000000000..f4288bb4f
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MapStepsConvo.java
@@ -0,0 +1,240 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.text.ParseException;
+import java.util.Arrays;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+import javax.obex.ResponseCodes;
+
+import junit.framework.Assert;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapAppParams;
+import com.android.bluetooth.map.BluetoothMapConvoListing;
+import com.android.bluetooth.map.BluetoothMapConvoListingElement;
+import com.android.bluetooth.map.BluetoothMapFolderElement;
+import com.android.bluetooth.tests.TestSequencer.OPTYPE;
+
+public class MapStepsConvo {
+ private static final String TAG = "MapStepsConvo";
+
+
+ protected static void addConvoListingSteps(TestSequencer sequencer) {
+ SeqStep step;
+ final int count = 5;
+
+ // TODO: As we use the default message database, these tests will fail if the
+ // database has any content.
+ // To cope with this for now, the validation is disabled.
+
+ /* Request the number of messages */
+ step = addConvoListingStep(sequencer,
+ 0 /*maxListCount*/,
+ -1 /*listStartOffset*/,
+ null /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+ /* Add messages and contacts for the entire sequence of tests */
+ step.mServerPreAction = new MapTestData.MapAddSmsMessages(count);
+
+ /* Request the XML for all conversations */
+ step = addConvoListingStep(sequencer,
+ -1 /*maxListCount*/,
+ -1 /*listStartOffset*/,
+ null /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 2 /*maxListCount*/,
+ -1 /*listStartOffset*/,
+ null /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 2 /*maxListCount*/,
+ 1 /*listStartOffset*/,
+ null /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 3 /*maxListCount*/,
+ 2 /*listStartOffset*/,
+ null /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 5 /*maxListCount*/,
+ 1 /*listStartOffset*/,
+ MapTestData.TEST_ACTIVITY_BEGIN_STRING /*activityBegin*/,
+ null /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 5 /*maxListCount*/,
+ 0 /*listStartOffset*/,
+ MapTestData.TEST_ACTIVITY_BEGIN_STRING /*activityBegin*/,
+ MapTestData.TEST_ACTIVITY_END_STRING /*activityEnd*/,
+ -1 /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ step = addConvoListingStep(sequencer,
+ 5 /*maxListCount*/,
+ 1 /*listStartOffset*/,
+ MapTestData.TEST_ACTIVITY_BEGIN_STRING /*activityBegin*/,
+ null /*activityEnd*/,
+ 2/* read only */ /*readStatus*/,
+ null /*recipient*/,
+ /*nearly impossible to validate due to auto assigned ID values*/
+ new MapConvoListValidator()
+ /*new MapConvoListValidator(MapTestData.TEST_NUM_CONTACTS)validator*/);
+
+ /* TODO: Test the different combinations of filtering */
+ }
+
+ /**
+ * Use -1 or null to omit value in request
+ * @param sequencer
+ * @param maxListCount
+ * @param listStartOffset
+ * @param activityBegin
+ * @param activityEnd
+ * @param readStatus -1 omit value, 0 = no filtering, 1 = get unread only, 2 = get read only,
+ * 3 = 1+2 - hence get none...
+ * @param recipient substring of the recipient name
+ * @param validator
+ * @return a reference to the step added, for further decoration
+ */
+ private static SeqStep addConvoListingStep(TestSequencer sequencer, int maxListCount,
+ int listStartOffset, String activityBegin, String activityEnd,
+ int readStatus, String recipient, ISeqStepValidator validator) {
+ SeqStep step;
+ BluetoothMapAppParams appParams = new BluetoothMapAppParams();
+ try {
+ if(activityBegin != null) {
+ appParams.setFilterLastActivityBegin(activityBegin);
+ }
+ if(activityEnd != null) {
+ appParams.setFilterLastActivityEnd(activityEnd);
+ }
+ if(readStatus != -1) {
+ appParams.setFilterReadStatus(readStatus);
+ }
+ if(recipient != null) {
+ appParams.setFilterRecipient(recipient);
+ }
+ if(maxListCount != -1) {
+ appParams.setMaxListCount(maxListCount);
+ }
+ if(listStartOffset != -1) {
+ appParams.setStartOffset(listStartOffset);
+ }
+ } catch (ParseException e) {
+ Log.e(TAG, "unable to build appParams", e);
+ }
+ step = sequencer.addStep(OPTYPE.GET, null);
+ HeaderSet hs = new HeaderSet();
+ hs.setHeader(HeaderSet.TYPE, MapObexLevelTest.TYPE_GET_CONVO_LISTING);
+ try {
+ hs.setHeader(HeaderSet.APPLICATION_PARAMETER, appParams.EncodeParams());
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "ERROR", e);
+ Assert.fail();
+ }
+ step.mReqHeaders = hs;
+ step.mValidator = validator;
+ return step;
+ }
+
+ /* Functions to validate results */
+ private static class MapConvoListValidator implements ISeqStepValidator {
+
+ final BluetoothMapConvoListing mExpectedListing;
+ final int mExpectedSize;
+
+ public MapConvoListValidator(BluetoothMapConvoListing listing) {
+ this.mExpectedListing = listing;
+ this.mExpectedSize = -1;
+ }
+
+ public MapConvoListValidator(int convoListingSize) {
+ this.mExpectedListing = null;
+ this.mExpectedSize = convoListingSize;
+ }
+
+ public MapConvoListValidator() {
+ this.mExpectedListing = null;
+ this.mExpectedSize = -1;
+ }
+
+ @Override
+ public boolean validate(SeqStep step, HeaderSet response, Operation op)
+ throws IOException {
+ Assert.assertNotNull(op);
+ op.noBodyHeader();
+ try {
+ // For some odd reason, the request will not be send before we start to read the
+ // reply data, hence we need to do this first?
+ BluetoothMapConvoListing receivedListing = new BluetoothMapConvoListing();
+ receivedListing.appendFromXml(op.openInputStream());
+ response = op.getReceivedHeader();
+ byte[] appParamsRaw = (byte[])response.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ Assert.assertNotNull(appParamsRaw);
+ BluetoothMapAppParams appParams;
+ appParams = new BluetoothMapAppParams(appParamsRaw);
+ Assert.assertNotNull(appParams);
+ Assert.assertNotNull(appParams.getDatabaseIdentifier());
+ Assert.assertNotSame(BluetoothMapAppParams.INVALID_VALUE_PARAMETER,
+ appParams.getConvoListingSize());
+ if(mExpectedSize >= 0) {
+ Assert.assertSame(mExpectedSize, appParams.getConvoListingSize());
+ }
+ if(mExpectedListing != null) {
+ // Recursively compare
+ Assert.assertTrue(mExpectedListing.equals(receivedListing));
+ Assert.assertSame(mExpectedListing.getList().size(),
+ appParams.getConvoListingSize());
+ }
+ int responseCode = op.getResponseCode();
+ Assert.assertEquals(ResponseCodes.OBEX_HTTP_OK, responseCode);
+ op.close();
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ Assert.fail();
+ }
+ return true;
+ }
+ }
+}
diff --git a/tests/src/com/android/bluetooth/tests/MapStepsFolder.java b/tests/src/com/android/bluetooth/tests/MapStepsFolder.java
new file mode 100644
index 000000000..11d27dcfb
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MapStepsFolder.java
@@ -0,0 +1,159 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+import javax.obex.ResponseCodes;
+
+import junit.framework.Assert;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapAppParams;
+import com.android.bluetooth.map.BluetoothMapFolderElement;
+import com.android.bluetooth.tests.TestSequencer.OPTYPE;
+
+public class MapStepsFolder {
+ private final static String TAG = "MapStepsFolder";
+ /**
+ * Request and expect the following folder structure:
+ * root
+ * telecom
+ * msg
+ * inbox
+ * outbox
+ * draft
+ * sent
+ * deleted
+ *
+ * The order in which they occur in the listing will not matter.
+ * @param sequencer
+ */
+ protected static void addGoToMsgFolderSteps(TestSequencer sequencer) {
+ SeqStep step;
+ //BluetoothMapFolderElement rootDir = new BluetoothMapFolderElement("root", null);
+
+ // MAP Get Folder Listing Steps
+ // The telecom folder
+ step = sequencer.addStep(OPTYPE.GET, null);
+ HeaderSet hs = new HeaderSet();
+ hs.setHeader(HeaderSet.TYPE, MapObexLevelTest.TYPE_GET_FOLDER_LISTING);
+ step.mReqHeaders = hs;
+ step.mValidator = new MapBuildFolderStructurValidator(1, null);
+
+ step = sequencer.addStep(OPTYPE.SET_PATH, ObexTest.getResponsecodevalidator());
+ hs = new HeaderSet();
+ hs.setHeader(HeaderSet.NAME, "telecom");
+ step.mReqHeaders = hs;
+ step.mClientPostAction = new MapSetClientFolder("telecom");
+
+
+ // The msg folder
+ step = sequencer.addStep(OPTYPE.GET, null);
+ hs = new HeaderSet();
+ hs.setHeader(HeaderSet.TYPE, MapObexLevelTest.TYPE_GET_FOLDER_LISTING);
+ step.mReqHeaders = hs;
+ step.mValidator = new MapBuildFolderStructurValidator(1, null);
+
+ step = sequencer.addStep(OPTYPE.SET_PATH, ObexTest.getResponsecodevalidator());
+ hs = new HeaderSet();
+ hs.setHeader(HeaderSet.NAME, "msg");
+ step.mReqHeaders = hs;
+ step.mClientPostAction = new MapSetClientFolder("msg");
+
+ // The msg folder
+ step = sequencer.addStep(OPTYPE.GET, null);
+ hs = new HeaderSet();
+ hs.setHeader(HeaderSet.TYPE, MapObexLevelTest.TYPE_GET_FOLDER_LISTING);
+ step.mReqHeaders = hs;
+ step.mValidator = new MapBuildFolderStructurValidator(5, buildDefaultFolderStructure());
+ }
+
+ /**
+ * Sets the current folder on the client, to the folder name specified in the constructor.
+ * TODO: Could be extended to be able to navigate back and forth in the folder structure.
+ */
+ private static class MapSetClientFolder implements ISeqStepAction {
+ final String mFolderName;
+ public MapSetClientFolder(String folderName) {
+ super();
+ this.mFolderName = folderName;
+ }
+ @Override
+ public void execute(SeqStep step, HeaderSet request, Operation op)
+ throws IOException {
+ MapBuildFolderStructurValidator.sCurrentFolder =
+ MapBuildFolderStructurValidator.sCurrentFolder.getSubFolder(mFolderName);
+ Assert.assertNotNull(MapBuildFolderStructurValidator.sCurrentFolder);
+ Log.i(TAG, "MapSetClientFolder(): Current path: " +
+ MapBuildFolderStructurValidator.sCurrentFolder.getFullPath());
+ }
+ }
+
+ /* Functions to validate results */
+ private static class MapBuildFolderStructurValidator implements ISeqStepValidator {
+
+ final int mExpectedListingSize;
+ static BluetoothMapFolderElement sCurrentFolder = null;
+ final BluetoothMapFolderElement mExpectedFolderElement;
+
+ public MapBuildFolderStructurValidator(int mExpectedListingSize,
+ BluetoothMapFolderElement folderElement) {
+ super();
+ if(sCurrentFolder == null) {
+ sCurrentFolder = new BluetoothMapFolderElement("root", null);
+ }
+ this.mExpectedListingSize = mExpectedListingSize;
+ this.mExpectedFolderElement = folderElement;
+ }
+
+
+ @Override
+ public boolean validate(SeqStep step, HeaderSet response, Operation op)
+ throws IOException {
+ Assert.assertNotNull(op);
+ op.noBodyHeader();
+ try {
+ // For some odd reason, the request will not be send before we start to read the
+ // reply data, hence we need to do this first?
+ sCurrentFolder.appendSubfolders(op.openInputStream());
+ response = op.getReceivedHeader();
+ byte[] appParamsRaw = (byte[])response.getHeader(HeaderSet.APPLICATION_PARAMETER);
+ Assert.assertNotNull(appParamsRaw);
+ BluetoothMapAppParams appParams;
+ appParams = new BluetoothMapAppParams(appParamsRaw);
+ Assert.assertNotNull(appParams);
+ if(mExpectedFolderElement != null) {
+ // Recursively compare
+ Assert.assertTrue(mExpectedFolderElement.compareTo(sCurrentFolder.getRoot())
+ == 0);
+ }
+ int responseCode = op.getResponseCode();
+ Assert.assertEquals(ResponseCodes.OBEX_HTTP_OK, responseCode);
+ op.close();
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ Assert.fail();
+ }
+ return true;
+ }
+
+ }
+
+
+ private static BluetoothMapFolderElement buildDefaultFolderStructure(){
+ BluetoothMapFolderElement root =
+ new BluetoothMapFolderElement("root", null); // This will be the root element
+ BluetoothMapFolderElement tmpFolder;
+ tmpFolder = root.addFolder("telecom"); // root/telecom
+ tmpFolder = tmpFolder.addFolder("msg"); // root/telecom/msg
+ tmpFolder.addFolder("inbox"); // root/telecom/msg/inbox
+ tmpFolder.addFolder("outbox"); // root/telecom/msg/outbox
+ tmpFolder.addFolder("sent"); // root/telecom/msg/sent
+ tmpFolder.addFolder("deleted"); // root/telecom/msg/deleted
+ tmpFolder.addFolder("draft"); // root/telecom/msg/draft
+ return root;
+ }
+
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/MapTestData.java b/tests/src/com/android/bluetooth/tests/MapTestData.java
new file mode 100644
index 000000000..7cb723bf2
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MapTestData.java
@@ -0,0 +1,286 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.obex.HeaderSet;
+import javax.obex.Operation;
+
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.Telephony.Sms;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import com.android.bluetooth.map.BluetoothMapConvoContactElement;
+import com.android.bluetooth.map.BluetoothMapConvoListing;
+import com.android.bluetooth.map.BluetoothMapConvoListingElement;
+import com.android.bluetooth.mapapi.BluetoothMapContract;
+
+/**
+ * Class to hold test data - both the server side data to insert into the databases, and the
+ * validation data to validate the result, when reading back the data.
+ *
+ * Should be data only, not operation specific functionality (client).
+ *
+ * Please try to keep useful functionality call-able from a test case, to make it possible
+ * to call a single test case to e.g. inject some contacts or messages into the database.
+ *
+ */
+@TargetApi(20)
+public class MapTestData extends AndroidTestCase {
+ private static final String TAG = "MapTestData";
+
+ /* Test validation variables */
+ static final String TEST_CONTACT_NAME = "Jesus Ãœberboss";
+ static final String TEST_CONTACT_PHONE = "55566688";
+ static final String TEST_CONTACT_EMAIL = "boss@the.skyes";
+ static final int TEST_NUM_CONTACTS = 3;
+
+ static final int TEST_ADD_CONTACT_PER_ITERATIONS = 4;
+ /* I do know this function is deprecated, but I'm unable to find a good alternative
+ * except from taking a copy of the Date.UTC function as suggested. */
+ // NOTE: This will only set the data on the message - not the lastActivity on SMS/MMS threads
+ static final long TEST_ACTIVITY_BEGIN = Date.UTC(
+ 2014-1900,
+ 8-1, /* month 0-11*/
+ 22, /*day 1-31 */
+ 22, /*hour*/
+ 15, /*minute*/
+ 20 /*second*/);
+
+ static final String TEST_ACTIVITY_BEGIN_STRING = "20150102T150047";
+ static final String TEST_ACTIVITY_END_STRING = "20160102T150047";
+
+ static final int TEST_ACTIVITY_INTERVAL = 5*60*1000; /*ms*/
+
+ static Context sContext = null;
+ public static void init(Context context){
+ sContext = context;
+ }
+ /**
+ * Adds messages to the SMS message database.
+ */
+ public static class MapAddSmsMessages implements ISeqStepAction {
+ int mCount;
+ /**
+ *
+ * @param count the number of iterations to execute
+ */
+ public MapAddSmsMessages(int count) {
+ mCount = count;
+ }
+
+ @Override
+ public void execute(SeqStep step, HeaderSet request, Operation op)
+ throws IOException {
+ int count = mCount; // Number of messages in each conversation
+ ContentResolver resolver = sContext.getContentResolver();
+
+ // Insert some messages
+ insertTestMessages(resolver, step.index, count);
+
+ // Cleanup if needed to avoid duplicates
+ deleteTestContacts(resolver);
+
+ // And now add the contacts
+ setupTestContacts(resolver);
+ }
+ }
+
+ /**
+ * TODO: Only works for filter on TEST_CONTACT_NAME
+ * @param maxCount
+ * @param offset
+ * @param filterContact
+ * @param read
+ * @param reportRead
+ * @param msgCount
+ * @return
+ */
+ public static BluetoothMapConvoListing getConvoListingReference(int maxCount, int offset,
+ boolean filterContact, boolean read, boolean reportRead, int msgCount){
+ BluetoothMapConvoListing list = new BluetoothMapConvoListing();
+ BluetoothMapConvoListingElement element;
+ BluetoothMapConvoContactElement contact;
+ element = new BluetoothMapConvoListingElement();
+ element.setRead(read, reportRead);
+ element.setVersionCounter(0);
+ contact = new BluetoothMapConvoContactElement();
+ contact.setName(TEST_CONTACT_NAME);
+ contact.setLastActivity(TEST_ACTIVITY_BEGIN +
+ msgCount*TEST_ADD_CONTACT_PER_ITERATIONS*TEST_ACTIVITY_INTERVAL);
+ element.addContact(contact);
+ list.add(element);
+ return null;
+ }
+
+ public static void insertTestMessages(ContentResolver resolver, int tag, int count) {
+ ContentValues values[] = new ContentValues[count*4]; // 4 messages/iteration
+ long date = TEST_ACTIVITY_BEGIN;
+ Log.i(TAG, "Preparing messages... with data = " + date);
+
+ for (int x = 0;x < count;x++){
+ /* NOTE: Update TEST_ADD_CONTACT_PER_ITERATIONS if more messages are added */
+ ContentValues item = new ContentValues(5);
+ item.put("address", "98765432");
+ item.put("body", "test message " + x + " step index: " + tag);
+ item.put("date", date+=TEST_ACTIVITY_INTERVAL);
+ item.put("read", "0");
+ if(x%2 == 0) {
+ item.put("type", Sms.MESSAGE_TYPE_INBOX);
+ } else {
+ item.put("type", Sms.MESSAGE_TYPE_SENT);
+ }
+ values[x] = item;
+
+ item = new ContentValues(5);
+ item.put("address", "23456780");
+ item.put("body", "test message " + x + " step index: " + tag);
+ item.put("date", date += TEST_ACTIVITY_INTERVAL);
+ item.put("read", "0");
+ if(x%2 == 0) {
+ item.put("type", Sms.MESSAGE_TYPE_INBOX);
+ } else {
+ item.put("type", Sms.MESSAGE_TYPE_SENT);
+ }
+ values[count+x] = item;
+
+ item = new ContentValues(5);
+ item.put("address", "+4523456780");
+ item.put("body", "test message "+x+" step index: " + tag);
+ item.put("date", date += TEST_ACTIVITY_INTERVAL);
+ item.put("read", "0");
+ if(x%2 == 0) {
+ item.put("type", Sms.MESSAGE_TYPE_INBOX);
+ } else {
+ item.put("type", Sms.MESSAGE_TYPE_SENT);
+ }
+ values[2*count+x] = item;
+
+ /* This is the message used for test */
+ item = new ContentValues(5);
+ item.put("address", TEST_CONTACT_PHONE);
+ item.put("body", "test message "+x+" step index: " + tag);
+ item.put("date", date += TEST_ACTIVITY_INTERVAL);
+ item.put("read", "0");
+ if(x%2 == 0) {
+ item.put("type", Sms.MESSAGE_TYPE_INBOX);
+ } else {
+ item.put("type", Sms.MESSAGE_TYPE_SENT);
+ }
+ values[3*count+x] = item;
+ }
+
+ Log.i(TAG, "Starting bulk insert...");
+ resolver.bulkInsert(Uri.parse("content://sms"), values);
+ Log.i(TAG, "Bulk insert done.");
+ }
+
+ /**
+ * Insert a few contacts in the main contact database, using a test account.
+ */
+ public static void setupTestContacts(ContentResolver resolver){
+ /*TEST_NUM_CONTACTS must be updated if this function is changed */
+ insertContact(resolver, "Hans Hansen", "98765432", "hans@hansens.global");
+ insertContact(resolver, "Helle Børgesen", "23456780", "hb@gmail.com");
+ insertContact(resolver, TEST_CONTACT_NAME, TEST_CONTACT_PHONE, TEST_CONTACT_EMAIL);
+ }
+
+ /**
+ * Helper function to insert a contact
+ * @param name
+ * @param phone
+ * @param email
+ */
+ private static void insertContact(ContentResolver resolver, String name, String phone, String email) {
+ // Get the account info
+ //Cursor c = resolver.query(uri, projection, selection, selectionArgs, sortOrder)
+ ContentValues item = new ContentValues(3);
+ item.put(ContactsContract.RawContacts.ACCOUNT_TYPE, "test_account");
+ item.put(ContactsContract.RawContacts.ACCOUNT_NAME, "MAP account");
+ Uri uri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI, item);
+ Log.i(TAG, "Inserted RawContact: " + uri);
+ long rawId = Long.parseLong(uri.getLastPathSegment());
+
+ //Now add contact information
+ item = new ContentValues(3);
+ item.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
+ item.put(ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
+ item.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
+ name);
+ resolver.insert(ContactsContract.Data.CONTENT_URI, item);
+
+ if(phone != null) {
+ item = new ContentValues(3);
+ item.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
+ item.put(ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
+ item.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
+ resolver.insert(ContactsContract.Data.CONTENT_URI, item);
+ }
+
+ if(email != null) {
+ item = new ContentValues(3);
+ item.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
+ item.put(ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
+ item.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);
+ resolver.insert(ContactsContract.Data.CONTENT_URI, item);
+ }
+ }
+
+ /**
+ * Delete all contacts belonging to the test_account.
+ */
+ public static void deleteTestContacts(ContentResolver resolver){
+ resolver.delete(ContactsContract.RawContacts.CONTENT_URI,
+ ContactsContract.RawContacts.ACCOUNT_TYPE + "=\"test_account\"", null);
+ }
+
+ /****************************************************************************
+ * Small test cases to trigger the functionality without running a sequence.
+ ****************************************************************************/
+ /**
+ * Insert a few contacts in the main contact database, using a test account.
+ */
+ public void testInsertMessages() {
+ ContentResolver resolver = mContext.getContentResolver();
+ insertTestMessages(resolver, 1234, 10);
+ }
+
+ public void testInsert1000Messages() {
+ ContentResolver resolver = mContext.getContentResolver();
+ insertTestMessages(resolver, 1234, 1000);
+ }
+
+ /**
+ * Insert a few contacts in the main contact database, using a test account.
+ */
+ public void testSetupContacts() {
+ ContentResolver resolver = mContext.getContentResolver();
+ setupTestContacts(resolver);
+ }
+
+ /**
+ * Delete all contacts belonging to the test_account.
+ */
+ public void testDeleteTestContacts() {
+ ContentResolver resolver = mContext.getContentResolver();
+ deleteTestContacts(resolver);
+ }
+
+ public void testSetup1000Contacts() {
+ ContentResolver resolver = mContext.getContentResolver();
+ for(int i = 0; i < 1000; i++) {
+ insertContact(resolver, "Hans Hansen " + i,
+ "98765431" + i, "hans" + i + "@hansens.global");
+ }
+ }
+
+}
diff --git a/tests/src/com/android/bluetooth/tests/MockMasInstance.java b/tests/src/com/android/bluetooth/tests/MockMasInstance.java
new file mode 100644
index 000000000..07de8e493
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/MockMasInstance.java
@@ -0,0 +1,30 @@
+package com.android.bluetooth.tests;
+
+import com.android.bluetooth.map.BluetoothMapMasInstance;
+import junit.framework.Assert;
+
+public class MockMasInstance extends BluetoothMapMasInstance {
+
+ private final int mMasId;
+ private final int mRemoteFeatureMask;
+
+ public MockMasInstance(int masId, int remoteFeatureMask) {
+ super();
+ this.mMasId = masId;
+ this.mRemoteFeatureMask = remoteFeatureMask;
+ }
+
+ public int getMasId() {
+ return mMasId;
+ }
+
+ @Override
+ public int getRemoteFeatureMask() {
+ return mRemoteFeatureMask;
+ }
+
+ @Override
+ public void restartObexServerSession() {
+ Assert.fail("restartObexServerSession() should not occur");
+ }
+}
diff --git a/tests/src/com/android/bluetooth/tests/ObexPipeTransport.java b/tests/src/com/android/bluetooth/tests/ObexPipeTransport.java
index 3bb980914..28625d57a 100644
--- a/tests/src/com/android/bluetooth/tests/ObexPipeTransport.java
+++ b/tests/src/com/android/bluetooth/tests/ObexPipeTransport.java
@@ -26,12 +26,12 @@ import java.io.PipedOutputStream;
import javax.obex.ObexTransport;
public class ObexPipeTransport implements ObexTransport {
- PipedInputStream mInStream;
- PipedOutputStream mOutStream;
+ InputStream mInStream;
+ OutputStream mOutStream;
boolean mEnableSrm;
- public ObexPipeTransport(PipedInputStream inStream,
- PipedOutputStream outStream, boolean enableSrm) {
+ public ObexPipeTransport(InputStream inStream,
+ OutputStream outStream, boolean enableSrm) {
mInStream = inStream;
mOutStream = outStream;
mEnableSrm = enableSrm;
@@ -74,12 +74,12 @@ public class ObexPipeTransport implements ObexTransport {
return true;
}
- public int getMaxTxPacketSize() {
- return 15432;
+ public int getMaxTransmitPacketSize() {
+ return 3*15432;
}
- public int getMaxRxPacketSize() {
- return 23450;
+ public int getMaxReceivePacketSize() {
+ return 2*23450;
}
@Override
@@ -88,3 +88,4 @@ public class ObexPipeTransport implements ObexTransport {
}
}
+
diff --git a/tests/src/com/android/bluetooth/tests/ObexTest.java b/tests/src/com/android/bluetooth/tests/ObexTest.java
index ad45522c2..b90ea14c4 100644
--- a/tests/src/com/android/bluetooth/tests/ObexTest.java
+++ b/tests/src/com/android/bluetooth/tests/ObexTest.java
@@ -22,41 +22,35 @@ import java.io.PipedOutputStream;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
-import javax.obex.ClientSession;
import javax.obex.HeaderSet;
-import javax.obex.ObexPacket;
import javax.obex.ObexTransport;
import javax.obex.Operation;
import javax.obex.ResponseCodes;
-import javax.obex.ServerSession;
+import javax.obex.ServerRequestHandler;
+import junit.framework.Assert;
import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.BluetoothUuid;
+import android.bluetooth.SdpMasRecord;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.nfc.cardemulation.OffHostApduService;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
import android.os.Build;
import android.os.Debug;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
import android.os.ParcelUuid;
import android.test.AndroidTestCase;
import android.util.Log;
import com.android.bluetooth.BluetoothObexTransport;
import com.android.bluetooth.sdp.SdpManager;
-import com.android.bluetooth.sdp.SdpMasRecord;
-import com.android.bluetooth.tests.ObexTest.TestSequencer.OPTYPE;
-import com.android.bluetooth.tests.ObexTest.TestSequencer.SeqStep;
+import com.android.bluetooth.tests.TestSequencer.OPTYPE;
/**
* Test either using the reference ril without a modem, or using a RIL implementing the
@@ -64,42 +58,47 @@ import com.android.bluetooth.tests.ObexTest.TestSequencer.SeqStep;
*
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
-public class ObexTest extends AndroidTestCase {
+public class ObexTest extends AndroidTestCase implements ITestSequenceConfigurator {
protected static String TAG = "ObexTest";
protected static final boolean D = true;
protected static final boolean TRACE = false;
protected static final boolean DELAY_PASS_30_SEC = false;
public static final long PROGRESS_INTERVAL_MS = 1000;
private static final ObexTestParams defaultParams =
- new ObexTestParams(2*8092, 0, 2*1024*1024/10);
+ new ObexTestParams(2*8092, 0, 2*1024*1024);
private static final ObexTestParams throttle100Params =
- new ObexTestParams(2*8092, 100000, 2*1024*1024/10);
+ new ObexTestParams(2*8092, 100000, 1024*1024);
private static final ObexTestParams smallParams =
new ObexTestParams(2*8092, 0, 2*1024);
private static final ObexTestParams hugeParams =
- new ObexTestParams(2*8092, 0, 100*1024*1024/1000);
+ new ObexTestParams(2*8092, 0, 100*1024*1024);
- private static final int SMALL_OPERATION_COUNT = 1000/100;
+ private static final int SMALL_OPERATION_COUNT = 1000;
private static final int CONNECT_OPERATION_COUNT = 4500;
private static final int L2CAP_PSM = 29; /* If SDP is not used */
private static final int RFCOMM_CHANNEL = 29; /* If SDP is not used */
- public static final String SERVER_ADDRESS = "10:68:3F:5E:F9:2E";
+ //public static final String SERVER_ADDRESS = "10:68:3F:5E:F9:2E";
+ public static final String SERVER_ADDRESS = "F8:CF:C5:A8:70:7E";
private static final String SDP_SERVER_NAME = "Samsung Server";
private static final String SDP_CLIENT_NAME = "Samsung Client";
- private static final long SDP_FEATURES = 0x87654321L; /* 32 bit */
+ private static final long SDP_FEATURES = 0x87654321L; /* 32 bit */
private static final int SDP_MSG_TYPES = 0xf1; /* 8 bit */
private static final int SDP_MAS_ID = 0xCA; /* 8 bit */
private static final int SDP_VERSION = 0xF0C0; /* 16 bit */
public static final ParcelUuid SDP_UUID_OBEX_MAS = BluetoothUuid.MAS;
private static int sSdpHandle = -1;
+ private static final ObexTestDataHandler sDataHandler = new ObexTestDataHandler("(Client)");
+ private static final ISeqStepValidator sResponseCodeValidator = new ResponseCodeValidator();
+ private static final ISeqStepValidator sDataValidator = new DataValidator();
+
private enum SequencerType {
SEQ_TYPE_PAYLOAD,
@@ -109,10 +108,6 @@ public class ObexTest extends AndroidTestCase {
private Context mContext = null;
private int mChannelType = 0;
- public static final int STEP_INDEX_HEADER = 0xF1; /*0xFE*/
- private static final int ENABLE_TIMEOUT = 5000;
- private static final int POLL_TIME = 500;
-
public ObexTest() {
super();
}
@@ -121,6 +116,8 @@ public class ObexTest extends AndroidTestCase {
* Test that a connection can be established.
* WARNING: The performance of the pipe implementation is not good. I'm only able to get a
* throughput of around 220 kbyte/sec - less that when using Bluetooth :-)
+ * UPDATE: Did a local socket implementation below to replace this...
+ * This has a throughput of more than 4000 kbyte/s
*/
public void testLocalPipes() {
mContext = this.getContext();
@@ -147,58 +144,97 @@ public class ObexTest extends AndroidTestCase {
TestSequencer sequencer = createBtPayloadTestSequence(clientTransport, serverTransport);
//Debug.startMethodTracing("ObexTrace");
- assertTrue(sequencer.run());
+ assertTrue(sequencer.run(mContext));
//Debug.stopMethodTracing();
} catch (IOException e) {
Log.e(TAG, "IOException", e);
}
}
+ /**
+ * Run the test sequence using a local socket.
+ * Throughput around 4000 kbyte/s - with a larger OBEX package size.
+ */
+ public void testLocalSockets() {
+ mContext = this.getContext();
+ System.out.println("Setting up sockets...");
+
+ try {
+ /* Create and interconnect local pipes for transport */
+ LocalServerSocket serverSock = new LocalServerSocket("com.android.bluetooth.tests.sock");
+ LocalSocket clientSock = new LocalSocket();
+ LocalSocket acceptSock;
+
+ clientSock.connect(serverSock.getLocalSocketAddress());
+
+ acceptSock = serverSock.accept();
+
+ /* Create the OBEX transport objects to wrap the pipes - enable SRM */
+ ObexPipeTransport clientTransport = new ObexPipeTransport(clientSock.getInputStream(),
+ clientSock.getOutputStream(), true);
+ ObexPipeTransport serverTransport = new ObexPipeTransport(acceptSock.getInputStream(),
+ acceptSock.getOutputStream(), true);
+
+ TestSequencer sequencer = createBtPayloadTestSequence(clientTransport, serverTransport);
+
+ //Debug.startMethodTracing("ObexTrace");
+ assertTrue(sequencer.run(mContext));
+ //Debug.stopMethodTracing();
+
+ clientSock.close();
+ acceptSock.close();
+ serverSock.close();
+ } catch (IOException e) {
+ Log.e(TAG, "IOException", e);
+ }
+ }
+
/* Create a sequence of put/get operations with different payload sizes */
private TestSequencer createBtPayloadTestSequence(ObexTransport clientTransport,
ObexTransport serverTransport)
throws IOException {
- TestSequencer sequencer = new TestSequencer(clientTransport, serverTransport);
+ TestSequencer sequencer = new TestSequencer(clientTransport, serverTransport, this);
SeqStep step;
- step = sequencer.addStep(OPTYPE.CONNECT);
+ step = sequencer.addStep(OPTYPE.CONNECT, sResponseCodeValidator);
+ if(false){
- step = sequencer.addStep(OPTYPE.PUT);
+ step = sequencer.addStep(OPTYPE.PUT, sDataValidator);
step.mParams = defaultParams;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.GET);
+ step = sequencer.addStep(OPTYPE.GET, sDataValidator);
step.mParams = defaultParams;
step.mUseSrm = true;
-if(true){
- step = sequencer.addStep(OPTYPE.PUT);
+
+ step = sequencer.addStep(OPTYPE.PUT, sDataValidator);
step.mParams = throttle100Params;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.GET);
+ step = sequencer.addStep(OPTYPE.GET, sDataValidator);
step.mParams = throttle100Params;
step.mUseSrm = true;
for(int i=0; i<SMALL_OPERATION_COUNT; i++){
- step = sequencer.addStep(OPTYPE.PUT);
+ step = sequencer.addStep(OPTYPE.PUT, sDataValidator);
step.mParams = smallParams;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.GET);
+ step = sequencer.addStep(OPTYPE.GET, sDataValidator);
step.mParams = smallParams;
step.mUseSrm = true;
}
+}
- step = sequencer.addStep(OPTYPE.PUT);
+ step = sequencer.addStep(OPTYPE.PUT, sDataValidator);
step.mParams = hugeParams;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.GET);
+ step = sequencer.addStep(OPTYPE.GET, sDataValidator);
step.mParams = hugeParams;
step.mUseSrm = true;
- }
- step = sequencer.addStep(OPTYPE.DISCONNECT);
+ step = sequencer.addStep(OPTYPE.DISCONNECT, sResponseCodeValidator);
return sequencer;
}
@@ -206,24 +242,98 @@ if(true){
private TestSequencer createBtConnectTestSequence(ObexTransport clientTransport,
ObexTransport serverTransport)
throws IOException {
- TestSequencer sequencer = new TestSequencer(clientTransport, serverTransport);
+ TestSequencer sequencer = new TestSequencer(clientTransport, serverTransport, this);
SeqStep step;
- step = sequencer.addStep(OPTYPE.CONNECT);
+ step = sequencer.addStep(OPTYPE.CONNECT, sResponseCodeValidator);
- step = sequencer.addStep(OPTYPE.PUT);
+ step = sequencer.addStep(OPTYPE.PUT, sDataValidator);
step.mParams = smallParams;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.GET);
+ step = sequencer.addStep(OPTYPE.GET, sDataValidator);
step.mParams = smallParams;
step.mUseSrm = true;
- step = sequencer.addStep(OPTYPE.DISCONNECT);
+ step = sequencer.addStep(OPTYPE.DISCONNECT, sResponseCodeValidator);
return sequencer;
}
+
+ /**
+ * Use this validator to validate operation response codes. E.g. for OBEX CONNECT and
+ * DISCONNECT operations.
+ * Expects HeaderSet to be valid, and Operation to be null.
+ */
+ public static ISeqStepValidator getResponsecodevalidator() {
+ return sResponseCodeValidator;
+ }
+
+ /**
+ * Use this validator to validate (and read/write data) for OBEX PUT and GET operations.
+ * Expects Operation to be valid, and HeaderSet to be null.
+ */
+ public static ISeqStepValidator getDatavalidator() {
+ return sDataValidator;
+ }
+
+ /**
+ * Use this validator to validate operation response codes. E.g. for OBEX CONNECT and
+ * DISCONNECT operations.
+ * Expects HeaderSet to be valid, and Operation to be null.
+ */
+ private static class ResponseCodeValidator implements ISeqStepValidator {
+
+ protected static boolean validateHeaderSet(HeaderSet headers, HeaderSet expected)
+ throws IOException {
+ if(headers.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
+ Log.e(TAG,"Wrong ResponseCode: " + headers.getResponseCode());
+ Assert.assertTrue(false);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean validate(SeqStep step, HeaderSet response, Operation op)
+ throws IOException {
+ if(response == null) {
+ if(op.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
+ Log.e(TAG,"Wrong ResponseCode: " + op.getResponseCode());
+ Assert.assertTrue(false);
+ return false;
+ }
+ return true;
+ }
+ return validateHeaderSet(response, step.mResHeaders);
+ }
+ }
+
+ /**
+ * Use this validator to validate (and read/write data) for OBEX PUT and GET operations.
+ * Expects Operation to ve valid, and HeaderSet to be null.
+ */
+ private static class DataValidator implements ISeqStepValidator {
+ @Override
+ public boolean validate(SeqStep step, HeaderSet notUsed, Operation op)
+ throws IOException {
+ Assert.assertNotNull(op);
+ if(step.mType == OPTYPE.GET) {
+ op.noBodyHeader();
+ sDataHandler.readData(op.openDataInputStream(), step.mParams);
+ } else if (step.mType == OPTYPE.PUT) {
+ sDataHandler.writeData(op.openDataOutputStream(), step.mParams);
+ }
+ int responseCode = op.getResponseCode();
+ Log.i(TAG, "response code: " + responseCode);
+ HeaderSet response = op.getReceivedHeader();
+ ResponseCodeValidator.validateHeaderSet(response, step.mResHeaders);
+ op.close();
+ return true;
+ }
+ }
+
public void testBtServerL2cap() {
testBtServer(BluetoothSocket.TYPE_L2CAP, false, SequencerType.SEQ_TYPE_PAYLOAD);
}
@@ -276,7 +386,7 @@ if(true){
SequencerType.SEQ_TYPE_CONNECT_DISCONNECT);
try {
// We give the server 100ms to allow adding SDP record
- Thread.sleep(100);
+ Thread.sleep(150);
} catch (InterruptedException e) {
Log.e(TAG,"Exception while waiting...",e);
}
@@ -303,7 +413,7 @@ if(true){
SequencerType.SEQ_TYPE_CONNECT_DISCONNECT);
try {
// We give the server 100ms to allow adding SDP record
- Thread.sleep(100);
+ Thread.sleep(250);
} catch (InterruptedException e) {
Log.e(TAG,"Exception while waiting...",e);
}
@@ -327,16 +437,17 @@ if(true){
Log.e(TAG,"No Bluetooth Device!");
assertTrue(false);
}
- enableBt(bt);
+ BluetoothTestUtils.enableBt(bt);
BluetoothServerSocket serverSocket=null;
if(type == BluetoothSocket.TYPE_L2CAP) {
if(useSdp == true) {
- serverSocket = bt.listenUsingL2capOn(L2CAP_PSM);
- } else {
serverSocket = bt.listenUsingL2capOn(
BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP);
+ } else {
+ serverSocket = bt.listenUsingL2capOn(L2CAP_PSM);
}
l2capPsm = serverSocket.getChannel();
+ Log.d(TAG, "L2CAP createde, PSM: " + l2capPsm);
} else if(type == BluetoothSocket.TYPE_RFCOMM) {
if(useSdp == true) {
serverSocket = bt.listenUsingInsecureRfcommOn(
@@ -345,19 +456,25 @@ if(true){
serverSocket = bt.listenUsingInsecureRfcommOn(RFCOMM_CHANNEL);
}
rfcommChannel = serverSocket.getChannel();
+ Log.d(TAG, "RFCOMM createde, Channel: " + rfcommChannel);
} else {
fail("Invalid transport type!");
}
if(useSdp == true) {
- /* We use the MAP service record to be able to */
+ /* We use the MAP service record to be able to set rfcomm and l2cap channels */
// TODO: We need to free this
- if(sSdpHandle < 0) {
- sSdpHandle = SdpManager.getDefaultManager().createMapMasRecord(SDP_SERVER_NAME,
- SDP_MAS_ID, rfcommChannel, l2capPsm,
- SDP_VERSION, SDP_MSG_TYPES, (int)(SDP_FEATURES & 0xffffffff));
+ if(sSdpHandle >= 0) {
+ SdpManager.getDefaultManager().removeSdpRecord(sSdpHandle);
}
+ Log.d(TAG, "Creating record with rfcomm channel: " + rfcommChannel +
+ " and l2cap channel: " + l2capPsm);
+ sSdpHandle = SdpManager.getDefaultManager().createMapMasRecord(SDP_SERVER_NAME,
+ SDP_MAS_ID, rfcommChannel, l2capPsm,
+ SDP_VERSION, SDP_MSG_TYPES, (int)(SDP_FEATURES & 0xffffffff));
+ } else {
+ Log.d(TAG, "SKIP creation of record with rfcomm channel: " + rfcommChannel +
+ " and l2cap channel: " + l2capPsm);
}
-
return serverSocket;
}
@@ -373,7 +490,7 @@ if(true){
*/
private void testBtServer(int type, boolean useSdp, SequencerType sequencerType) {
mContext = this.getContext();
- System.out.println("Starting BT Server...");
+ Log.d(TAG,"Starting BT Server...");
if(TRACE) Debug.startMethodTracing("ServerSide");
try {
@@ -398,7 +515,7 @@ if(true){
}
//Debug.startMethodTracing("ObexTrace");
- assertTrue(sequencer.run());
+ assertTrue(sequencer.run(mContext));
//Debug.stopMethodTracing();
// Same as below... serverTransport.close();
// This is done by the obex server socket.close();
@@ -436,7 +553,7 @@ if(true){
Log.e(TAG,"No Bluetooth Device!");
assertTrue(false);
}
- enableBt(bt);
+ BluetoothTestUtils.enableBt(bt);
BluetoothDevice serverDevice = bt.getRemoteDevice(SERVER_ADDRESS);
if(useSdp == true) {
@@ -487,9 +604,9 @@ if(true){
}
//Debug.startMethodTracing("ObexTrace");
- assertTrue(sequencer.run());
+ assertTrue(sequencer.run(mContext));
//Debug.stopMethodTracing();
- // socket.close(); shall be closed by the obex client
+ socket.close(); // Only the streams are closed by the obex client
sequencer.shutdown();
} catch (IOException e) {
@@ -591,336 +708,13 @@ if(true){
return broadcastReceiver.getMasRecord();
}
- /** Helper to turn BT on.
- * This method will either fail on an assert, or return with BT turned on.
- * Behavior of getState() and isEnabled() are validated along the way.
- */
- public static void enableBt(BluetoothAdapter adapter) {
- if (adapter.getState() == BluetoothAdapter.STATE_ON) {
- assertTrue(adapter.isEnabled());
- return;
- }
- assertEquals(BluetoothAdapter.STATE_OFF, adapter.getState());
- assertFalse(adapter.isEnabled());
- adapter.enable();
- for (int i=0; i<ENABLE_TIMEOUT/POLL_TIME; i++) {
- switch (adapter.getState()) {
- case BluetoothAdapter.STATE_ON:
- assertTrue(adapter.isEnabled());
- return;
- case BluetoothAdapter.STATE_OFF:
- Log.i(TAG, "STATE_OFF: Still waiting for enable to begin...");
- break;
- default:
- assertEquals(BluetoothAdapter.STATE_TURNING_ON, adapter.getState());
- assertFalse(adapter.isEnabled());
- break;
- }
- try {
- Thread.sleep(POLL_TIME);
- } catch (InterruptedException e) {}
- }
- fail("enable() timeout");
- Log.i(TAG, "Bluetooth enabled...");
+ @Override
+ public ServerRequestHandler getObexServer(ArrayList<SeqStep> sequence,
+ CountDownLatch stopLatch) {
+ return new ObexTestServer(sequence, stopLatch);
}
- public static class TestSequencer implements Callback {
-
- private final static int MSG_ID_TIMEOUT = 0x01;
- private final static int TIMEOUT_VALUE = 100*2000; // ms
- private ArrayList<SeqStep> mSequence = null;
- private HandlerThread mHandlerThread = null;
- private Handler mMessageHandler = null;
- private ObexTransport mClientTransport;
- private ObexTransport mServerTransport;
-
- private ClientSession mClientSession;
- private ServerSession mServerSession;
- ObexTestDataHandler mDataHandler;
-
- public enum OPTYPE {CONNECT, PUT, GET, DISCONNECT};
-
-
- public class SeqStep {
- /**
- * Test step class to define the operations to be tested.
- * Some of the data in these test steps will be modified during
- * test - e.g. the HeaderSets will be modified to enable SRM
- * and/or carry test information
- */
- /* Operation type - Connect, Get, Put etc. */
- public OPTYPE mType;
- /* The headers to send in the request - and validate on server side */
- public HeaderSet mReqHeaders = null;
- /* The headers to send in the response - and validate on client side */
- public HeaderSet mResHeaders = null;
- /* Use SRM */
- public boolean mUseSrm = false;
- /* The amount of data to include in the body */
- public ObexTestParams mParams = null;
- /* The offset into the data where the un-pause signal is to be sent */
- public int mUnPauseOffset = -1;
- /* The offset into the data where the Abort request is to be sent */
- public int mAbortOffset = -1;
- /* The side to perform Abort */
- public boolean mServerSideAbout = false;
- /* The ID of the test step */
- private int mId;
-
- /* Arrays to hold expected sequence of request/response packets. */
- public ArrayList<ObexPacket> mRequestPackets = null;
- public ArrayList<ObexPacket> mResponsePackets = null;
-
- public int index = 0; /* requests with same index are executed in parallel
- (without waiting for a response) */
-
- public SeqStep(OPTYPE type) {
- mRequestPackets = new ArrayList<ObexPacket>();
- mResponsePackets = new ArrayList<ObexPacket>();
- mType = type;
- }
-
- /* TODO: Consider to build these automatically based on the operations
- * to be performed. Validate using utility functions - not strict
- * binary compare.*/
- public void addObexPacketSet(ObexPacket request, ObexPacket response) {
- mRequestPackets.add(request);
- mResponsePackets.add(response);
- }
- }
-
- public TestSequencer(ObexTransport clientTransport, ObexTransport serverTransport)
- throws IOException {
- /* Setup the looper thread to handle messages */
-// mHandlerThread = new HandlerThread("TestTimeoutHandler",
-// android.os.Process.THREAD_PRIORITY_BACKGROUND);
-// mHandlerThread.start();
-// Looper testLooper = mHandlerThread.getLooper();
-// mMessageHandler = new Handler(testLooper, this);
- mClientTransport = clientTransport;
- mServerTransport = serverTransport;
-
- //TODO: fix looper cleanup on server - crash after 464 iterations - related to prepare?
-
- /* Initialize members */
- mSequence = new ArrayList<SeqStep>();
- mDataHandler = new ObexTestDataHandler("(Client)");
- }
-
- /**
- * Add a test step to the sequencer.
- * @param type the OBEX operation to perform.
- * @return the created step, which can be decorated before execution.
- */
- public SeqStep addStep(OPTYPE type) {
- SeqStep newStep = new SeqStep(type);
- mSequence.add(newStep);
- return newStep;
- }
-
- /**
- * Add a sub-step to a sequencer step. All requests added to the same index will be send to
- * the SapServer in the order added before listening for the response.
- * The response order is not validated - hence for each response received the entire list of
- * responses in the step will be searched for a match.
- * @param index the index returned from addStep() to which the sub-step is to be added.
- * @param request The request to send to the SAP server
- * @param response The response to EXPECT from the SAP server
-
- public void addSubStep(int index, SapMessage request, SapMessage response) {
- SeqStep step = sequence.get(index);
- step.add(request, response);
- }*/
-
-
- /**
- * Run the sequence.
- * Validate the response is either the expected response or one of the expected events.
- *
- * @return true when done - asserts at error/fail
- */
- public boolean run() throws IOException {
- CountDownLatch stopLatch = new CountDownLatch(1);
-
- /* TODO:
- * First create sequencer to validate using BT-snoop
- * 1) Create the transports (this could include a validation sniffer on each side)
- * 2) Create a server thread with a link to the transport
- * 3) execute the client operation
- * 4) validate response
- *
- * On server:
- * 1) validate the request contains the expected content
- * 2) send response.
- * */
-
- /* Create the server */
- if(mServerTransport != null) {
- mServerSession = new ServerSession(mServerTransport, new ObexTestServer(mSequence,
- stopLatch), null);
- }
-
- /* Create the client */
- if(mClientTransport != null) {
- mClientSession = new ClientSession(mClientTransport);
-
- for(SeqStep step : mSequence) {
- long stepIndex = mSequence.indexOf(step);
-
- Log.i(TAG, "Executing step " + stepIndex + " of type: " + step.mType);
-
- switch(step.mType) {
- case CONNECT: {
- HeaderSet reqHeaders = step.mReqHeaders;
- if(reqHeaders == null) {
- reqHeaders = new HeaderSet();
- }
- reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
- HeaderSet response = mClientSession.connect(reqHeaders);
- validateHeaderSet(response, step.mResHeaders);
- break;
- }
- case GET:{
- HeaderSet reqHeaders = step.mReqHeaders;
- if(reqHeaders == null) {
- reqHeaders = new HeaderSet();
- }
- reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
- Operation op = mClientSession.get(reqHeaders);
- if(op != null) {
- op.noBodyHeader();
- mDataHandler.readData(op.openDataInputStream(), step.mParams);
- int responseCode = op.getResponseCode();
- Log.i(TAG, "response code: " + responseCode);
- HeaderSet response = op.getReceivedHeader();
- validateHeaderSet(response, step.mResHeaders);
- op.close();
- }
- break;
- }
- case PUT: {
- HeaderSet reqHeaders = step.mReqHeaders;
- if(reqHeaders == null) {
- reqHeaders = new HeaderSet();
- }
- reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
- Operation op = mClientSession.put(reqHeaders);
- if(op != null) {
- mDataHandler.writeData(op.openDataOutputStream(), step.mParams);
- int responseCode = op.getResponseCode();
- Log.i(TAG, "response code: " + responseCode);
- HeaderSet response = op.getReceivedHeader();
- validateHeaderSet(response, step.mResHeaders);
- op.close();
- }
- break;
- }
- case DISCONNECT: {
- Log.i(TAG,"Requesting disconnect...");
- HeaderSet reqHeaders = step.mReqHeaders;
- if(reqHeaders == null) {
- reqHeaders = new HeaderSet();
- }
- reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
- try{
- HeaderSet response = mClientSession.disconnect(reqHeaders);
- Log.i(TAG,"Received disconnect response...");
- // For some reason this returns -1 -> EOS
- // Maybe increase server timeout.
- validateHeaderSet(response, step.mResHeaders);
- } catch (IOException e) {
- Log.e(TAG, "Error getting response code", e);
- }
- break;
- }
- default:
- assertTrue("Unknown type: " + step.mType, false);
- break;
-
- }
- }
- mClientSession.close();
- }
- /* All done, close down... */
- if(mServerSession != null) {
- boolean interrupted = false;
- do {
- try {
- interrupted = false;
- Log.i(TAG,"Waiting for stopLatch signal...");
- stopLatch.await();
- } catch (InterruptedException e) {
- Log.w(TAG,e);
- interrupted = true;
- }
- } while (interrupted == true);
- Log.i(TAG,"stopLatch signal received closing down...");
- try {
- interrupted = false;
- Log.i(TAG," Sleep 50ms to allow disconnect signal to be send before closing.");
- Thread.sleep(50);
- } catch (InterruptedException e) {
- Log.w(TAG,e);
- interrupted = true;
- }
- mServerSession.close();
- }
- // this will close the I/O streams as well.
- return true;
- }
-
- public void shutdown() {
-// mMessageHandler.removeCallbacksAndMessages(null);
-// mMessageHandler.quit();
-// mMessageHandler = null;
- }
-
-
- void validateHeaderSet(HeaderSet headers, HeaderSet expected) throws IOException {
- /* TODO: Implement and assert if different */
- if(headers.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
- Log.e(TAG,"Wrong ResponseCode: " + headers.getResponseCode());
- assertTrue(false);
- }
- }
-
-// private void startTimer() {
-// Message timeoutMessage = mMessageHandler.obtainMessage(MSG_ID_TIMEOUT);
-// mMessageHandler.sendMessageDelayed(timeoutMessage, TIMEOUT_VALUE);
-// }
-//
-// private void stopTimer() {
-// mMessageHandler.removeMessages(MSG_ID_TIMEOUT);
-// }
-
- @Override
- public boolean handleMessage(Message msg) {
- Log.i(TAG,"Handling message ID: " + msg.what);
- switch(msg.what) {
- case MSG_ID_TIMEOUT:
- Log.w(TAG, "Timeout occured!");
-/* try {
- //inStream.close();
- } catch (IOException e) {
- Log.e(TAG, "failed to close inStream", e);
- }
- try {
- //outStream.close();
- } catch (IOException e) {
- Log.e(TAG, "failed to close outStream", e);
- }*/
- break;
- default:
- /* Message not handled */
- return false;
- }
- return true; // Message handles
- }
-
-
-
- }
+}
-} \ No newline at end of file
diff --git a/tests/src/com/android/bluetooth/tests/ObexTestServer.java b/tests/src/com/android/bluetooth/tests/ObexTestServer.java
index b7df65c57..1efe56d5c 100644
--- a/tests/src/com/android/bluetooth/tests/ObexTestServer.java
+++ b/tests/src/com/android/bluetooth/tests/ObexTestServer.java
@@ -13,8 +13,6 @@ import javax.obex.ServerRequestHandler;
import android.util.Log;
-import com.android.bluetooth.tests.ObexTest.TestSequencer.SeqStep;
-
public class ObexTestServer extends ServerRequestHandler {
private static final String TAG = "ObexTestServer";
@@ -40,7 +38,7 @@ public class ObexTestServer extends ServerRequestHandler {
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
- index = ((Long)request.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onConnect - aborting...");
@@ -58,7 +56,7 @@ public class ObexTestServer extends ServerRequestHandler {
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
- index = ((Long)request.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onDisconnect...");
@@ -89,7 +87,7 @@ public class ObexTestServer extends ServerRequestHandler {
try{
inStream = operation.openInputStream();
HeaderSet reqHeaders = operation.getReceivedHeader();
- int index = ((Long)reqHeaders.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ int index = ((Long)reqHeaders.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
mDataHandler.readData(inStream, mSequence.get(index).mParams);
} catch (IOException e) {
@@ -121,7 +119,7 @@ public class ObexTestServer extends ServerRequestHandler {
try{
outStream = operation.openOutputStream();
HeaderSet reqHeaders = operation.getReceivedHeader();
- int index = ((Long)reqHeaders.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ int index = ((Long)reqHeaders.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
mDataHandler.writeData(outStream, mSequence.get(index).mParams);
} catch (IOException e) {
diff --git a/tests/src/com/android/bluetooth/tests/SdpManagerTest.java b/tests/src/com/android/bluetooth/tests/SdpManagerTest.java
index c72207298..2b7310d1d 100644
--- a/tests/src/com/android/bluetooth/tests/SdpManagerTest.java
+++ b/tests/src/com/android/bluetooth/tests/SdpManagerTest.java
@@ -34,8 +34,8 @@ public class SdpManagerTest extends AndroidTestCase {
public static final int SDP_RECORD_COUNT = 12; /* Maximum number of records to create */
public static final int SDP_ITERATIONS = 2000;
- public static final String SDP_SERVER_NAME = "SDP test Server";
- public static final String SDP_CLIENT_NAME = "SDP test Client";
+ public static final String SDP_SERVER_NAME = "SDP test server";
+ public static final String SDP_CLIENT_NAME = "SDP test client";
public static final long SDP_FEATURES = 0x87654321L; /* 32 bit */
public static final int SDP_MSG_TYPES = 0xf1; /* 8 bit */
@@ -51,7 +51,7 @@ public class SdpManagerTest extends AndroidTestCase {
Log.e(TAG,"No Bluetooth Device!");
assertTrue(false);
}
- ObexTest.enableBt(bt);
+ BluetoothTestUtils.enableBt(bt);
mManager = SdpManager.getDefaultManager();
addRemoveRecords(SDP_RECORD_COUNT);
}
@@ -62,7 +62,7 @@ public class SdpManagerTest extends AndroidTestCase {
Log.e(TAG,"No Bluetooth Device!");
assertTrue(false);
}
- ObexTest.enableBt(bt);
+ BluetoothTestUtils.enableBt(bt);
mManager = SdpManager.getDefaultManager();
int handles[] = new int[SDP_RECORD_COUNT];
@@ -175,7 +175,7 @@ public class SdpManagerTest extends AndroidTestCase {
mClientSession = new ClientSession(clientTransport);
{ // Connect
HeaderSet reqHeaders = new HeaderSet();
- reqHeaders.setHeader(ObexTest.STEP_INDEX_HEADER, (long)0);
+ reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, (long)0);
HeaderSet response = mClientSession.connect(reqHeaders);
assertEquals(response.responseCode, ResponseCodes.OBEX_HTTP_OK);
}
@@ -186,7 +186,7 @@ public class SdpManagerTest extends AndroidTestCase {
{ // get operation to trigger SDP search on peer device
HeaderSet reqHeaders = new HeaderSet();
- reqHeaders.setHeader(ObexTest.STEP_INDEX_HEADER, (long)iteration);
+ reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, (long)iteration);
reqHeaders.setHeader(HeaderSet.COUNT, (long)count);
reqHeaders.setHeader(HeaderSet.NAME, uuids_str);
Operation op = mClientSession.get(reqHeaders);
@@ -201,7 +201,7 @@ public class SdpManagerTest extends AndroidTestCase {
}
{ // disconnect to end test
HeaderSet reqHeaders = new HeaderSet();
- reqHeaders.setHeader(ObexTest.STEP_INDEX_HEADER, 0L); // signals end of test
+ reqHeaders.setHeader(TestSequencer.STEP_INDEX_HEADER, 0L); // signals end of test
HeaderSet response = mClientSession.disconnect(reqHeaders);
assertEquals(response.responseCode, ResponseCodes.OBEX_HTTP_OK);
}
diff --git a/tests/src/com/android/bluetooth/tests/SdpManagerTestServer.java b/tests/src/com/android/bluetooth/tests/SdpManagerTestServer.java
index 2151e564b..19e01bea4 100644
--- a/tests/src/com/android/bluetooth/tests/SdpManagerTestServer.java
+++ b/tests/src/com/android/bluetooth/tests/SdpManagerTestServer.java
@@ -1,9 +1,6 @@
package com.android.bluetooth.tests;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
@@ -13,9 +10,12 @@ 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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -25,11 +25,6 @@ import android.util.Log;
import com.android.bluetooth.btservice.AbstractionLayer;
import com.android.bluetooth.sdp.SdpManager;
-import com.android.bluetooth.sdp.SdpMasRecord;
-import com.android.bluetooth.sdp.SdpMnsRecord;
-import com.android.bluetooth.sdp.SdpOppOpsRecord;
-import com.android.bluetooth.sdp.SdpPseRecord;
-import com.android.bluetooth.tests.ObexTest.TestSequencer.SeqStep;
/**
* We use an OBEX server to execute SDP search operations, and validate results.
@@ -64,7 +59,7 @@ public class SdpManagerTestServer extends ServerRequestHandler {
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
- index = ((Long)request.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onConnect - aborting...");
@@ -80,7 +75,7 @@ public class SdpManagerTestServer extends ServerRequestHandler {
int index;
int result = ResponseCodes.OBEX_HTTP_OK;
try {
- index = ((Long)request.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ index = ((Long)request.getHeader(TestSequencer.STEP_INDEX_HEADER)).intValue();
mOperationIndex = index;
} catch (IOException e) {
Log.e(TAG, "Exception in onDisconnect...");
@@ -122,7 +117,7 @@ public class SdpManagerTestServer extends ServerRequestHandler {
mResult = ResponseCodes.OBEX_HTTP_OK;
try{
HeaderSet reqHeaders = operation.getReceivedHeader();
- int index = ((Long)reqHeaders.getHeader(ObexTest.STEP_INDEX_HEADER)).intValue();
+ 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();
diff --git a/tests/src/com/android/bluetooth/tests/SeqStep.java b/tests/src/com/android/bluetooth/tests/SeqStep.java
new file mode 100644
index 000000000..3f6772a5c
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/SeqStep.java
@@ -0,0 +1,88 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.obex.HeaderSet;
+import javax.obex.ObexPacket;
+import javax.obex.Operation;
+
+import junit.framework.Assert;
+
+import com.android.bluetooth.tests.TestSequencer.OPTYPE;
+
+public class SeqStep {
+ /**
+ * Test step class to define the operations to be tested.
+ * Some of the data in these test steps will be modified during
+ * test - e.g. the HeaderSets will be modified to enable SRM
+ * and/or carry test information
+ */
+ /* Operation type - Connect, Get, Put etc. */
+ public OPTYPE mType;
+ /* The headers to send in the request - and validate on server side */
+ public HeaderSet mReqHeaders = null;
+ /* The headers to send in the response - and validate on client side */
+ public HeaderSet mResHeaders = null;
+ /* Use SRM */
+ public boolean mUseSrm = false;
+ /* The amount of data to include in the body */
+ public ObexTestParams mParams = null;
+ /* The offset into the data where the un-pause signal is to be sent */
+ public int mUnPauseOffset = -1;
+ /* The offset into the data where the Abort request is to be sent */
+ public int mAbortOffset = -1;
+ /* The side to perform Abort */
+ public boolean mServerSideAbout = false;
+ /* The ID of the test step */
+ private int mId;
+
+ public boolean mSetPathBackup = false; /* bit 0 in flags */
+ public boolean mSetPathCreate = false; /* Inverse of bit 1 in flags */
+
+
+ public ISeqStepValidator mValidator = null;
+ public ISeqStepAction mServerPreAction = null;
+ public ISeqStepAction mClientPostAction = null;
+
+ /* Arrays to hold expected sequence of request/response packets. */
+ public ArrayList<ObexPacket> mRequestPackets = null;
+ public ArrayList<ObexPacket> mResponsePackets = null;
+
+ public int index = 0; /* requests with same index are executed in parallel
+ (without waiting for a response) */
+
+ public SeqStep(OPTYPE type) {
+ mRequestPackets = new ArrayList<ObexPacket>();
+ mResponsePackets = new ArrayList<ObexPacket>();
+ mType = type;
+ }
+
+ public boolean validate(HeaderSet response, Operation op) throws IOException {
+ Assert.assertNotNull(mValidator);
+ return mValidator.validate(this, response, op);
+ }
+
+ public void serverPreAction(HeaderSet request, Operation op) throws IOException {
+ if(mServerPreAction != null) {
+ mServerPreAction.execute(this, request, op);
+ }
+ }
+
+ public void clientPostAction(HeaderSet response, Operation op) throws IOException {
+ if(mClientPostAction != null) {
+ mClientPostAction.execute(this, response, op);
+ }
+ }
+
+
+ /* TODO: Consider to build these automatically based on the operations
+ * to be performed. Validate using utility functions - not strict
+ * binary compare.
+ *
+ * OR simply remove!*/
+ public void addObexPacketSet(ObexPacket request, ObexPacket response) {
+ mRequestPackets.add(request);
+ mResponsePackets.add(response);
+ }
+}
diff --git a/tests/src/com/android/bluetooth/tests/TestSequencer.java b/tests/src/com/android/bluetooth/tests/TestSequencer.java
new file mode 100644
index 000000000..fb0dcbae8
--- /dev/null
+++ b/tests/src/com/android/bluetooth/tests/TestSequencer.java
@@ -0,0 +1,284 @@
+package com.android.bluetooth.tests;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+
+import javax.obex.ClientSession;
+import javax.obex.HeaderSet;
+import javax.obex.ObexTransport;
+import javax.obex.Operation;
+import javax.obex.ServerSession;
+
+import junit.framework.Assert;
+
+import android.content.Context;
+import android.hardware.camera2.impl.GetCommand;
+import android.os.Handler;
+import android.os.Handler.Callback;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.PowerManager;
+import android.util.Log;
+
+public class TestSequencer implements Callback {
+ protected static String TAG = "TestSequencer";
+ protected static final boolean D = true;
+
+ private final static int MSG_ID_TIMEOUT = 0x01;
+ private final static int TIMEOUT_VALUE = 100*2000; // ms
+ private ArrayList<SeqStep> mSequence = null;
+ private HandlerThread mHandlerThread = null;
+ private Handler mMessageHandler = null;
+ private ObexTransport mClientTransport;
+ private ObexTransport mServerTransport;
+
+ private ClientSession mClientSession = null;
+ private ServerSession mServerSession = null;
+ public static final int STEP_INDEX_HEADER = 0xF1; /*0xFE*/
+
+ public enum OPTYPE {CONNECT, PUT, GET, SET_PATH, DISCONNECT};
+
+ private ITestSequenceConfigurator mConfigurator = null;
+
+ public TestSequencer(ObexTransport clientTransport, ObexTransport serverTransport,
+ ITestSequenceConfigurator configurator)
+ throws IOException {
+ /* Setup the looper thread to handle timeout messages */
+// mHandlerThread = new HandlerThread("TestTimeoutHandler",
+// android.os.Process.THREAD_PRIORITY_BACKGROUND);
+// mHandlerThread.start();
+// Looper testLooper = mHandlerThread.getLooper();
+// mMessageHandler = new Handler(testLooper, this);
+ //TODO: fix looper cleanup on server - crash after 464 iterations - related to prepare?
+
+ mClientTransport = clientTransport;
+ mServerTransport = serverTransport;
+
+ /* Initialize members */
+ mSequence = new ArrayList<SeqStep>();
+ mConfigurator = configurator;
+ Assert.assertNotNull(configurator);
+ }
+
+ /**
+ * Add a test step to the sequencer.
+ * @param type the OBEX operation to perform.
+ * @return the created step, which can be decorated before execution.
+ */
+ public SeqStep addStep(OPTYPE type, ISeqStepValidator validator) {
+ SeqStep newStep = new SeqStep(type);
+ newStep.mValidator = validator;
+ mSequence.add(newStep);
+ return newStep;
+ }
+
+ /**
+ * Add a sub-step to a sequencer step. All requests added to the same index will be send to
+ * the SapServer in the order added before listening for the response.
+ * The response order is not validated - hence for each response received the entire list of
+ * responses in the step will be searched for a match.
+ * @param index the index returned from addStep() to which the sub-step is to be added.
+ * @param request The request to send to the SAP server
+ * @param response The response to EXPECT from the SAP server
+
+ public void addSubStep(int index, SapMessage request, SapMessage response) {
+ SeqStep step = sequence.get(index);
+ step.add(request, response);
+ }*/
+
+
+ /**
+ * Run the sequence.
+ * Validate the response is either the expected response or one of the expected events.
+ *
+ * @return true when done - asserts at error/fail
+ */
+ public boolean run(Context context) throws IOException {
+ CountDownLatch stopLatch = new CountDownLatch(1);
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ //wl.acquire();
+ try {
+ /* TODO:
+ * First create sequencer to validate using BT-snoop
+ * 1) Create the transports (this could include a validation sniffer on each side)
+ * 2) Create a server thread with a link to the transport
+ * 3) execute the client operation
+ * 4) validate response
+ *
+ * On server:
+ * 1) validate the request contains the expected content
+ * 2) send response.
+ * */
+
+ /* Create the server */
+ if(mServerTransport != null) {
+ mServerSession = new ServerSession(mServerTransport,
+ mConfigurator.getObexServer(mSequence, stopLatch) , null);
+ }
+
+ /* Create the client */
+ if(mClientTransport != null) {
+ mClientSession = new ClientSession(mClientTransport);
+
+ for(SeqStep step : mSequence) {
+ long stepIndex = mSequence.indexOf(step);
+
+ Log.i(TAG, "Executing step " + stepIndex + " of type: " + step.mType);
+
+ switch(step.mType) {
+ case CONNECT: {
+ HeaderSet reqHeaders = step.mReqHeaders;
+ if(reqHeaders == null) {
+ reqHeaders = new HeaderSet();
+ }
+ reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
+ HeaderSet response = mClientSession.connect(reqHeaders);
+ step.validate(response, null);
+ step.clientPostAction(response, null);
+ break;
+ }
+ case GET:{
+ HeaderSet reqHeaders = step.mReqHeaders;
+ if(reqHeaders == null) {
+ reqHeaders = new HeaderSet();
+ }
+ reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
+ Log.i(TAG, " Starting operation...");
+ Operation op = mClientSession.get(reqHeaders);
+ Log.i(TAG, " Operation done...");
+ step.validate(null, op);
+ step.clientPostAction(null, op);
+ break;
+ }
+ case PUT: {
+ HeaderSet reqHeaders = step.mReqHeaders;
+ if(reqHeaders == null) {
+ reqHeaders = new HeaderSet();
+ }
+ reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
+ Operation op = mClientSession.put(reqHeaders);
+ step.validate(null, op);
+ step.clientPostAction(null, op);
+ break;
+ }
+ case SET_PATH: {
+ HeaderSet reqHeaders = step.mReqHeaders;
+ if(reqHeaders == null) {
+ reqHeaders = new HeaderSet();
+ }
+ reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
+ try{
+ HeaderSet response = mClientSession.setPath(reqHeaders,
+ step.mSetPathBackup, step.mSetPathCreate);;
+ Log.i(TAG,"Received setPath response...");
+ step.validate(response, null);
+ step.clientPostAction(response, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error getting response code", e);
+ }
+ break;
+ }
+ case DISCONNECT: {
+ Log.i(TAG,"Requesting disconnect...");
+ HeaderSet reqHeaders = step.mReqHeaders;
+ if(reqHeaders == null) {
+ reqHeaders = new HeaderSet();
+ }
+ reqHeaders.setHeader(STEP_INDEX_HEADER, stepIndex);
+ try{
+ HeaderSet response = mClientSession.disconnect(reqHeaders);
+ Log.i(TAG,"Received disconnect response...");
+ step.validate(response, null);
+ step.clientPostAction(response, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error getting response code", e);
+ }
+ break;
+ }
+ default:
+ Assert.assertTrue("Unknown type: " + step.mType, false);
+ break;
+
+ }
+ }
+ mClientSession.close();
+ }
+ /* All done, close down... */
+ if(mServerSession != null) {
+ boolean interrupted = false;
+ do {
+ try {
+ interrupted = false;
+ Log.i(TAG,"Waiting for stopLatch signal...");
+ stopLatch.await();
+ } catch (InterruptedException e) {
+ Log.w(TAG,e);
+ interrupted = true;
+ }
+ } while (interrupted == true);
+ Log.i(TAG,"stopLatch signal received closing down...");
+ try {
+ interrupted = false;
+ Log.i(TAG," Sleep 50ms to allow disconnect signal to be send before closing.");
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ Log.w(TAG,e);
+ interrupted = true;
+ }
+ mServerSession.close();
+ }
+ // this will close the I/O streams as well.
+ } finally {
+ //wl.release();
+ }
+ return true;
+ }
+
+ public void shutdown() {
+// mMessageHandler.removeCallbacksAndMessages(null);
+// mMessageHandler.quit();
+// mMessageHandler = null;
+ }
+
+
+// private void startTimer() {
+// Message timeoutMessage = mMessageHandler.obtainMessage(MSG_ID_TIMEOUT);
+// mMessageHandler.sendMessageDelayed(timeoutMessage, TIMEOUT_VALUE);
+// }
+//
+// private void stopTimer() {
+// mMessageHandler.removeMessages(MSG_ID_TIMEOUT);
+// }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+
+ Log.i(TAG,"Handling message ID: " + msg.what);
+
+ switch(msg.what) {
+ case MSG_ID_TIMEOUT:
+ Log.w(TAG, "Timeout occured!");
+/* try {
+ //inStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "failed to close inStream", e);
+ }
+ try {
+ //outStream.close();
+ } catch (IOException e) {
+ Log.e(TAG, "failed to close outStream", e);
+ }*/
+ break;
+ default:
+ /* Message not handled */
+ return false;
+ }
+ return true; // Message handles
+ }
+
+
+
+}
+