Loading src/com/android/bluetooth/mapclient/MapClientService.java +19 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,14 @@ public class MapClientService extends ProfileService { return mapStateMachine.getSupportedFeatures(); } public synchronized boolean setMessageStatus(BluetoothDevice device, String handle, int status) { MceStateMachine mapStateMachine = mMapInstanceMap.get(device); if (mapStateMachine == null) { return false; } return mapStateMachine.setMessageStatus(handle, status); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading Loading @@ -595,6 +603,17 @@ public class MapClientService extends ProfileService { "Need BLUETOOTH permission"); return service.getSupportedFeatures(device); } @Override public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { MapClientService service = getService(); if (service == null) { return false; } mService.enforceCallingOrSelfPermission(Manifest.permission.READ_SMS, "Need READ_SMS permission"); return service.setMessageStatus(device, handle, status); } } private class MapBroadcastReceiver extends BroadcastReceiver { Loading src/com/android/bluetooth/mapclient/MceStateMachine.java +86 −4 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ final class MceStateMachine extends StateMachine { static final int MSG_NOTIFICATION = 2003; static final int MSG_GET_LISTING = 2004; static final int MSG_GET_MESSAGE_LISTING = 2005; // Set message status to read or deleted static final int MSG_SET_MESSAGE_STATUS = 2006; private static final String TAG = "MceSM"; private static final Boolean DBG = MapClientService.DBG; Loading Loading @@ -336,6 +338,45 @@ final class MceStateMachine extends StateMachine { return 0; } synchronized boolean setMessageStatus(String handle, int status) { if (DBG) { Log.d(TAG, "setMessageStatus(" + handle + ", " + status + ")"); } if (this.getCurrentState() == mConnected) { RequestSetMessageStatus.StatusIndicator statusIndicator; byte value; switch (status) { case BluetoothMapClient.UNREAD: statusIndicator = RequestSetMessageStatus.StatusIndicator.READ; value = RequestSetMessageStatus.STATUS_NO; break; case BluetoothMapClient.READ: statusIndicator = RequestSetMessageStatus.StatusIndicator.READ; value = RequestSetMessageStatus.STATUS_YES; break; case BluetoothMapClient.UNDELETED: statusIndicator = RequestSetMessageStatus.StatusIndicator.DELETED; value = RequestSetMessageStatus.STATUS_NO; break; case BluetoothMapClient.DELETED: statusIndicator = RequestSetMessageStatus.StatusIndicator.DELETED; value = RequestSetMessageStatus.STATUS_YES; break; default: Log.e(TAG, "Invalid parameter for status" + status); return false; } sendMessage(MSG_SET_MESSAGE_STATUS, 0, 0, new RequestSetMessageStatus( handle, statusIndicator, value)); return true; } return false; } private String getContactURIFromPhone(String number) { return PhoneAccount.SCHEME_TEL + ":" + number; } Loading Loading @@ -518,6 +559,12 @@ final class MceStateMachine extends StateMachine { (String) message.obj, 0, filter, 0, 50, 0)); break; case MSG_SET_MESSAGE_STATUS: if (message.obj instanceof RequestSetMessageStatus) { mMasClient.makeRequest((RequestSetMessageStatus) message.obj); } break; case MSG_MAS_REQUEST_COMPLETED: if (DBG) { Log.d(TAG, "Completed request"); Loading @@ -538,6 +585,8 @@ final class MceStateMachine extends StateMachine { } } else if (message.obj instanceof RequestGetMessagesListing) { processMessageListing((RequestGetMessagesListing) message.obj); } else if (message.obj instanceof RequestSetMessageStatus) { processSetMessageStatus((RequestSetMessageStatus) message.obj); } break; Loading Loading @@ -614,15 +663,15 @@ final class MceStateMachine extends StateMachine { if (DBG) Log.d(TAG, "markMessageRead"); MessageMetadata metadata = mMessages.get(request.getHandle()); metadata.setRead(true); mMasClient.makeRequest(new RequestSetMessageStatus( request.getHandle(), RequestSetMessageStatus.StatusIndicator.READ)); mMasClient.makeRequest(new RequestSetMessageStatus(request.getHandle(), RequestSetMessageStatus.StatusIndicator.READ, RequestSetMessageStatus.STATUS_YES)); } // Sets the specified message status to "deleted" private void markMessageDeleted(RequestGetMessage request) { if (DBG) Log.d(TAG, "markMessageDeleted"); mMasClient.makeRequest(new RequestSetMessageStatus( request.getHandle(), RequestSetMessageStatus.StatusIndicator.DELETED)); mMasClient.makeRequest(new RequestSetMessageStatus(request.getHandle(), RequestSetMessageStatus.StatusIndicator.DELETED, RequestSetMessageStatus.STATUS_YES)); } /** Loading Loading @@ -653,6 +702,39 @@ final class MceStateMachine extends StateMachine { } } private void processSetMessageStatus(RequestSetMessageStatus request) { if (DBG) { Log.d(TAG, "processSetMessageStatus"); } int result = BluetoothMapClient.RESULT_SUCCESS; if (!request.isSuccess()) { Log.e(TAG, "Set message status failed"); result = BluetoothMapClient.RESULT_FAILURE; } Intent intent; RequestSetMessageStatus.StatusIndicator status = request.getStatusIndicator(); switch (status) { case READ: intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED); intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_READ_STATUS, request.getValue() == RequestSetMessageStatus.STATUS_YES ? true : false); break; case DELETED: intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED); intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_DELETED_STATUS, request.getValue() == RequestSetMessageStatus.STATUS_YES ? true : false); break; default: Log.e(TAG, "Unknown status indicator " + status); return; } intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE, request.getHandle()); intent.putExtra(BluetoothMapClient.EXTRA_RESULT_CODE, result); mService.sendBroadcast(intent); } /** * Given the response of a GetMessage request, will broadcast the bMessage contents on to * all registered applications. Loading src/com/android/bluetooth/mapclient/obex/RequestSetMessageStatus.java +27 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.mapclient; import android.util.Log; import java.io.IOException; import javax.obex.ClientSession; Loading @@ -23,10 +25,12 @@ import javax.obex.HeaderSet; final class RequestSetMessageStatus extends Request { public enum StatusIndicator { READ, DELETED } private static final String TAG = "RequestSetMessageStatus"; private static final String TYPE = "x-bt/messageStatus"; private static StatusIndicator mStatusInd; private static byte mValue; public RequestSetMessageStatus(String handle, StatusIndicator statusInd) { public RequestSetMessageStatus(String handle, StatusIndicator statusInd, byte value) { mHeaderSet.setHeader(HeaderSet.TYPE, TYPE); mHeaderSet.setHeader(HeaderSet.NAME, handle); Loading @@ -34,8 +38,28 @@ final class RequestSetMessageStatus extends Request { oap.add(OAP_TAGID_STATUS_INDICATOR, statusInd == StatusIndicator.READ ? STATUS_INDICATOR_READ : STATUS_INDICATOR_DELETED); oap.add(OAP_TAGID_STATUS_VALUE, STATUS_YES); oap.add(OAP_TAGID_STATUS_VALUE, value == STATUS_YES ? STATUS_YES : STATUS_NO); oap.addToHeaderSet(mHeaderSet); mStatusInd = statusInd; mValue = value; } public StatusIndicator getStatusIndicator() { return mStatusInd; } public byte getValue() { return mValue; } public String getHandle() { try { return (String) mHeaderSet.getHeader(HeaderSet.NAME); } catch (IOException e) { Log.e(TAG, "Unexpected exception while reading handle!", e); return null; } } @Override Loading tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothMapClient; import android.bluetooth.BluetoothProfile; import android.bluetooth.SdpMasRecord; import android.content.Context; Loading Loading @@ -203,6 +204,25 @@ public class MapClientStateMachineTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); } /** * Test set message status */ @Test public void testSetMessageStatus() { setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); Assert.assertTrue(mMceStateMachine.setMessageStatus("123456789AB", BluetoothMapClient.READ)); } private void setupSdpRecordReceipt() { // Perform first part of MAP connection logic. verify(mMockMapClientService, Loading Loading
src/com/android/bluetooth/mapclient/MapClientService.java +19 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,14 @@ public class MapClientService extends ProfileService { return mapStateMachine.getSupportedFeatures(); } public synchronized boolean setMessageStatus(BluetoothDevice device, String handle, int status) { MceStateMachine mapStateMachine = mMapInstanceMap.get(device); if (mapStateMachine == null) { return false; } return mapStateMachine.setMessageStatus(handle, status); } @Override public void dump(StringBuilder sb) { super.dump(sb); Loading Loading @@ -595,6 +603,17 @@ public class MapClientService extends ProfileService { "Need BLUETOOTH permission"); return service.getSupportedFeatures(device); } @Override public boolean setMessageStatus(BluetoothDevice device, String handle, int status) { MapClientService service = getService(); if (service == null) { return false; } mService.enforceCallingOrSelfPermission(Manifest.permission.READ_SMS, "Need READ_SMS permission"); return service.setMessageStatus(device, handle, status); } } private class MapBroadcastReceiver extends BroadcastReceiver { Loading
src/com/android/bluetooth/mapclient/MceStateMachine.java +86 −4 Original line number Diff line number Diff line Loading @@ -94,6 +94,8 @@ final class MceStateMachine extends StateMachine { static final int MSG_NOTIFICATION = 2003; static final int MSG_GET_LISTING = 2004; static final int MSG_GET_MESSAGE_LISTING = 2005; // Set message status to read or deleted static final int MSG_SET_MESSAGE_STATUS = 2006; private static final String TAG = "MceSM"; private static final Boolean DBG = MapClientService.DBG; Loading Loading @@ -336,6 +338,45 @@ final class MceStateMachine extends StateMachine { return 0; } synchronized boolean setMessageStatus(String handle, int status) { if (DBG) { Log.d(TAG, "setMessageStatus(" + handle + ", " + status + ")"); } if (this.getCurrentState() == mConnected) { RequestSetMessageStatus.StatusIndicator statusIndicator; byte value; switch (status) { case BluetoothMapClient.UNREAD: statusIndicator = RequestSetMessageStatus.StatusIndicator.READ; value = RequestSetMessageStatus.STATUS_NO; break; case BluetoothMapClient.READ: statusIndicator = RequestSetMessageStatus.StatusIndicator.READ; value = RequestSetMessageStatus.STATUS_YES; break; case BluetoothMapClient.UNDELETED: statusIndicator = RequestSetMessageStatus.StatusIndicator.DELETED; value = RequestSetMessageStatus.STATUS_NO; break; case BluetoothMapClient.DELETED: statusIndicator = RequestSetMessageStatus.StatusIndicator.DELETED; value = RequestSetMessageStatus.STATUS_YES; break; default: Log.e(TAG, "Invalid parameter for status" + status); return false; } sendMessage(MSG_SET_MESSAGE_STATUS, 0, 0, new RequestSetMessageStatus( handle, statusIndicator, value)); return true; } return false; } private String getContactURIFromPhone(String number) { return PhoneAccount.SCHEME_TEL + ":" + number; } Loading Loading @@ -518,6 +559,12 @@ final class MceStateMachine extends StateMachine { (String) message.obj, 0, filter, 0, 50, 0)); break; case MSG_SET_MESSAGE_STATUS: if (message.obj instanceof RequestSetMessageStatus) { mMasClient.makeRequest((RequestSetMessageStatus) message.obj); } break; case MSG_MAS_REQUEST_COMPLETED: if (DBG) { Log.d(TAG, "Completed request"); Loading @@ -538,6 +585,8 @@ final class MceStateMachine extends StateMachine { } } else if (message.obj instanceof RequestGetMessagesListing) { processMessageListing((RequestGetMessagesListing) message.obj); } else if (message.obj instanceof RequestSetMessageStatus) { processSetMessageStatus((RequestSetMessageStatus) message.obj); } break; Loading Loading @@ -614,15 +663,15 @@ final class MceStateMachine extends StateMachine { if (DBG) Log.d(TAG, "markMessageRead"); MessageMetadata metadata = mMessages.get(request.getHandle()); metadata.setRead(true); mMasClient.makeRequest(new RequestSetMessageStatus( request.getHandle(), RequestSetMessageStatus.StatusIndicator.READ)); mMasClient.makeRequest(new RequestSetMessageStatus(request.getHandle(), RequestSetMessageStatus.StatusIndicator.READ, RequestSetMessageStatus.STATUS_YES)); } // Sets the specified message status to "deleted" private void markMessageDeleted(RequestGetMessage request) { if (DBG) Log.d(TAG, "markMessageDeleted"); mMasClient.makeRequest(new RequestSetMessageStatus( request.getHandle(), RequestSetMessageStatus.StatusIndicator.DELETED)); mMasClient.makeRequest(new RequestSetMessageStatus(request.getHandle(), RequestSetMessageStatus.StatusIndicator.DELETED, RequestSetMessageStatus.STATUS_YES)); } /** Loading Loading @@ -653,6 +702,39 @@ final class MceStateMachine extends StateMachine { } } private void processSetMessageStatus(RequestSetMessageStatus request) { if (DBG) { Log.d(TAG, "processSetMessageStatus"); } int result = BluetoothMapClient.RESULT_SUCCESS; if (!request.isSuccess()) { Log.e(TAG, "Set message status failed"); result = BluetoothMapClient.RESULT_FAILURE; } Intent intent; RequestSetMessageStatus.StatusIndicator status = request.getStatusIndicator(); switch (status) { case READ: intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED); intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_READ_STATUS, request.getValue() == RequestSetMessageStatus.STATUS_YES ? true : false); break; case DELETED: intent = new Intent(BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED); intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_DELETED_STATUS, request.getValue() == RequestSetMessageStatus.STATUS_YES ? true : false); break; default: Log.e(TAG, "Unknown status indicator " + status); return; } intent.putExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE, request.getHandle()); intent.putExtra(BluetoothMapClient.EXTRA_RESULT_CODE, result); mService.sendBroadcast(intent); } /** * Given the response of a GetMessage request, will broadcast the bMessage contents on to * all registered applications. Loading
src/com/android/bluetooth/mapclient/obex/RequestSetMessageStatus.java +27 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.mapclient; import android.util.Log; import java.io.IOException; import javax.obex.ClientSession; Loading @@ -23,10 +25,12 @@ import javax.obex.HeaderSet; final class RequestSetMessageStatus extends Request { public enum StatusIndicator { READ, DELETED } private static final String TAG = "RequestSetMessageStatus"; private static final String TYPE = "x-bt/messageStatus"; private static StatusIndicator mStatusInd; private static byte mValue; public RequestSetMessageStatus(String handle, StatusIndicator statusInd) { public RequestSetMessageStatus(String handle, StatusIndicator statusInd, byte value) { mHeaderSet.setHeader(HeaderSet.TYPE, TYPE); mHeaderSet.setHeader(HeaderSet.NAME, handle); Loading @@ -34,8 +38,28 @@ final class RequestSetMessageStatus extends Request { oap.add(OAP_TAGID_STATUS_INDICATOR, statusInd == StatusIndicator.READ ? STATUS_INDICATOR_READ : STATUS_INDICATOR_DELETED); oap.add(OAP_TAGID_STATUS_VALUE, STATUS_YES); oap.add(OAP_TAGID_STATUS_VALUE, value == STATUS_YES ? STATUS_YES : STATUS_NO); oap.addToHeaderSet(mHeaderSet); mStatusInd = statusInd; mValue = value; } public StatusIndicator getStatusIndicator() { return mStatusInd; } public byte getValue() { return mValue; } public String getHandle() { try { return (String) mHeaderSet.getHeader(HeaderSet.NAME); } catch (IOException e) { Log.e(TAG, "Unexpected exception while reading handle!", e); return null; } } @Override Loading
tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothMapClient; import android.bluetooth.BluetoothProfile; import android.bluetooth.SdpMasRecord; import android.content.Context; Loading Loading @@ -203,6 +204,25 @@ public class MapClientStateMachineTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); } /** * Test set message status */ @Test public void testSetMessageStatus() { setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); Assert.assertTrue(mMceStateMachine.setMessageStatus("123456789AB", BluetoothMapClient.READ)); } private void setupSdpRecordReceipt() { // Perform first part of MAP connection logic. verify(mMockMapClientService, Loading