diff options
| -rw-r--r-- | services/core/java/com/android/server/media/DeviceRouteController.java | 173 | ||||
| -rw-r--r-- | services/core/java/com/android/server/media/LegacyDeviceRouteController.java | 178 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java (renamed from services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java) | 12 |
3 files changed, 214 insertions, 149 deletions
diff --git a/services/core/java/com/android/server/media/DeviceRouteController.java b/services/core/java/com/android/server/media/DeviceRouteController.java index 8bd6416a6ddb..3fc930903883 100644 --- a/services/core/java/com/android/server/media/DeviceRouteController.java +++ b/services/core/java/com/android/server/media/DeviceRouteController.java @@ -16,32 +16,12 @@ package com.android.server.media; -import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; -import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; -import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK; -import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; -import static android.media.MediaRoute2Info.TYPE_DOCK; -import static android.media.MediaRoute2Info.TYPE_HDMI; -import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; -import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; -import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; - import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.Context; import android.media.AudioManager; -import android.media.AudioRoutesInfo; -import android.media.IAudioRoutesObserver; import android.media.IAudioService; import android.media.MediaRoute2Info; -import android.os.RemoteException; import android.os.ServiceManager; -import android.util.Slog; - -import com.android.internal.R; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.Objects; /** * Controls device routes. @@ -49,145 +29,52 @@ import java.util.Objects; * <p>A device route is a system wired route, for example, built-in speaker, wired * headsets and headphones, dock, hdmi, or usb devices. * - * <p>Thread safe. - * * @see SystemMediaRoute2Provider */ -/* package */ final class DeviceRouteController { - - private static final String TAG = "WiredRoutesController"; - - private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE"; - - @NonNull - private final Context mContext; - @NonNull - private final AudioManager mAudioManager; - @NonNull - private final IAudioService mAudioService; - - @NonNull - private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; - @NonNull - private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver(); - - private int mDeviceVolume; - private MediaRoute2Info mDeviceRoute; +/* package */ interface DeviceRouteController { + /** + * Returns a new instance of {@link DeviceRouteController}. + */ /* package */ static DeviceRouteController createInstance(@NonNull Context context, @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { AudioManager audioManager = context.getSystemService(AudioManager.class); IAudioService audioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - return new DeviceRouteController(context, + return new LegacyDeviceRouteController(context, audioManager, audioService, onDeviceRouteChangedListener); } - @VisibleForTesting - /* package */ DeviceRouteController(@NonNull Context context, - @NonNull AudioManager audioManager, - @NonNull IAudioService audioService, - @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { - Objects.requireNonNull(context); - Objects.requireNonNull(audioManager); - Objects.requireNonNull(audioService); - Objects.requireNonNull(onDeviceRouteChangedListener); - - mContext = context; - mOnDeviceRouteChangedListener = onDeviceRouteChangedListener; - - mAudioManager = audioManager; - mAudioService = audioService; - - AudioRoutesInfo newAudioRoutes = null; - try { - newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); - } catch (RemoteException e) { - Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e); - } - - mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes); - } - + /** + * Returns currently selected device (built-in or wired) route. + * + * @return non-null device route. + */ @NonNull - /* package */ synchronized MediaRoute2Info getDeviceRoute() { - return mDeviceRoute; - } - - /* package */ synchronized boolean updateVolume(int volume) { - if (mDeviceVolume == volume) { - return false; - } - - mDeviceVolume = volume; - mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) - .setVolume(volume) - .build(); - - return true; - } - - private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) { - int name = R.string.default_audio_route_name; - int type = TYPE_BUILTIN_SPEAKER; - - if (newRoutes != null) { - if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) { - type = TYPE_WIRED_HEADPHONES; - name = com.android.internal.R.string.default_audio_route_name_headphones; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { - type = TYPE_WIRED_HEADSET; - name = com.android.internal.R.string.default_audio_route_name_headphones; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { - type = TYPE_DOCK; - name = com.android.internal.R.string.default_audio_route_name_dock_speakers; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { - type = TYPE_HDMI; - name = com.android.internal.R.string.default_audio_route_name_external_device; - } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { - type = TYPE_USB_DEVICE; - name = com.android.internal.R.string.default_audio_route_name_usb; - } - } - - synchronized (this) { - return new MediaRoute2Info.Builder( - DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString()) - .setVolumeHandling(mAudioManager.isVolumeFixed() - ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED - : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) - .setVolume(mDeviceVolume) - .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) - .setType(type) - .addFeature(FEATURE_LIVE_AUDIO) - .addFeature(FEATURE_LIVE_VIDEO) - .addFeature(FEATURE_LOCAL_PLAYBACK) - .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) - .build(); - } - } - - private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) { - mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); - } - - /* package */ interface OnDeviceRouteChangedListener { + MediaRoute2Info getDeviceRoute(); + + /** + * Updates device route volume. + * + * @param volume specifies a volume for the device route or 0 for unknown. + * @return {@code true} if updated successfully and {@code false} otherwise. + */ + boolean updateVolume(int volume); + + /** + * Interface for receiving events when device route has changed. + */ + interface OnDeviceRouteChangedListener { + + /** + * Called when device route has changed. + * + * @param deviceRoute non-null device route. + */ void onDeviceRouteChanged(@NonNull MediaRoute2Info deviceRoute); } - private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { - - @Override - public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) { - MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes); - synchronized (DeviceRouteController.this) { - mDeviceRoute = deviceRoute; - } - notifyDeviceRouteUpdate(deviceRoute); - } - } - } diff --git a/services/core/java/com/android/server/media/LegacyDeviceRouteController.java b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java new file mode 100644 index 000000000000..c9b62acb5ceb --- /dev/null +++ b/services/core/java/com/android/server/media/LegacyDeviceRouteController.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.media; + +import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; +import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; +import static android.media.MediaRoute2Info.FEATURE_LOCAL_PLAYBACK; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_DOCK; +import static android.media.MediaRoute2Info.TYPE_HDMI; +import static android.media.MediaRoute2Info.TYPE_USB_DEVICE; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.media.AudioManager; +import android.media.AudioRoutesInfo; +import android.media.IAudioRoutesObserver; +import android.media.IAudioService; +import android.media.MediaRoute2Info; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.Objects; + +/** + * Controls device routes. + * + * <p>A device route is a system wired route, for example, built-in speaker, wired + * headsets and headphones, dock, hdmi, or usb devices. + * + * <p>Thread safe. + * + * @see SystemMediaRoute2Provider + */ +/* package */ final class LegacyDeviceRouteController implements DeviceRouteController { + + private static final String TAG = "WiredRoutesController"; + + private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE"; + + @NonNull + private final Context mContext; + @NonNull + private final AudioManager mAudioManager; + @NonNull + private final IAudioService mAudioService; + + @NonNull + private final OnDeviceRouteChangedListener mOnDeviceRouteChangedListener; + @NonNull + private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver(); + + private int mDeviceVolume; + private MediaRoute2Info mDeviceRoute; + + @VisibleForTesting + /* package */ LegacyDeviceRouteController(@NonNull Context context, + @NonNull AudioManager audioManager, + @NonNull IAudioService audioService, + @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) { + Objects.requireNonNull(context); + Objects.requireNonNull(audioManager); + Objects.requireNonNull(audioService); + Objects.requireNonNull(onDeviceRouteChangedListener); + + mContext = context; + mOnDeviceRouteChangedListener = onDeviceRouteChangedListener; + + mAudioManager = audioManager; + mAudioService = audioService; + + AudioRoutesInfo newAudioRoutes = null; + try { + newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); + } catch (RemoteException e) { + Slog.w(TAG, "Cannot connect to audio service to start listen to routes", e); + } + + mDeviceRoute = createRouteFromAudioInfo(newAudioRoutes); + } + + @Override + @NonNull + public synchronized MediaRoute2Info getDeviceRoute() { + return mDeviceRoute; + } + + @Override + public synchronized boolean updateVolume(int volume) { + if (mDeviceVolume == volume) { + return false; + } + + mDeviceVolume = volume; + mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute) + .setVolume(volume) + .build(); + + return true; + } + + private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) { + int name = R.string.default_audio_route_name; + int type = TYPE_BUILTIN_SPEAKER; + + if (newRoutes != null) { + if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) { + type = TYPE_WIRED_HEADPHONES; + name = com.android.internal.R.string.default_audio_route_name_headphones; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { + type = TYPE_WIRED_HEADSET; + name = com.android.internal.R.string.default_audio_route_name_headphones; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) { + type = TYPE_DOCK; + name = com.android.internal.R.string.default_audio_route_name_dock_speakers; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) { + type = TYPE_HDMI; + name = com.android.internal.R.string.default_audio_route_name_external_device; + } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { + type = TYPE_USB_DEVICE; + name = com.android.internal.R.string.default_audio_route_name_usb; + } + } + + synchronized (this) { + return new MediaRoute2Info.Builder( + DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString()) + .setVolumeHandling(mAudioManager.isVolumeFixed() + ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED + : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) + .setVolume(mDeviceVolume) + .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) + .setType(type) + .addFeature(FEATURE_LIVE_AUDIO) + .addFeature(FEATURE_LIVE_VIDEO) + .addFeature(FEATURE_LOCAL_PLAYBACK) + .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) + .build(); + } + } + + private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) { + mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute); + } + + private class AudioRoutesObserver extends IAudioRoutesObserver.Stub { + + @Override + public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) { + MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes); + synchronized (LegacyDeviceRouteController.this) { + mDeviceRoute = deviceRoute; + } + notifyDeviceRouteUpdate(deviceRoute); + } + } + +} diff --git a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java index 24ed42cab63a..24e48517f280 100644 --- a/services/tests/servicestests/src/com/android/server/media/DeviceRouteControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/media/LegacyDeviceRouteControllerTest.java @@ -50,7 +50,7 @@ import java.util.Arrays; import java.util.Collection; @RunWith(Enclosed.class) -public class DeviceRouteControllerTest { +public class LegacyDeviceRouteControllerTest { private static final String DEFAULT_ROUTE_NAME = "default_route"; private static final String DEFAULT_HEADPHONES_NAME = "headphone"; @@ -97,7 +97,7 @@ public class DeviceRouteControllerTest { // Default route should be initialized even when AudioService returns null. when(mAudioService.startWatchingRoutes(any())).thenReturn(null); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -122,7 +122,7 @@ public class DeviceRouteControllerTest { AudioRoutesInfo fakeBluetoothAudioRoute = createFakeBluetoothAudioRoute(); when(mAudioService.startWatchingRoutes(any())).thenReturn(fakeBluetoothAudioRoute); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -236,7 +236,7 @@ public class DeviceRouteControllerTest { when(mResources.getText(mExpectedRouteNameResource)) .thenReturn(mExpectedRouteNameValue); - DeviceRouteController deviceRouteController = new DeviceRouteController( + LegacyDeviceRouteController deviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, @@ -269,7 +269,7 @@ public class DeviceRouteControllerTest { @Captor private ArgumentCaptor<IAudioRoutesObserver.Stub> mAudioRoutesObserverCaptor; - private DeviceRouteController mDeviceRouteController; + private LegacyDeviceRouteController mDeviceRouteController; private IAudioRoutesObserver.Stub mAudioRoutesObserver; @Before @@ -287,7 +287,7 @@ public class DeviceRouteControllerTest { when(mAudioService.startWatchingRoutes(mAudioRoutesObserverCaptor.capture())) .thenReturn(audioRoutesInfo); - mDeviceRouteController = new DeviceRouteController( + mDeviceRouteController = new LegacyDeviceRouteController( mContext, mAudioManager, mAudioService, |