Loading core/res/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -2030,6 +2030,10 @@ STREAM_MUSIC as if it's on TV platform. --> <bool name="config_single_volume">false</bool> <!-- Flag indicating whether notification and ringtone volumes are controlled together (aliasing is true) or not. --> <bool name="config_alias_ring_notif_stream_types">true</bool> <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions on grouped devices. --> <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool> Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -273,6 +273,7 @@ <java-symbol type="attr" name="autofillSaveCustomSubtitleMaxHeight"/> <java-symbol type="bool" name="action_bar_embed_tabs" /> <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" /> <java-symbol type="bool" name="config_alias_ring_notif_stream_types" /> <java-symbol type="bool" name="config_avoidGfxAccel" /> <java-symbol type="bool" name="config_bluetooth_address_validation" /> <java-symbol type="integer" name="config_chooser_max_targets_per_row" /> Loading services/core/java/com/android/server/audio/AudioService.java +50 −2 Original line number Diff line number Diff line Loading @@ -275,6 +275,25 @@ public class AudioService extends IAudioService.Stub // indicates whether the system maps all streams to a single stream. private final boolean mIsSingleVolume; /** * indicates whether STREAM_NOTIFICATION is aliased to STREAM_RING * not final due to test method, see {@link #setNotifAliasRingForTest(boolean)}. */ private boolean mNotifAliasRing; /** * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING, * volumes will be updated in case of a change. * @param alias if true, STREAM_NOTIFICATION is aliased to STREAM_RING */ /*package*/ void setNotifAliasRingForTest(boolean alias) { boolean update = (mNotifAliasRing != alias); mNotifAliasRing = alias; if (update) { updateStreamVolumeAlias(true, "AudioServiceTest"); } } /*package*/ boolean isPlatformVoice() { return mPlatformType == AudioSystem.PLATFORM_VOICE; } Loading Loading @@ -942,10 +961,25 @@ public class AudioService extends IAudioService.Stub */ public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper) { this (context, audioSystem, systemServer, settings, looper, context.getSystemService(AppOpsManager.class)); } /** * @param context * @param audioSystem Adapter for {@link AudioSystem} * @param systemServer Adapter for privilieged functionality for system server components * @param settings Adapter for {@link Settings} * @param looper Looper to use for the service's message handler. If this is null, an * {@link AudioSystemThread} is created as the messaging thread instead. */ public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper, AppOpsManager appOps) { sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()")); mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mAppOps = appOps; mAudioSystem = audioSystem; mSystemServer = systemServer; Loading Loading @@ -976,6 +1010,9 @@ public class AudioService extends IAudioService.Stub mUseVolumeGroupAliases = mContext.getResources().getBoolean( com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups); mNotifAliasRing = mContext.getResources().getBoolean( com.android.internal.R.bool.config_alias_ring_notif_stream_types); // Initialize volume // Priority 1 - Android Property // Priority 2 - Audio Policy Service Loading Loading @@ -2008,7 +2045,13 @@ public class AudioService extends IAudioService.Stub pw.println("\nStream volumes (device: index)"); int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int i = 0; i < numStreamTypes; i++) { pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":"); StringBuilder alias = new StringBuilder(); if (mStreamVolumeAlias[i] != i) { alias.append(" (aliased to: ") .append(AudioSystem.STREAM_NAMES[mStreamVolumeAlias[i]]) .append(")"); } pw.println("- " + AudioSystem.STREAM_NAMES[i] + alias + ":"); mStreamStates[i].dump(pw); pw.println(""); } Loading Loading @@ -2040,6 +2083,10 @@ public class AudioService extends IAudioService.Stub mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT; dtmfStreamAlias = AudioSystem.STREAM_MUSIC; } if (!mNotifAliasRing) { mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; } } if (mIsSingleVolume) { Loading Loading @@ -9888,6 +9935,7 @@ public class AudioService extends IAudioService.Stub pw.print(" mBtScoOnByApp="); pw.println(mBtScoOnByApp); pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume); pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume); pw.print(" mNotifAliasRing="); pw.println(mNotifAliasRing); pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices)); pw.print(" mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices)); pw.print(" mAbsoluteVolumeDevices.keySet()="); pw.println(dumpDeviceTypes( Loading services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java +41 −1 Original line number Diff line number Diff line Loading @@ -15,12 +15,18 @@ */ package com.android.server.audio; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; import android.media.AudioSystem; import android.os.Looper; import android.os.UserHandle; import android.util.Log; Loading @@ -33,6 +39,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; @MediumTest Loading @@ -46,6 +53,7 @@ public class AudioServiceTest { private AudioSystemAdapter mAudioSystem; @Spy private SystemServerAdapter mSpySystemServer; private SettingsAdapter mSettingsAdapter; @Mock private AppOpsManager mMockAppOpsManager; // the class being unit-tested here private AudioService mAudioService; Loading @@ -61,8 +69,11 @@ public class AudioServiceTest { mAudioSystem = new NoOpAudioSystemAdapter(); mSpySystemServer = spy(new NoOpSystemServerAdapter()); mSettingsAdapter = new NoOpSettingsAdapter(); mMockAppOpsManager = mock(AppOpsManager.class); when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), anyString(), anyString())) .thenReturn(AppOpsManager.MODE_ALLOWED); mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer, mSettingsAdapter, null); mSettingsAdapter, null, mMockAppOpsManager); } /** Loading Loading @@ -113,4 +124,33 @@ public class AudioServiceTest { reset(mSpySystemServer); } } @Test public void testRingNotifAlias() throws Exception { Log.i(TAG, "running testRingNotifAlias"); Assert.assertNotNull(mAudioService); // TODO add initialization message that can be caught here instead of sleeping Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // wait for full AudioService initialization // test with aliasing RING and NOTIFICATION mAudioService.setNotifAliasRingForTest(true); final int ringMaxVol = mAudioService.getStreamMaxVolume(AudioSystem.STREAM_RING); final int ringMinVol = mAudioService.getStreamMinVolume(AudioSystem.STREAM_RING); final int ringVol = ringMinVol + 1; // set a value for NOTIFICATION so it's not at the target test value (ringMaxVol) mAudioService.setStreamVolume(AudioSystem.STREAM_NOTIFICATION, ringVol, 0, "bla"); mAudioService.setStreamVolume(AudioSystem.STREAM_RING, ringMaxVol, 0, "bla"); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); Assert.assertEquals(ringMaxVol, mAudioService.getStreamVolume(AudioSystem.STREAM_NOTIFICATION)); // test with no aliasing between RING and NOTIFICATION mAudioService.setNotifAliasRingForTest(false); mAudioService.setStreamVolume(AudioSystem.STREAM_RING, ringVol, 0, "bla"); mAudioService.setStreamVolume(AudioSystem.STREAM_NOTIFICATION, ringMaxVol, 0, "bla"); Assert.assertEquals(ringVol, mAudioService.getStreamVolume(AudioSystem.STREAM_RING)); Assert.assertEquals(ringMaxVol, mAudioService.getStreamVolume( AudioSystem.STREAM_NOTIFICATION)); } } Loading
core/res/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -2030,6 +2030,10 @@ STREAM_MUSIC as if it's on TV platform. --> <bool name="config_single_volume">false</bool> <!-- Flag indicating whether notification and ringtone volumes are controlled together (aliasing is true) or not. --> <bool name="config_alias_ring_notif_stream_types">true</bool> <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions on grouped devices. --> <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool> Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -273,6 +273,7 @@ <java-symbol type="attr" name="autofillSaveCustomSubtitleMaxHeight"/> <java-symbol type="bool" name="action_bar_embed_tabs" /> <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" /> <java-symbol type="bool" name="config_alias_ring_notif_stream_types" /> <java-symbol type="bool" name="config_avoidGfxAccel" /> <java-symbol type="bool" name="config_bluetooth_address_validation" /> <java-symbol type="integer" name="config_chooser_max_targets_per_row" /> Loading
services/core/java/com/android/server/audio/AudioService.java +50 −2 Original line number Diff line number Diff line Loading @@ -275,6 +275,25 @@ public class AudioService extends IAudioService.Stub // indicates whether the system maps all streams to a single stream. private final boolean mIsSingleVolume; /** * indicates whether STREAM_NOTIFICATION is aliased to STREAM_RING * not final due to test method, see {@link #setNotifAliasRingForTest(boolean)}. */ private boolean mNotifAliasRing; /** * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING, * volumes will be updated in case of a change. * @param alias if true, STREAM_NOTIFICATION is aliased to STREAM_RING */ /*package*/ void setNotifAliasRingForTest(boolean alias) { boolean update = (mNotifAliasRing != alias); mNotifAliasRing = alias; if (update) { updateStreamVolumeAlias(true, "AudioServiceTest"); } } /*package*/ boolean isPlatformVoice() { return mPlatformType == AudioSystem.PLATFORM_VOICE; } Loading Loading @@ -942,10 +961,25 @@ public class AudioService extends IAudioService.Stub */ public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper) { this (context, audioSystem, systemServer, settings, looper, context.getSystemService(AppOpsManager.class)); } /** * @param context * @param audioSystem Adapter for {@link AudioSystem} * @param systemServer Adapter for privilieged functionality for system server components * @param settings Adapter for {@link Settings} * @param looper Looper to use for the service's message handler. If this is null, an * {@link AudioSystemThread} is created as the messaging thread instead. */ public AudioService(Context context, AudioSystemAdapter audioSystem, SystemServerAdapter systemServer, SettingsAdapter settings, @Nullable Looper looper, AppOpsManager appOps) { sLifecycleLogger.log(new AudioEventLogger.StringEvent("AudioService()")); mContext = context; mContentResolver = context.getContentResolver(); mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); mAppOps = appOps; mAudioSystem = audioSystem; mSystemServer = systemServer; Loading Loading @@ -976,6 +1010,9 @@ public class AudioService extends IAudioService.Stub mUseVolumeGroupAliases = mContext.getResources().getBoolean( com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups); mNotifAliasRing = mContext.getResources().getBoolean( com.android.internal.R.bool.config_alias_ring_notif_stream_types); // Initialize volume // Priority 1 - Android Property // Priority 2 - Audio Policy Service Loading Loading @@ -2008,7 +2045,13 @@ public class AudioService extends IAudioService.Stub pw.println("\nStream volumes (device: index)"); int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int i = 0; i < numStreamTypes; i++) { pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":"); StringBuilder alias = new StringBuilder(); if (mStreamVolumeAlias[i] != i) { alias.append(" (aliased to: ") .append(AudioSystem.STREAM_NAMES[mStreamVolumeAlias[i]]) .append(")"); } pw.println("- " + AudioSystem.STREAM_NAMES[i] + alias + ":"); mStreamStates[i].dump(pw); pw.println(""); } Loading Loading @@ -2040,6 +2083,10 @@ public class AudioService extends IAudioService.Stub mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT; dtmfStreamAlias = AudioSystem.STREAM_MUSIC; } if (!mNotifAliasRing) { mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION; } } if (mIsSingleVolume) { Loading Loading @@ -9888,6 +9935,7 @@ public class AudioService extends IAudioService.Stub pw.print(" mBtScoOnByApp="); pw.println(mBtScoOnByApp); pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume); pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume); pw.print(" mNotifAliasRing="); pw.println(mNotifAliasRing); pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices)); pw.print(" mFullVolumeDevices="); pw.println(dumpDeviceTypes(mFullVolumeDevices)); pw.print(" mAbsoluteVolumeDevices.keySet()="); pw.println(dumpDeviceTypes( Loading
services/tests/servicestests/src/com/android/server/audio/AudioServiceTest.java +41 −1 Original line number Diff line number Diff line Loading @@ -15,12 +15,18 @@ */ package com.android.server.audio; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.content.Context; import android.media.AudioSystem; import android.os.Looper; import android.os.UserHandle; import android.util.Log; Loading @@ -33,6 +39,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; @MediumTest Loading @@ -46,6 +53,7 @@ public class AudioServiceTest { private AudioSystemAdapter mAudioSystem; @Spy private SystemServerAdapter mSpySystemServer; private SettingsAdapter mSettingsAdapter; @Mock private AppOpsManager mMockAppOpsManager; // the class being unit-tested here private AudioService mAudioService; Loading @@ -61,8 +69,11 @@ public class AudioServiceTest { mAudioSystem = new NoOpAudioSystemAdapter(); mSpySystemServer = spy(new NoOpSystemServerAdapter()); mSettingsAdapter = new NoOpSettingsAdapter(); mMockAppOpsManager = mock(AppOpsManager.class); when(mMockAppOpsManager.noteOp(anyInt(), anyInt(), anyString(), anyString(), anyString())) .thenReturn(AppOpsManager.MODE_ALLOWED); mAudioService = new AudioService(mContext, mAudioSystem, mSpySystemServer, mSettingsAdapter, null); mSettingsAdapter, null, mMockAppOpsManager); } /** Loading Loading @@ -113,4 +124,33 @@ public class AudioServiceTest { reset(mSpySystemServer); } } @Test public void testRingNotifAlias() throws Exception { Log.i(TAG, "running testRingNotifAlias"); Assert.assertNotNull(mAudioService); // TODO add initialization message that can be caught here instead of sleeping Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); // wait for full AudioService initialization // test with aliasing RING and NOTIFICATION mAudioService.setNotifAliasRingForTest(true); final int ringMaxVol = mAudioService.getStreamMaxVolume(AudioSystem.STREAM_RING); final int ringMinVol = mAudioService.getStreamMinVolume(AudioSystem.STREAM_RING); final int ringVol = ringMinVol + 1; // set a value for NOTIFICATION so it's not at the target test value (ringMaxVol) mAudioService.setStreamVolume(AudioSystem.STREAM_NOTIFICATION, ringVol, 0, "bla"); mAudioService.setStreamVolume(AudioSystem.STREAM_RING, ringMaxVol, 0, "bla"); Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS); Assert.assertEquals(ringMaxVol, mAudioService.getStreamVolume(AudioSystem.STREAM_NOTIFICATION)); // test with no aliasing between RING and NOTIFICATION mAudioService.setNotifAliasRingForTest(false); mAudioService.setStreamVolume(AudioSystem.STREAM_RING, ringVol, 0, "bla"); mAudioService.setStreamVolume(AudioSystem.STREAM_NOTIFICATION, ringMaxVol, 0, "bla"); Assert.assertEquals(ringVol, mAudioService.getStreamVolume(AudioSystem.STREAM_RING)); Assert.assertEquals(ringMaxVol, mAudioService.getStreamVolume( AudioSystem.STREAM_NOTIFICATION)); } }