Loading services/core/java/com/android/server/audio/AudioDeviceBroker.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -154,6 +154,8 @@ import java.util.concurrent.atomic.AtomicBoolean; mPreferredDeviceforComm = null; mPreferredDeviceforComm = null; initCommunicationStrategyId(); initCommunicationStrategyId(); mSystemServer.registerUserStartedReceiver(mContext); } } /*package*/ Context getContext() { /*package*/ Context getContext() { Loading Loading @@ -993,6 +995,10 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent); } /*package*/ void dump(PrintWriter pw, String prefix) { /*package*/ void dump(PrintWriter pw, String prefix) { if (mBrokerHandler != null) { if (mBrokerHandler != null) { pw.println(prefix + "Message handler (watch for unhandled messages):"); pw.println(prefix + "Message handler (watch for unhandled messages):"); Loading services/core/java/com/android/server/audio/AudioDeviceInventory.java +1 −3 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.audio; package com.android.server.audio; import android.annotation.NonNull; import android.annotation.NonNull; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; Loading @@ -37,7 +36,6 @@ import android.media.MediaMetrics; import android.os.Binder; import android.os.Binder; import android.os.RemoteCallbackList; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; Loading Loading @@ -1270,7 +1268,7 @@ public class AudioDeviceInventory { final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); try { try { ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_CURRENT); mDeviceBroker.broadcastStickyIntentToCurrentProfileGroup(intent); } finally { } finally { Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident); } } Loading services/core/java/com/android/server/audio/AudioService.java +6 −2 Original line number Original line Diff line number Diff line Loading @@ -5591,7 +5591,9 @@ public class AudioService extends IAudioService.Stub profile, suppressNoisyIntent, a2dpVolume); profile, suppressNoisyIntent, a2dpVolume); } } /*package*/ void setMusicMute(boolean mute) { /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting public void setMusicMute(boolean mute) { mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); } } Loading Loading @@ -7071,7 +7073,9 @@ public class AudioService extends IAudioService.Stub } } } } /*package*/ void checkMusicActive(int deviceType, String caller) { /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting public void checkMusicActive(int deviceType, String caller) { if (mSafeMediaVolumeDevices.contains(deviceType)) { if (mSafeMediaVolumeDevices.contains(deviceType)) { sendMsg(mAudioHandler, sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, MSG_CHECK_MUSIC_ACTIVE, Loading services/core/java/com/android/server/audio/SystemServerAdapter.java +63 −0 Original line number Original line Diff line number Diff line Loading @@ -18,11 +18,20 @@ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; import android.media.AudioManager; import android.media.AudioManager; import android.os.Binder; import android.os.Binder; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import java.util.Objects; import java.util.Objects; Loading Loading @@ -82,4 +91,58 @@ public class SystemServerAdapter { Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident); } } } } /** * Send sticky broadcast to current user's profile group (including current user) */ @VisibleForTesting public void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { int[] profileIds = LocalServices.getService( ActivityManagerInternal.class).getCurrentProfileIds(); for (int userId : profileIds) { ActivityManager.broadcastStickyIntent(intent, userId); } } /** * Broadcast sticky intents when a profile is started. This is needed because newly created * profiles would not receive the intents until the next state change. */ /*package*/ void registerUserStartedReceiver(Context context) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_STARTED); context.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) { return; } UserManager userManager = context.getSystemService(UserManager.class); final UserInfo profileParent = userManager.getProfileParent(userId); if (profileParent == null) { return; } // get sticky intents from parent and broadcast them to the started profile broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HDMI_AUDIO_PLUG, userId, profileParent.id); broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HEADSET_PLUG, userId, profileParent.id); } } }, UserHandle.ALL, filter, null, null); } private void broadcastProfileParentStickyIntent(Context context, String intentAction, int profileId, int parentId) { Intent intent = context.registerReceiverAsUser(/*receiver*/ null, UserHandle.of(parentId), new IntentFilter(intentAction), /*broadcastPermission*/ null, /*scheduler*/ null); if (intent != null) { ActivityManager.broadcastStickyIntent(intent, profileId); } } } } services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +29 −3 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.audio; import static org.mockito.Mockito.any; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; Loading @@ -27,6 +28,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioManager; import android.media.AudioSystem; import android.media.AudioSystem; import android.util.Log; import android.util.Log; Loading Loading @@ -58,7 +60,7 @@ public class AudioDeviceBrokerTest { @Mock private AudioService mMockAudioService; @Mock private AudioService mMockAudioService; @Spy private AudioDeviceInventory mSpyDevInventory; @Spy private AudioDeviceInventory mSpyDevInventory; @Spy private AudioSystemAdapter mSpyAudioSystem; @Spy private AudioSystemAdapter mSpyAudioSystem; private SystemServerAdapter mSystemServer; @Spy private SystemServerAdapter mSpySystemServer; private BluetoothDevice mFakeBtDevice; private BluetoothDevice mFakeBtDevice; Loading @@ -69,9 +71,9 @@ public class AudioDeviceBrokerTest { mMockAudioService = mock(AudioService.class); mMockAudioService = mock(AudioService.class); mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mSystemServer = new NoOpSystemServerAdapter(); mSpySystemServer = spy(new NoOpSystemServerAdapter()); mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory, mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory, mSystemServer); mSpySystemServer); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); Loading Loading @@ -172,6 +174,30 @@ public class AudioDeviceBrokerTest { true); true); } } /** * Test that device wired state intents are broadcasted on connection state change * @throws Exception */ @Test public void testSetWiredDeviceConnectionState() throws Exception { Log.i(TAG, "starting postSetWiredDeviceConnectionState"); final String address = "testAddress"; final String name = "testName"; final String caller = "testCaller"; doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup( any(Intent.class)); mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioService.CONNECTION_STATE_CONNECTED, address, name, caller); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // Verify that the sticky intent is broadcasted verify(mSpySystemServer, times(1)).broadcastStickyIntentToCurrentProfileGroup( any(Intent.class)); } private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection, private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection, boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception { boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception { when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC)) when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC)) Loading Loading
services/core/java/com/android/server/audio/AudioDeviceBroker.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -154,6 +154,8 @@ import java.util.concurrent.atomic.AtomicBoolean; mPreferredDeviceforComm = null; mPreferredDeviceforComm = null; initCommunicationStrategyId(); initCommunicationStrategyId(); mSystemServer.registerUserStartedReceiver(mContext); } } /*package*/ Context getContext() { /*package*/ Context getContext() { Loading Loading @@ -993,6 +995,10 @@ import java.util.concurrent.atomic.AtomicBoolean; } } } } /*package*/ void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { mSystemServer.broadcastStickyIntentToCurrentProfileGroup(intent); } /*package*/ void dump(PrintWriter pw, String prefix) { /*package*/ void dump(PrintWriter pw, String prefix) { if (mBrokerHandler != null) { if (mBrokerHandler != null) { pw.println(prefix + "Message handler (watch for unhandled messages):"); pw.println(prefix + "Message handler (watch for unhandled messages):"); Loading
services/core/java/com/android/server/audio/AudioDeviceInventory.java +1 −3 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.audio; package com.android.server.audio; import android.annotation.NonNull; import android.annotation.NonNull; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; Loading @@ -37,7 +36,6 @@ import android.media.MediaMetrics; import android.os.Binder; import android.os.Binder; import android.os.RemoteCallbackList; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.ArraySet; import android.util.ArraySet; Loading Loading @@ -1270,7 +1268,7 @@ public class AudioDeviceInventory { final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); try { try { ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_CURRENT); mDeviceBroker.broadcastStickyIntentToCurrentProfileGroup(intent); } finally { } finally { Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident); } } Loading
services/core/java/com/android/server/audio/AudioService.java +6 −2 Original line number Original line Diff line number Diff line Loading @@ -5591,7 +5591,9 @@ public class AudioService extends IAudioService.Stub profile, suppressNoisyIntent, a2dpVolume); profile, suppressNoisyIntent, a2dpVolume); } } /*package*/ void setMusicMute(boolean mute) { /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting public void setMusicMute(boolean mute) { mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); } } Loading Loading @@ -7071,7 +7073,9 @@ public class AudioService extends IAudioService.Stub } } } } /*package*/ void checkMusicActive(int deviceType, String caller) { /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting public void checkMusicActive(int deviceType, String caller) { if (mSafeMediaVolumeDevices.contains(deviceType)) { if (mSafeMediaVolumeDevices.contains(deviceType)) { sendMsg(mAudioHandler, sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, MSG_CHECK_MUSIC_ACTIVE, Loading
services/core/java/com/android/server/audio/SystemServerAdapter.java +63 −0 Original line number Original line Diff line number Diff line Loading @@ -18,11 +18,20 @@ package com.android.server.audio; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; import android.media.AudioManager; import android.media.AudioManager; import android.os.Binder; import android.os.Binder; import android.os.UserHandle; import android.os.UserHandle; import android.os.UserManager; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import java.util.Objects; import java.util.Objects; Loading Loading @@ -82,4 +91,58 @@ public class SystemServerAdapter { Binder.restoreCallingIdentity(ident); Binder.restoreCallingIdentity(ident); } } } } /** * Send sticky broadcast to current user's profile group (including current user) */ @VisibleForTesting public void broadcastStickyIntentToCurrentProfileGroup(Intent intent) { int[] profileIds = LocalServices.getService( ActivityManagerInternal.class).getCurrentProfileIds(); for (int userId : profileIds) { ActivityManager.broadcastStickyIntent(intent, userId); } } /** * Broadcast sticky intents when a profile is started. This is needed because newly created * profiles would not receive the intents until the next state change. */ /*package*/ void registerUserStartedReceiver(Context context) { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_STARTED); context.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) { return; } UserManager userManager = context.getSystemService(UserManager.class); final UserInfo profileParent = userManager.getProfileParent(userId); if (profileParent == null) { return; } // get sticky intents from parent and broadcast them to the started profile broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HDMI_AUDIO_PLUG, userId, profileParent.id); broadcastProfileParentStickyIntent(context, AudioManager.ACTION_HEADSET_PLUG, userId, profileParent.id); } } }, UserHandle.ALL, filter, null, null); } private void broadcastProfileParentStickyIntent(Context context, String intentAction, int profileId, int parentId) { Intent intent = context.registerReceiverAsUser(/*receiver*/ null, UserHandle.of(parentId), new IntentFilter(intentAction), /*broadcastPermission*/ null, /*scheduler*/ null); if (intent != null) { ActivityManager.broadcastStickyIntent(intent, profileId); } } } }
services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java +29 −3 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.audio; import static org.mockito.Mockito.any; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; Loading @@ -27,6 +28,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.Context; import android.content.Intent; import android.media.AudioManager; import android.media.AudioManager; import android.media.AudioSystem; import android.media.AudioSystem; import android.util.Log; import android.util.Log; Loading Loading @@ -58,7 +60,7 @@ public class AudioDeviceBrokerTest { @Mock private AudioService mMockAudioService; @Mock private AudioService mMockAudioService; @Spy private AudioDeviceInventory mSpyDevInventory; @Spy private AudioDeviceInventory mSpyDevInventory; @Spy private AudioSystemAdapter mSpyAudioSystem; @Spy private AudioSystemAdapter mSpyAudioSystem; private SystemServerAdapter mSystemServer; @Spy private SystemServerAdapter mSpySystemServer; private BluetoothDevice mFakeBtDevice; private BluetoothDevice mFakeBtDevice; Loading @@ -69,9 +71,9 @@ public class AudioDeviceBrokerTest { mMockAudioService = mock(AudioService.class); mMockAudioService = mock(AudioService.class); mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); mSpyAudioSystem = spy(new NoOpAudioSystemAdapter()); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mSpyDevInventory = spy(new AudioDeviceInventory(mSpyAudioSystem)); mSystemServer = new NoOpSystemServerAdapter(); mSpySystemServer = spy(new NoOpSystemServerAdapter()); mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory, mAudioDeviceBroker = new AudioDeviceBroker(mContext, mMockAudioService, mSpyDevInventory, mSystemServer); mSpySystemServer); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); mSpyDevInventory.setDeviceBroker(mAudioDeviceBroker); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); Loading Loading @@ -172,6 +174,30 @@ public class AudioDeviceBrokerTest { true); true); } } /** * Test that device wired state intents are broadcasted on connection state change * @throws Exception */ @Test public void testSetWiredDeviceConnectionState() throws Exception { Log.i(TAG, "starting postSetWiredDeviceConnectionState"); final String address = "testAddress"; final String name = "testName"; final String caller = "testCaller"; doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup( any(Intent.class)); mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioService.CONNECTION_STATE_CONNECTED, address, name, caller); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // Verify that the sticky intent is broadcasted verify(mSpySystemServer, times(1)).broadcastStickyIntentToCurrentProfileGroup( any(Intent.class)); } private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection, private void doTestConnectionDisconnectionReconnection(int delayAfterDisconnection, boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception { boolean mockMediaPlayback, boolean guaranteeSingleConnection) throws Exception { when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC)) when(mMockAudioService.getDeviceForStream(AudioManager.STREAM_MUSIC)) Loading