Loading android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +26 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,10 @@ public class HearingAidService extends ProfileService { mStateMachinesThread = new HandlerThread("HearingAidService.StateMachines"); mStateMachinesThread.start(); // Clear HiSyncId map and capabilities map mDeviceHiSyncIdMap.clear(); mDeviceCapabilitiesMap.clear(); // Setup broadcast receivers IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); Loading Loading @@ -162,6 +166,10 @@ public class HearingAidService extends ProfileService { mStateMachines.clear(); } // Clear HiSyncId map and capabilities map mDeviceHiSyncIdMap.clear(); mDeviceCapabilitiesMap.clear(); if (mStateMachinesThread != null) { mStateMachinesThread.quitSafely(); mStateMachinesThread = null; Loading Loading @@ -227,13 +235,26 @@ public class HearingAidService extends ProfileService { long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); if (hiSyncId != mActiveDeviceHiSyncId) { if (hiSyncId != mActiveDeviceHiSyncId && hiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID && mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) { for (BluetoothDevice connectedDevice : getConnectedDevices()) { disconnect(connectedDevice); } } synchronized (mStateMachines) { HearingAidStateMachine smConnect = getOrCreateStateMachine(device); if (smConnect == null) { Log.e(TAG, "Cannot connect to " + device + " : no state machine"); } smConnect.sendMessage(HearingAidStateMachine.CONNECT); } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (device.equals(storedDevice)) { continue; } if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { synchronized (mStateMachines) { Loading @@ -243,7 +264,6 @@ public class HearingAidService extends ProfileService { continue; } sm.sendMessage(HearingAidStateMachine.CONNECT); } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { Loading Loading @@ -511,6 +531,10 @@ public class HearingAidService extends ProfileService { BluetoothDevice device = stackEvent.device; int capabilities = stackEvent.valueInt1; long hiSyncId = stackEvent.valueLong2; if (DBG) { Log.d(TAG, "Device available: device=" + device + " capabilities=" + capabilities + " hiSyncId=" + hiSyncId); } mDeviceCapabilitiesMap.put(device, capabilities); mDeviceHiSyncIdMap.put(device, hiSyncId); return; Loading android/app/src/com/android/bluetooth/newavrcp/AvrcpNativeInterface.java +3 −0 Original line number Diff line number Diff line Loading @@ -186,11 +186,13 @@ public class AvrcpNativeInterface { } void setActiveDevice(String bdaddr) { bdaddr = bdaddr.toUpperCase(); d("setActiveDevice: bdaddr=" + bdaddr); mAvrcpService.setActiveDevice(bdaddr); } void deviceConnected(String bdaddr, boolean absoluteVolume) { bdaddr = bdaddr.toUpperCase(); d("deviceConnected: bdaddr=" + bdaddr + " absoluteVolume=" + absoluteVolume); if (mAvrcpService == null) { Log.w(TAG, "deviceConnected: AvrcpTargetService is null"); Loading @@ -201,6 +203,7 @@ public class AvrcpNativeInterface { } void deviceDisconnected(String bdaddr) { bdaddr = bdaddr.toUpperCase(); d("deviceDisconnected: bdaddr=" + bdaddr); if (mAvrcpService == null) { Log.w(TAG, "deviceDisconnected: AvrcpTargetService is null"); Loading android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java +1 −2 Original line number Diff line number Diff line Loading @@ -296,7 +296,7 @@ public class AvrcpTargetService extends ProfileService { void setActiveDevice(String address) { Log.i(TAG, "setActiveDevice: address=" + address); BluetoothDevice d = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address.toUpperCase()); BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); if (d == null) { Log.wtfStack(TAG, "setActiveDevice: could not find device with address " + address); } Loading @@ -320,7 +320,6 @@ public class AvrcpTargetService extends ProfileService { } mVolumeManager.dump(sb); sb.append("\n"); } private static class AvrcpTargetBinder extends IBluetoothAvrcpTarget.Stub Loading android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java +49 −45 Original line number Diff line number Diff line Loading @@ -44,21 +44,58 @@ class AvrcpVolumeManager { String mCurrentDeviceAddr = ""; boolean mAbsoluteVolumeSupported = false; int avrcpToSystemVolume(int avrcpVolume) { static int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.floor((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); } int systemToAvrcpVolume(int deviceVolume) { static int systemToAvrcpVolume(int deviceVolume) { int avrcpVolume = (int) Math.floor((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); if (avrcpVolume > 127) avrcpVolume = 127; return avrcpVolume; } SharedPreferences getVolumeMap() { private SharedPreferences getVolumeMap() { return mContext.getSharedPreferences(VOLUME_MAP, Context.MODE_PRIVATE); } private int getVolume(String bdaddr, int defaultValue) { if (!mVolumeMap.containsKey(bdaddr)) { Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + bdaddr); return defaultValue; } return mVolumeMap.get(bdaddr); } private void switchVolumeDevice(String bdaddr) { // Inform the audio manager that the device has changed mAudioManager.avrcpSupportsAbsoluteVolume(bdaddr, mDeviceMap.get(bdaddr)); // Get the current system volume and try to get the preference volume int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); int savedVolume = getVolume(bdaddr, currVolume); // If the preference volume isn't equal to the current stream volume then that means // we had a stored preference. if (DEBUG) { Log.d(TAG, "switchVolumeDevice: currVolume=" + currVolume + " savedVolume=" + savedVolume); } if (savedVolume != currVolume) { Log.i(TAG, "switchVolumeDevice: restoring volume level " + savedVolume); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, savedVolume, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); } // If absolute volume for the device is supported, set the volume for the device if (mDeviceMap.get(bdaddr)) { int avrcpVolume = systemToAvrcpVolume(savedVolume); Log.i(TAG, "switchVolumeDevice: Updating device volume: avrcpVolume=" + avrcpVolume); mNativeInterface.sendVolumeChanged(avrcpVolume); } } AvrcpVolumeManager(Context context, AudioManager audioManager, AvrcpNativeInterface nativeInterface) { mContext = context; Loading @@ -66,7 +103,7 @@ class AvrcpVolumeManager { mNativeInterface = nativeInterface; sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); // Load the volume map into a hash map since shared preferences are slow // Load the volume map into a hash map since shared preferences are slow to poll and update Map<String, ?> allKeys = getVolumeMap().getAll(); for (Map.Entry<String, ?> entry : allKeys.entrySet()) { String key = entry.getKey(); Loading @@ -77,15 +114,6 @@ class AvrcpVolumeManager { } } int getVolume(String bdaddr, int defaultValue) { if (!mVolumeMap.containsKey(bdaddr)) { Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + bdaddr); return defaultValue; } return mVolumeMap.get(bdaddr); } void storeVolume() { SharedPreferences.Editor pref = getVolumeMap().edit(); int storeVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); Loading @@ -101,18 +129,18 @@ class AvrcpVolumeManager { Log.d(TAG, "deviceConnected: bdaddr=" + bdaddr + " absoluteVolume=" + absoluteVolume); } mDeviceMap.put(bdaddr.toUpperCase(), absoluteVolume); mDeviceMap.put(bdaddr, absoluteVolume); // AVRCP features lookup has completed after the device became active. Switch to the new // device now. if (bdaddr == mCurrentDeviceAddr) { if (bdaddr.equals(mCurrentDeviceAddr)) { switchVolumeDevice(bdaddr); } } void volumeDeviceSwitched(String bdaddr) { if (DEBUG) { Log.d(TAG, "activeDeviceChanged: mCurrentDeviceAddr=" + mCurrentDeviceAddr Log.d(TAG, "volumeDeviceSwitched: mCurrentDeviceAddr=" + mCurrentDeviceAddr + " bdaddr=" + bdaddr); } Loading @@ -137,53 +165,29 @@ class AvrcpVolumeManager { // device supports absolute volume. Defer switching the device until AVRCP returns the // info. if (!mDeviceMap.containsKey(bdaddr)) { Log.w(TAG, "Device isn't connected: " + bdaddr); Log.w(TAG, "volumeDeviceSwitched: Device isn't connected: " + bdaddr); return; } switchVolumeDevice(bdaddr); } void switchVolumeDevice(String bdaddr) { // Inform the audio manager that the device has changed mAudioManager.avrcpSupportsAbsoluteVolume(bdaddr, mDeviceMap.get(bdaddr)); // Get the current system volume and try to get the preference volume int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); int savedVolume = getVolume(bdaddr, currVolume); // If the preference volume isn't equal to the current stream volume then that means // we had a stored preference. void deviceDisconnected(String bdaddr) { if (DEBUG) { Log.d(TAG, "activeDeviceChanged: currVolume=" + currVolume + " savedVolume=" + savedVolume); } if (savedVolume != currVolume) { mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, savedVolume, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); } // If absolute volume for the device is supported, set the volume for the device if (mDeviceMap.get(bdaddr)) { int avrcpVolume = systemToAvrcpVolume(savedVolume); Log.e(TAG, "activeDeviceChanged: Updating device volume: avrcpVolume=" + avrcpVolume); mNativeInterface.sendVolumeChanged(avrcpVolume); } Log.d(TAG, "deviceDisconnected: bdaddr=" + bdaddr); } void deviceDisconnected(String bdaddr) { Log.e(TAG, "deviceDisconnected: bdaddr=" + bdaddr); mDeviceMap.remove(bdaddr); } public void dump(StringBuilder sb) { sb.append("Bluetooth Device Volume Map:\n"); sb.append(" Device Address : Volume\n"); Map<String, ?> allKeys = getVolumeMap().getAll(); for (Map.Entry<String, ?> entry : allKeys.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (value instanceof Integer) { sb.append(" " + key + " - " + (Integer) value + "\n"); sb.append(" " + key + " : " + (Integer) value + "\n"); mVolumeMap.put(key, (Integer) value); } } Loading android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java +172 −20 Original line number Diff line number Diff line Loading @@ -115,19 +115,6 @@ public class HearingAidServiceTest { mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); HearingAidStackEvent event = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); event.device = mLeftDevice; event.valueInt1 = 0x02; event.valueLong2 = 0x0101; mService.messageFromNative(event); event.device = mRightDevice; event.valueInt1 = 0x03; mService.messageFromNative(event); event.device = mSingleDevice; event.valueInt1 = 0x00; event.valueLong2 = 0x0102; mService.messageFromNative(event); doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService) .getBondState(any(BluetoothDevice.class)); doReturn(new ParcelUuid[]{BluetoothUuid.HearingAid}).when(mAdapterService) Loading Loading @@ -408,8 +395,8 @@ public class HearingAidServiceTest { */ @Test public void testConnectAPair_connectBothDevices() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -436,8 +423,8 @@ public class HearingAidServiceTest { */ @Test public void testConnectAnotherPair_disconnectCurrentPair() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -454,7 +441,7 @@ public class HearingAidServiceTest { verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); Loading Loading @@ -496,8 +483,8 @@ public class HearingAidServiceTest { */ @Test public void testAudioManagerConnectDisconnect() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -519,6 +506,7 @@ public class HearingAidServiceTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); Loading Loading @@ -769,6 +757,8 @@ public class HearingAidServiceTest { @Test public void testConnectionStateChangedActiveDevice() { // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading Loading @@ -797,6 +787,8 @@ public class HearingAidServiceTest { @Test public void testConnectionStateChangedAnotherActiveDevice() { // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -819,6 +811,151 @@ public class HearingAidServiceTest { Assert.assertTrue(mService.getActiveDevices().contains(mSingleDevice)); } /** * Verify the correctness during first time connection. * Connect to left device -> Get left device hiSyncId -> Connect to right device -> * Get right device hiSyncId -> Both devices should be always connected */ @Test public void firstTimeConnection_shouldConnectToBothDevices() { // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request for left device Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId for left device HearingAidStackEvent hiSyncIdEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); hiSyncIdEvent.device = mLeftDevice; hiSyncIdEvent.valueInt1 = 0x02; hiSyncIdEvent.valueLong2 = 0x0101; mService.messageFromNative(hiSyncIdEvent); // Send a connect request for right device Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); // Verify the left device is still connected Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId for right device hiSyncIdEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); hiSyncIdEvent.device = mRightDevice; hiSyncIdEvent.valueInt1 = 0x02; hiSyncIdEvent.valueLong2 = 0x0101; mService.messageFromNative(hiSyncIdEvent); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); } /** * Get the HiSyncId from native stack after connecting to left device, then connect right */ @Test public void getHiSyncId_afterFirstDeviceConnected() { // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mRightDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId update from native stack getHiSyncIdFromNative(); // Send a connect request for right Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); // Verify the left device is still connected Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); } private void connectDevice(BluetoothDevice device) { HearingAidStackEvent connCompletedEvent; Loading Loading @@ -896,4 +1033,19 @@ public class HearingAidServiceTest { Assert.assertEquals(expected, mService.okToConnect(device)); } private void getHiSyncIdFromNative() { HearingAidStackEvent event = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); event.device = mLeftDevice; event.valueInt1 = 0x02; event.valueLong2 = 0x0101; mService.messageFromNative(event); event.device = mRightDevice; event.valueInt1 = 0x03; mService.messageFromNative(event); event.device = mSingleDevice; event.valueInt1 = 0x00; event.valueLong2 = 0x0102; mService.messageFromNative(event); } } Loading
android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +26 −2 Original line number Diff line number Diff line Loading @@ -111,6 +111,10 @@ public class HearingAidService extends ProfileService { mStateMachinesThread = new HandlerThread("HearingAidService.StateMachines"); mStateMachinesThread.start(); // Clear HiSyncId map and capabilities map mDeviceHiSyncIdMap.clear(); mDeviceCapabilitiesMap.clear(); // Setup broadcast receivers IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); Loading Loading @@ -162,6 +166,10 @@ public class HearingAidService extends ProfileService { mStateMachines.clear(); } // Clear HiSyncId map and capabilities map mDeviceHiSyncIdMap.clear(); mDeviceCapabilitiesMap.clear(); if (mStateMachinesThread != null) { mStateMachinesThread.quitSafely(); mStateMachinesThread = null; Loading Loading @@ -227,13 +235,26 @@ public class HearingAidService extends ProfileService { long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); if (hiSyncId != mActiveDeviceHiSyncId) { if (hiSyncId != mActiveDeviceHiSyncId && hiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID && mActiveDeviceHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) { for (BluetoothDevice connectedDevice : getConnectedDevices()) { disconnect(connectedDevice); } } synchronized (mStateMachines) { HearingAidStateMachine smConnect = getOrCreateStateMachine(device); if (smConnect == null) { Log.e(TAG, "Cannot connect to " + device + " : no state machine"); } smConnect.sendMessage(HearingAidStateMachine.CONNECT); } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (device.equals(storedDevice)) { continue; } if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { synchronized (mStateMachines) { Loading @@ -243,7 +264,6 @@ public class HearingAidService extends ProfileService { continue; } sm.sendMessage(HearingAidStateMachine.CONNECT); } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { Loading Loading @@ -511,6 +531,10 @@ public class HearingAidService extends ProfileService { BluetoothDevice device = stackEvent.device; int capabilities = stackEvent.valueInt1; long hiSyncId = stackEvent.valueLong2; if (DBG) { Log.d(TAG, "Device available: device=" + device + " capabilities=" + capabilities + " hiSyncId=" + hiSyncId); } mDeviceCapabilitiesMap.put(device, capabilities); mDeviceHiSyncIdMap.put(device, hiSyncId); return; Loading
android/app/src/com/android/bluetooth/newavrcp/AvrcpNativeInterface.java +3 −0 Original line number Diff line number Diff line Loading @@ -186,11 +186,13 @@ public class AvrcpNativeInterface { } void setActiveDevice(String bdaddr) { bdaddr = bdaddr.toUpperCase(); d("setActiveDevice: bdaddr=" + bdaddr); mAvrcpService.setActiveDevice(bdaddr); } void deviceConnected(String bdaddr, boolean absoluteVolume) { bdaddr = bdaddr.toUpperCase(); d("deviceConnected: bdaddr=" + bdaddr + " absoluteVolume=" + absoluteVolume); if (mAvrcpService == null) { Log.w(TAG, "deviceConnected: AvrcpTargetService is null"); Loading @@ -201,6 +203,7 @@ public class AvrcpNativeInterface { } void deviceDisconnected(String bdaddr) { bdaddr = bdaddr.toUpperCase(); d("deviceDisconnected: bdaddr=" + bdaddr); if (mAvrcpService == null) { Log.w(TAG, "deviceDisconnected: AvrcpTargetService is null"); Loading
android/app/src/com/android/bluetooth/newavrcp/AvrcpTargetService.java +1 −2 Original line number Diff line number Diff line Loading @@ -296,7 +296,7 @@ public class AvrcpTargetService extends ProfileService { void setActiveDevice(String address) { Log.i(TAG, "setActiveDevice: address=" + address); BluetoothDevice d = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address.toUpperCase()); BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); if (d == null) { Log.wtfStack(TAG, "setActiveDevice: could not find device with address " + address); } Loading @@ -320,7 +320,6 @@ public class AvrcpTargetService extends ProfileService { } mVolumeManager.dump(sb); sb.append("\n"); } private static class AvrcpTargetBinder extends IBluetoothAvrcpTarget.Stub Loading
android/app/src/com/android/bluetooth/newavrcp/AvrcpVolumeManager.java +49 −45 Original line number Diff line number Diff line Loading @@ -44,21 +44,58 @@ class AvrcpVolumeManager { String mCurrentDeviceAddr = ""; boolean mAbsoluteVolumeSupported = false; int avrcpToSystemVolume(int avrcpVolume) { static int avrcpToSystemVolume(int avrcpVolume) { return (int) Math.floor((double) avrcpVolume * sDeviceMaxVolume / AVRCP_MAX_VOL); } int systemToAvrcpVolume(int deviceVolume) { static int systemToAvrcpVolume(int deviceVolume) { int avrcpVolume = (int) Math.floor((double) deviceVolume * AVRCP_MAX_VOL / sDeviceMaxVolume); if (avrcpVolume > 127) avrcpVolume = 127; return avrcpVolume; } SharedPreferences getVolumeMap() { private SharedPreferences getVolumeMap() { return mContext.getSharedPreferences(VOLUME_MAP, Context.MODE_PRIVATE); } private int getVolume(String bdaddr, int defaultValue) { if (!mVolumeMap.containsKey(bdaddr)) { Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + bdaddr); return defaultValue; } return mVolumeMap.get(bdaddr); } private void switchVolumeDevice(String bdaddr) { // Inform the audio manager that the device has changed mAudioManager.avrcpSupportsAbsoluteVolume(bdaddr, mDeviceMap.get(bdaddr)); // Get the current system volume and try to get the preference volume int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); int savedVolume = getVolume(bdaddr, currVolume); // If the preference volume isn't equal to the current stream volume then that means // we had a stored preference. if (DEBUG) { Log.d(TAG, "switchVolumeDevice: currVolume=" + currVolume + " savedVolume=" + savedVolume); } if (savedVolume != currVolume) { Log.i(TAG, "switchVolumeDevice: restoring volume level " + savedVolume); mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, savedVolume, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); } // If absolute volume for the device is supported, set the volume for the device if (mDeviceMap.get(bdaddr)) { int avrcpVolume = systemToAvrcpVolume(savedVolume); Log.i(TAG, "switchVolumeDevice: Updating device volume: avrcpVolume=" + avrcpVolume); mNativeInterface.sendVolumeChanged(avrcpVolume); } } AvrcpVolumeManager(Context context, AudioManager audioManager, AvrcpNativeInterface nativeInterface) { mContext = context; Loading @@ -66,7 +103,7 @@ class AvrcpVolumeManager { mNativeInterface = nativeInterface; sDeviceMaxVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); // Load the volume map into a hash map since shared preferences are slow // Load the volume map into a hash map since shared preferences are slow to poll and update Map<String, ?> allKeys = getVolumeMap().getAll(); for (Map.Entry<String, ?> entry : allKeys.entrySet()) { String key = entry.getKey(); Loading @@ -77,15 +114,6 @@ class AvrcpVolumeManager { } } int getVolume(String bdaddr, int defaultValue) { if (!mVolumeMap.containsKey(bdaddr)) { Log.w(TAG, "getVolume: Couldn't find volume preference for device: " + bdaddr); return defaultValue; } return mVolumeMap.get(bdaddr); } void storeVolume() { SharedPreferences.Editor pref = getVolumeMap().edit(); int storeVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); Loading @@ -101,18 +129,18 @@ class AvrcpVolumeManager { Log.d(TAG, "deviceConnected: bdaddr=" + bdaddr + " absoluteVolume=" + absoluteVolume); } mDeviceMap.put(bdaddr.toUpperCase(), absoluteVolume); mDeviceMap.put(bdaddr, absoluteVolume); // AVRCP features lookup has completed after the device became active. Switch to the new // device now. if (bdaddr == mCurrentDeviceAddr) { if (bdaddr.equals(mCurrentDeviceAddr)) { switchVolumeDevice(bdaddr); } } void volumeDeviceSwitched(String bdaddr) { if (DEBUG) { Log.d(TAG, "activeDeviceChanged: mCurrentDeviceAddr=" + mCurrentDeviceAddr Log.d(TAG, "volumeDeviceSwitched: mCurrentDeviceAddr=" + mCurrentDeviceAddr + " bdaddr=" + bdaddr); } Loading @@ -137,53 +165,29 @@ class AvrcpVolumeManager { // device supports absolute volume. Defer switching the device until AVRCP returns the // info. if (!mDeviceMap.containsKey(bdaddr)) { Log.w(TAG, "Device isn't connected: " + bdaddr); Log.w(TAG, "volumeDeviceSwitched: Device isn't connected: " + bdaddr); return; } switchVolumeDevice(bdaddr); } void switchVolumeDevice(String bdaddr) { // Inform the audio manager that the device has changed mAudioManager.avrcpSupportsAbsoluteVolume(bdaddr, mDeviceMap.get(bdaddr)); // Get the current system volume and try to get the preference volume int currVolume = mAudioManager.getStreamVolume(STREAM_MUSIC); int savedVolume = getVolume(bdaddr, currVolume); // If the preference volume isn't equal to the current stream volume then that means // we had a stored preference. void deviceDisconnected(String bdaddr) { if (DEBUG) { Log.d(TAG, "activeDeviceChanged: currVolume=" + currVolume + " savedVolume=" + savedVolume); } if (savedVolume != currVolume) { mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, savedVolume, AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_BLUETOOTH_ABS_VOLUME); } // If absolute volume for the device is supported, set the volume for the device if (mDeviceMap.get(bdaddr)) { int avrcpVolume = systemToAvrcpVolume(savedVolume); Log.e(TAG, "activeDeviceChanged: Updating device volume: avrcpVolume=" + avrcpVolume); mNativeInterface.sendVolumeChanged(avrcpVolume); } Log.d(TAG, "deviceDisconnected: bdaddr=" + bdaddr); } void deviceDisconnected(String bdaddr) { Log.e(TAG, "deviceDisconnected: bdaddr=" + bdaddr); mDeviceMap.remove(bdaddr); } public void dump(StringBuilder sb) { sb.append("Bluetooth Device Volume Map:\n"); sb.append(" Device Address : Volume\n"); Map<String, ?> allKeys = getVolumeMap().getAll(); for (Map.Entry<String, ?> entry : allKeys.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (value instanceof Integer) { sb.append(" " + key + " - " + (Integer) value + "\n"); sb.append(" " + key + " : " + (Integer) value + "\n"); mVolumeMap.put(key, (Integer) value); } } Loading
android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java +172 −20 Original line number Diff line number Diff line Loading @@ -115,19 +115,6 @@ public class HearingAidServiceTest { mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); HearingAidStackEvent event = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); event.device = mLeftDevice; event.valueInt1 = 0x02; event.valueLong2 = 0x0101; mService.messageFromNative(event); event.device = mRightDevice; event.valueInt1 = 0x03; mService.messageFromNative(event); event.device = mSingleDevice; event.valueInt1 = 0x00; event.valueLong2 = 0x0102; mService.messageFromNative(event); doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService) .getBondState(any(BluetoothDevice.class)); doReturn(new ParcelUuid[]{BluetoothUuid.HearingAid}).when(mAdapterService) Loading Loading @@ -408,8 +395,8 @@ public class HearingAidServiceTest { */ @Test public void testConnectAPair_connectBothDevices() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -436,8 +423,8 @@ public class HearingAidServiceTest { */ @Test public void testConnectAnotherPair_disconnectCurrentPair() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -454,7 +441,7 @@ public class HearingAidServiceTest { verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); Loading Loading @@ -496,8 +483,8 @@ public class HearingAidServiceTest { */ @Test public void testAudioManagerConnectDisconnect() { HearingAidStackEvent connCompletedEvent; // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -519,6 +506,7 @@ public class HearingAidServiceTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); Loading Loading @@ -769,6 +757,8 @@ public class HearingAidServiceTest { @Test public void testConnectionStateChangedActiveDevice() { // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading Loading @@ -797,6 +787,8 @@ public class HearingAidServiceTest { @Test public void testConnectionStateChangedAnotherActiveDevice() { // Update hiSyncId map getHiSyncIdFromNative(); // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); Loading @@ -819,6 +811,151 @@ public class HearingAidServiceTest { Assert.assertTrue(mService.getActiveDevices().contains(mSingleDevice)); } /** * Verify the correctness during first time connection. * Connect to left device -> Get left device hiSyncId -> Connect to right device -> * Get right device hiSyncId -> Both devices should be always connected */ @Test public void firstTimeConnection_shouldConnectToBothDevices() { // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request for left device Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId for left device HearingAidStackEvent hiSyncIdEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); hiSyncIdEvent.device = mLeftDevice; hiSyncIdEvent.valueInt1 = 0x02; hiSyncIdEvent.valueLong2 = 0x0101; mService.messageFromNative(hiSyncIdEvent); // Send a connect request for right device Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); // Verify the left device is still connected Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId for right device hiSyncIdEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); hiSyncIdEvent.device = mRightDevice; hiSyncIdEvent.valueInt1 = 0x02; hiSyncIdEvent.valueLong2 = 0x0101; mService.messageFromNative(hiSyncIdEvent); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); } /** * Get the HiSyncId from native stack after connecting to left device, then connect right */ @Test public void getHiSyncId_afterFirstDeviceConnected() { // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mService.getConnectionState(mRightDevice)); HearingAidStackEvent connCompletedEvent; // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Get hiSyncId update from native stack getHiSyncIdFromNative(); // Send a connect request for right Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); // Verify the left device is still connected Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mRightDevice)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mService.getConnectionState(mLeftDevice)); } private void connectDevice(BluetoothDevice device) { HearingAidStackEvent connCompletedEvent; Loading Loading @@ -896,4 +1033,19 @@ public class HearingAidServiceTest { Assert.assertEquals(expected, mService.okToConnect(device)); } private void getHiSyncIdFromNative() { HearingAidStackEvent event = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); event.device = mLeftDevice; event.valueInt1 = 0x02; event.valueLong2 = 0x0101; mService.messageFromNative(event); event.device = mRightDevice; event.valueInt1 = 0x03; mService.messageFromNative(event); event.device = mSingleDevice; event.valueInt1 = 0x00; event.valueLong2 = 0x0102; mService.messageFromNative(event); } }