Loading framework/java/android/bluetooth/BluetoothMapClient.java +69 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,18 @@ public final class BluetoothMapClient implements BluetoothProfile { public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY = "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY"; /** * Action to notify read status changed */ public static final String ACTION_MESSAGE_READ_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED"; /** * Action to notify deleted status changed */ public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED"; /* Extras used in ACTION_MESSAGE_RECEIVED intent. * NOTE: HANDLE is only valid for a single session with the device. */ public static final String EXTRA_MESSAGE_HANDLE = Loading @@ -65,6 +77,25 @@ public final class BluetoothMapClient implements BluetoothProfile { public static final String EXTRA_SENDER_CONTACT_NAME = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; /** * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED * Contains the MAP message deleted status * Possible values are: * true: deleted * false: undeleted */ public static final String EXTRA_MESSAGE_DELETED_STATUS = "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS"; /** * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED * Possible values are: * 0: failure * 1: success */ public static final String EXTRA_RESULT_CODE = "android.bluetooth.device.extra.RESULT_CODE"; /** There was an error trying to obtain the state */ public static final int STATE_ERROR = -1; Loading @@ -75,6 +106,12 @@ public final class BluetoothMapClient implements BluetoothProfile { private static final int UPLOADING_FEATURE_BITMASK = 0x08; /** Parameters in setMessageStatus */ public static final int UNREAD = 0; public static final int READ = 1; public static final int UNDELETED = 2; public static final int DELETED = 3; private BluetoothAdapter mAdapter; private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT, Loading Loading @@ -405,6 +442,38 @@ public final class BluetoothMapClient implements BluetoothProfile { return false; } /** * Set message status of message on MSE * <p> * When read status changed, the result will be published via * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED} * When deleted status changed, the result will be published via * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED} * * @param device Bluetooth device * @param handle message handle * @param status <code>UNREAD</code> for "unread", <code>READ</code> for * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for * "deleted", otherwise return error * @return <code>true</code> if request has been sent, <code>false</code> on error * */ @RequiresPermission(Manifest.permission.READ_SMS) public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")"); final IBluetoothMapClient service = getService(); if (service != null && isEnabled() && isValidDevice(device) && handle != null && (status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) { try { return service.setMessageStatus(device, handle, status); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); return false; } } return false; } private boolean isEnabled() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true; Loading framework/tests/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -15,14 +15,18 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.bluetooth.tests" > package="com.android.bluetooth.tests" android:sharedUserId="android.uid.bluetooth" > <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> Loading framework/tests/src/android/bluetooth/BluetoothStressTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,30 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.unpair(mAdapter, device); } /* Make sure there is at least 1 unread message in the last week on remote device */ public void testMceSetMessageStatus() { int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations; if (iterations == 0) { return; } BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null); mTestUtils.mceGetUnreadMessage(mAdapter, device); for (int i = 0; i < iterations; i++) { mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ); mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD); } /** * It is hard to find device to support set undeleted status, so just * set deleted in 1 iteration **/ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED); } private void sleep(long time) { try { Thread.sleep(time); Loading framework/tests/src/android/bluetooth/BluetoothTestRunner.java +11 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.util.Log; * [-e connect_input_iterations <iterations>] \ * [-e connect_pan_iterations <iterations>] \ * [-e start_stop_sco_iterations <iterations>] \ * [-e mce_set_message_status_iterations <iterations>] \ * [-e pair_address <address>] \ * [-e headset_address <address>] \ * [-e a2dp_address <address>] \ Loading @@ -64,6 +65,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { public static int sConnectInputIterations = 100; public static int sConnectPanIterations = 100; public static int sStartStopScoIterations = 100; public static int sMceSetMessageStatusIterations = 100; public static String sDeviceAddress = ""; public static byte[] sDevicePairPin = {'1', '2', '3', '4'}; Loading Loading @@ -173,6 +175,15 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { } } val = arguments.getString("mce_set_message_status_iterations"); if (val != null) { try { sMceSetMessageStatusIterations = Integer.parseInt(val); } catch (NumberFormatException e) { // Invalid argument, fall back to default value } } val = arguments.getString("device_address"); if (val != null) { sDeviceAddress = val; Loading framework/tests/src/android/bluetooth/BluetoothTestUtils.java +154 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,10 @@ public class BluetoothTestUtils extends Assert { private static final int CONNECT_PROXY_TIMEOUT = 5000; /** Time between polls in ms. */ private static final int POLL_TIME = 100; /** Timeout to get map message in ms. */ private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000; /** Timeout to set map message status in ms. */ private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000; private abstract class FlagReceiver extends BroadcastReceiver { private int mExpectedFlags = 0; Loading Loading @@ -98,6 +102,8 @@ public class BluetoothTestUtils extends Assert { private static final int STATE_TURNING_ON_FLAG = 1 << 6; private static final int STATE_ON_FLAG = 1 << 7; private static final int STATE_TURNING_OFF_FLAG = 1 << 8; private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9; private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10; public BluetoothReceiver(int expectedFlags) { super(expectedFlags); Loading Loading @@ -231,6 +237,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED; break; case BluetoothProfile.MAP_CLIENT: mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED; break; default: mConnectionAction = null; } Loading Loading @@ -308,6 +317,34 @@ public class BluetoothTestUtils extends Assert { } } private class MceSetMessageStatusReceiver extends FlagReceiver { private static final int MESSAGE_RECEIVED_FLAG = 1; private static final int STATUS_CHANGED_FLAG = 1 << 1; public MceSetMessageStatusReceiver(int expectedFlags) { super(expectedFlags); } @Override public void onReceive(Context context, Intent intent) { if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE); assertNotNull(handle); setFiredFlag(MESSAGE_RECEIVED_FLAG); mMsgHandle = handle; } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) { int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) { int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); } } } private BluetoothProfile.ServiceListener mServiceListener = new BluetoothProfile.ServiceListener() { @Override Loading @@ -326,6 +363,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mPan = (BluetoothPan) proxy; break; case BluetoothProfile.MAP_CLIENT: mMce = (BluetoothMapClient) proxy; break; } } } Loading @@ -346,6 +386,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mPan = null; break; case BluetoothProfile.MAP_CLIENT: mMce = null; break; } } } Loading @@ -362,6 +405,8 @@ public class BluetoothTestUtils extends Assert { private BluetoothHeadset mHeadset = null; private BluetoothHidHost mInput = null; private BluetoothPan mPan = null; private BluetoothMapClient mMce = null; private String mMsgHandle = null; /** * Creates a utility instance for testing Bluetooth. Loading Loading @@ -898,7 +943,7 @@ public class BluetoothTestUtils extends Assert { * @param adapter The BT adapter. * @param device The remote device. * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP}, * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}. * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}.. * @param methodName The method name to printed in the logs. If null, will be * "connectProfile(profile=<profile>, device=<device>)" */ Loading Loading @@ -941,6 +986,8 @@ public class BluetoothTestUtils extends Assert { assertTrue(((BluetoothHeadset)proxy).connect(device)); } else if (profile == BluetoothProfile.HID_HOST) { assertTrue(((BluetoothHidHost)proxy).connect(device)); } else if (profile == BluetoothProfile.MAP_CLIENT) { assertTrue(((BluetoothMapClient)proxy).connect(device)); } break; default: Loading Loading @@ -1016,6 +1063,8 @@ public class BluetoothTestUtils extends Assert { assertTrue(((BluetoothHeadset)proxy).disconnect(device)); } else if (profile == BluetoothProfile.HID_HOST) { assertTrue(((BluetoothHidHost)proxy).disconnect(device)); } else if (profile == BluetoothProfile.MAP_CLIENT) { assertTrue(((BluetoothMapClient)proxy).disconnect(device)); } break; case BluetoothProfile.STATE_DISCONNECTED: Loading Loading @@ -1373,6 +1422,89 @@ public class BluetoothTestUtils extends Assert { } } public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) { int mask; String methodName = "getUnreadMessage"; if (!adapter.isEnabled()) { fail(String.format("%s bluetooth not enabled", methodName)); } if (!adapter.getBondedDevices().contains(device)) { fail(String.format("%s device not paired", methodName)); } mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); assertNotNull(mMce); if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { fail(String.format("%s device is not connected", methodName)); } mMsgHandle = null; mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG; MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); assertTrue(mMce.getUnreadMessages(device)); long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) { if ((receiver.getFiredFlags() & mask) == mask) { writeOutput(String.format("%s completed", methodName)); removeReceiver(receiver); return; } sleep(POLL_TIME); } int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask)); } /** * Set a message to read/unread/deleted/undeleted */ public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) { int mask; String methodName = "setMessageStatus"; if (!adapter.isEnabled()) { fail(String.format("%s bluetooth not enabled", methodName)); } if (!adapter.getBondedDevices().contains(device)) { fail(String.format("%s device not paired", methodName)); } mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); assertNotNull(mMce); if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { fail(String.format("%s device is not connected", methodName)); } assertNotNull(mMsgHandle); mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG; MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); assertTrue(mMce.setMessageStatus(device, mMsgHandle, status)); long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) { if ((receiver.getFiredFlags() & mask) == mask) { writeOutput(String.format("%s completed", methodName)); removeReceiver(receiver); return; } sleep(POLL_TIME); } int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask)); } private void addReceiver(BroadcastReceiver receiver, String[] actions) { IntentFilter filter = new IntentFilter(); for (String action: actions) { Loading Loading @@ -1408,7 +1540,8 @@ public class BluetoothTestUtils extends Assert { String[] actions = { BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED}; BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED}; ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile, expectedFlags); addReceiver(receiver, actions); Loading @@ -1430,6 +1563,16 @@ public class BluetoothTestUtils extends Assert { return receiver; } private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device, int expectedFlags) { String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED, BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED, BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED}; MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags); addReceiver(receiver, actions); return receiver; } private void removeReceiver(BroadcastReceiver receiver) { mContext.unregisterReceiver(receiver); mReceivers.remove(receiver); Loading @@ -1456,6 +1599,10 @@ public class BluetoothTestUtils extends Assert { if (mPan != null) { return mPan; } case BluetoothProfile.MAP_CLIENT: if (mMce != null) { return mMce; } break; default: return null; Loading Loading @@ -1483,6 +1630,11 @@ public class BluetoothTestUtils extends Assert { sleep(POLL_TIME); } return mPan; case BluetoothProfile.MAP_CLIENT: while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { sleep(POLL_TIME); } return mMce; default: return null; } Loading Loading
framework/java/android/bluetooth/BluetoothMapClient.java +69 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,18 @@ public final class BluetoothMapClient implements BluetoothProfile { public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY = "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY"; /** * Action to notify read status changed */ public static final String ACTION_MESSAGE_READ_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED"; /** * Action to notify deleted status changed */ public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED = "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED"; /* Extras used in ACTION_MESSAGE_RECEIVED intent. * NOTE: HANDLE is only valid for a single session with the device. */ public static final String EXTRA_MESSAGE_HANDLE = Loading @@ -65,6 +77,25 @@ public final class BluetoothMapClient implements BluetoothProfile { public static final String EXTRA_SENDER_CONTACT_NAME = "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME"; /** * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED * Contains the MAP message deleted status * Possible values are: * true: deleted * false: undeleted */ public static final String EXTRA_MESSAGE_DELETED_STATUS = "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS"; /** * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED * Possible values are: * 0: failure * 1: success */ public static final String EXTRA_RESULT_CODE = "android.bluetooth.device.extra.RESULT_CODE"; /** There was an error trying to obtain the state */ public static final int STATE_ERROR = -1; Loading @@ -75,6 +106,12 @@ public final class BluetoothMapClient implements BluetoothProfile { private static final int UPLOADING_FEATURE_BITMASK = 0x08; /** Parameters in setMessageStatus */ public static final int UNREAD = 0; public static final int READ = 1; public static final int UNDELETED = 2; public static final int DELETED = 3; private BluetoothAdapter mAdapter; private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT, Loading Loading @@ -405,6 +442,38 @@ public final class BluetoothMapClient implements BluetoothProfile { return false; } /** * Set message status of message on MSE * <p> * When read status changed, the result will be published via * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED} * When deleted status changed, the result will be published via * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED} * * @param device Bluetooth device * @param handle message handle * @param status <code>UNREAD</code> for "unread", <code>READ</code> for * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for * "deleted", otherwise return error * @return <code>true</code> if request has been sent, <code>false</code> on error * */ @RequiresPermission(Manifest.permission.READ_SMS) public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")"); final IBluetoothMapClient service = getService(); if (service != null && isEnabled() && isValidDevice(device) && handle != null && (status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) { try { return service.setMessageStatus(device, handle, status); } catch (RemoteException e) { Log.e(TAG, Log.getStackTraceString(new Throwable())); return false; } } return false; } private boolean isEnabled() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true; Loading
framework/tests/AndroidManifest.xml +5 −1 Original line number Diff line number Diff line Loading @@ -15,14 +15,18 @@ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.bluetooth.tests" > package="com.android.bluetooth.tests" android:sharedUserId="android.uid.bluetooth" > <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_SMS"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> Loading
framework/tests/src/android/bluetooth/BluetoothStressTest.java +24 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,30 @@ public class BluetoothStressTest extends InstrumentationTestCase { mTestUtils.unpair(mAdapter, device); } /* Make sure there is at least 1 unread message in the last week on remote device */ public void testMceSetMessageStatus() { int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations; if (iterations == 0) { return; } BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress); mTestUtils.enable(mAdapter); mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null); mTestUtils.mceGetUnreadMessage(mAdapter, device); for (int i = 0; i < iterations; i++) { mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ); mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD); } /** * It is hard to find device to support set undeleted status, so just * set deleted in 1 iteration **/ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED); } private void sleep(long time) { try { Thread.sleep(time); Loading
framework/tests/src/android/bluetooth/BluetoothTestRunner.java +11 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.util.Log; * [-e connect_input_iterations <iterations>] \ * [-e connect_pan_iterations <iterations>] \ * [-e start_stop_sco_iterations <iterations>] \ * [-e mce_set_message_status_iterations <iterations>] \ * [-e pair_address <address>] \ * [-e headset_address <address>] \ * [-e a2dp_address <address>] \ Loading @@ -64,6 +65,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { public static int sConnectInputIterations = 100; public static int sConnectPanIterations = 100; public static int sStartStopScoIterations = 100; public static int sMceSetMessageStatusIterations = 100; public static String sDeviceAddress = ""; public static byte[] sDevicePairPin = {'1', '2', '3', '4'}; Loading Loading @@ -173,6 +175,15 @@ public class BluetoothTestRunner extends InstrumentationTestRunner { } } val = arguments.getString("mce_set_message_status_iterations"); if (val != null) { try { sMceSetMessageStatusIterations = Integer.parseInt(val); } catch (NumberFormatException e) { // Invalid argument, fall back to default value } } val = arguments.getString("device_address"); if (val != null) { sDeviceAddress = val; Loading
framework/tests/src/android/bluetooth/BluetoothTestUtils.java +154 −2 Original line number Diff line number Diff line Loading @@ -56,6 +56,10 @@ public class BluetoothTestUtils extends Assert { private static final int CONNECT_PROXY_TIMEOUT = 5000; /** Time between polls in ms. */ private static final int POLL_TIME = 100; /** Timeout to get map message in ms. */ private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000; /** Timeout to set map message status in ms. */ private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000; private abstract class FlagReceiver extends BroadcastReceiver { private int mExpectedFlags = 0; Loading Loading @@ -98,6 +102,8 @@ public class BluetoothTestUtils extends Assert { private static final int STATE_TURNING_ON_FLAG = 1 << 6; private static final int STATE_ON_FLAG = 1 << 7; private static final int STATE_TURNING_OFF_FLAG = 1 << 8; private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9; private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10; public BluetoothReceiver(int expectedFlags) { super(expectedFlags); Loading Loading @@ -231,6 +237,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED; break; case BluetoothProfile.MAP_CLIENT: mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED; break; default: mConnectionAction = null; } Loading Loading @@ -308,6 +317,34 @@ public class BluetoothTestUtils extends Assert { } } private class MceSetMessageStatusReceiver extends FlagReceiver { private static final int MESSAGE_RECEIVED_FLAG = 1; private static final int STATUS_CHANGED_FLAG = 1 << 1; public MceSetMessageStatusReceiver(int expectedFlags) { super(expectedFlags); } @Override public void onReceive(Context context, Intent intent) { if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) { String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE); assertNotNull(handle); setFiredFlag(MESSAGE_RECEIVED_FLAG); mMsgHandle = handle; } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) { int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) { int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE); assertEquals(result, BluetoothMapClient.RESULT_SUCCESS); setFiredFlag(STATUS_CHANGED_FLAG); } } } private BluetoothProfile.ServiceListener mServiceListener = new BluetoothProfile.ServiceListener() { @Override Loading @@ -326,6 +363,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mPan = (BluetoothPan) proxy; break; case BluetoothProfile.MAP_CLIENT: mMce = (BluetoothMapClient) proxy; break; } } } Loading @@ -346,6 +386,9 @@ public class BluetoothTestUtils extends Assert { case BluetoothProfile.PAN: mPan = null; break; case BluetoothProfile.MAP_CLIENT: mMce = null; break; } } } Loading @@ -362,6 +405,8 @@ public class BluetoothTestUtils extends Assert { private BluetoothHeadset mHeadset = null; private BluetoothHidHost mInput = null; private BluetoothPan mPan = null; private BluetoothMapClient mMce = null; private String mMsgHandle = null; /** * Creates a utility instance for testing Bluetooth. Loading Loading @@ -898,7 +943,7 @@ public class BluetoothTestUtils extends Assert { * @param adapter The BT adapter. * @param device The remote device. * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP}, * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}. * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}.. * @param methodName The method name to printed in the logs. If null, will be * "connectProfile(profile=<profile>, device=<device>)" */ Loading Loading @@ -941,6 +986,8 @@ public class BluetoothTestUtils extends Assert { assertTrue(((BluetoothHeadset)proxy).connect(device)); } else if (profile == BluetoothProfile.HID_HOST) { assertTrue(((BluetoothHidHost)proxy).connect(device)); } else if (profile == BluetoothProfile.MAP_CLIENT) { assertTrue(((BluetoothMapClient)proxy).connect(device)); } break; default: Loading Loading @@ -1016,6 +1063,8 @@ public class BluetoothTestUtils extends Assert { assertTrue(((BluetoothHeadset)proxy).disconnect(device)); } else if (profile == BluetoothProfile.HID_HOST) { assertTrue(((BluetoothHidHost)proxy).disconnect(device)); } else if (profile == BluetoothProfile.MAP_CLIENT) { assertTrue(((BluetoothMapClient)proxy).disconnect(device)); } break; case BluetoothProfile.STATE_DISCONNECTED: Loading Loading @@ -1373,6 +1422,89 @@ public class BluetoothTestUtils extends Assert { } } public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) { int mask; String methodName = "getUnreadMessage"; if (!adapter.isEnabled()) { fail(String.format("%s bluetooth not enabled", methodName)); } if (!adapter.getBondedDevices().contains(device)) { fail(String.format("%s device not paired", methodName)); } mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); assertNotNull(mMce); if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { fail(String.format("%s device is not connected", methodName)); } mMsgHandle = null; mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG; MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); assertTrue(mMce.getUnreadMessages(device)); long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) { if ((receiver.getFiredFlags() & mask) == mask) { writeOutput(String.format("%s completed", methodName)); removeReceiver(receiver); return; } sleep(POLL_TIME); } int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask)); } /** * Set a message to read/unread/deleted/undeleted */ public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) { int mask; String methodName = "setMessageStatus"; if (!adapter.isEnabled()) { fail(String.format("%s bluetooth not enabled", methodName)); } if (!adapter.getBondedDevices().contains(device)) { fail(String.format("%s device not paired", methodName)); } mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT); assertNotNull(mMce); if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) { fail(String.format("%s device is not connected", methodName)); } assertNotNull(mMsgHandle); mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG; MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask); assertTrue(mMce.setMessageStatus(device, mMsgHandle, status)); long s = System.currentTimeMillis(); while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) { if ((receiver.getFiredFlags() & mask) == mask) { writeOutput(String.format("%s completed", methodName)); removeReceiver(receiver); return; } sleep(POLL_TIME); } int firedFlags = receiver.getFiredFlags(); removeReceiver(receiver); fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)", methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask)); } private void addReceiver(BroadcastReceiver receiver, String[] actions) { IntentFilter filter = new IntentFilter(); for (String action: actions) { Loading Loading @@ -1408,7 +1540,8 @@ public class BluetoothTestUtils extends Assert { String[] actions = { BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED, BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED, BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED}; BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED, BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED}; ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile, expectedFlags); addReceiver(receiver, actions); Loading @@ -1430,6 +1563,16 @@ public class BluetoothTestUtils extends Assert { return receiver; } private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device, int expectedFlags) { String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED, BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED, BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED}; MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags); addReceiver(receiver, actions); return receiver; } private void removeReceiver(BroadcastReceiver receiver) { mContext.unregisterReceiver(receiver); mReceivers.remove(receiver); Loading @@ -1456,6 +1599,10 @@ public class BluetoothTestUtils extends Assert { if (mPan != null) { return mPan; } case BluetoothProfile.MAP_CLIENT: if (mMce != null) { return mMce; } break; default: return null; Loading Loading @@ -1483,6 +1630,11 @@ public class BluetoothTestUtils extends Assert { sleep(POLL_TIME); } return mPan; case BluetoothProfile.MAP_CLIENT: while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) { sleep(POLL_TIME); } return mMce; default: return null; } Loading