Loading services/core/java/com/android/server/media/BluetoothRouteProvider.java +20 −3 Original line number Diff line number Diff line Loading @@ -166,6 +166,20 @@ class BluetoothRouteProvider { } } @Nullable MediaRoute2Info getSelectedRoute() { return (mSelectedRoute == null) ? null : mSelectedRoute.route; } @NonNull List<MediaRoute2Info> getTransferableRoutes() { List<MediaRoute2Info> routes = getAllBluetoothRoutes(); if (mSelectedRoute != null) { routes.remove(mSelectedRoute.route); } return routes; } @NonNull List<MediaRoute2Info> getAllBluetoothRoutes() { ArrayList<MediaRoute2Info> routes = new ArrayList<>(); Loading @@ -175,9 +189,12 @@ class BluetoothRouteProvider { return routes; } @Nullable String getSelectedRouteId() { return mSelectedRoute == null ? null : mSelectedRoute.route.getId(); boolean setSelectedRouteVolume(int volume) { if (mSelectedRoute == null) return false; mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route) .setVolume(volume) .build(); return true; } private void notifyBluetoothRoutesUpdated() { Loading services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +59 −100 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.server.media; import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; Loading @@ -42,15 +41,13 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers. */ // TODO: check thread safety. We may need to use lock to protect variables. class SystemMediaRoute2Provider extends MediaRoute2Provider { private static final String TAG = "MR2SystemProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); Loading @@ -68,19 +65,16 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { SystemMediaRoute2Provider.class.getPackageName$(), SystemMediaRoute2Provider.class.getName()); @GuardedBy("mLock") private String mSelectedRouteId; MediaRoute2Info mDefaultRoute; @NonNull List<MediaRoute2Info> mBluetoothRoutes = Collections.EMPTY_LIST; final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { @Override public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { mHandler.post(new Runnable() { @Override public void run() { updateAudioRoutes(newRoutes); } mHandler.post(() -> { updateDefaultRoute(newRoutes); notifyProviderState(); }); } }; Loading @@ -97,11 +91,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); AudioRoutesInfo newAudioRoutes = null; try { newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); } catch (RemoteException e) { } updateDefaultRoute(newAudioRoutes); initializeDefaultRoute(); mBtRouteProvider = BluetoothRouteProvider.getInstance(context, (routes) -> { mBluetoothRoutes = routes; publishRoutes(); publishProviderState(); boolean sessionInfoChanged; synchronized (mLock) { Loading @@ -111,7 +109,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { notifySessionInfoUpdated(); } }); initializeSessionInfo(); mHandler.post(() -> notifyProviderState()); //TODO: clean up this // This is required because it is not instantiated in the main thread and // BluetoothRoutesUpdatedListener can be called before here synchronized (mLock) { updateSessionInfosIfNeededLocked(); } mContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); Loading Loading @@ -164,53 +170,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { // Do nothing since we don't support grouping volume yet. } private void initializeDefaultRoute() { mDefaultRoute = new MediaRoute2Info.Builder( DEFAULT_ROUTE_ID, mContext.getResources().getText(R.string.default_audio_route_name).toString()) .setVolumeHandling(mAudioManager.isVolumeFixed() ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) .addFeature(FEATURE_LIVE_AUDIO) .addFeature(FEATURE_LIVE_VIDEO) .build(); AudioRoutesInfo newAudioRoutes = null; try { newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); } catch (RemoteException e) { } if (newAudioRoutes != null) { // This will select the active BT route if there is one and the current // selected route is the default system route, or if there is no selected // route yet. updateAudioRoutes(newAudioRoutes); } } private void initializeSessionInfo() { mBluetoothRoutes = mBtRouteProvider.getAllBluetoothRoutes(); MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } setProviderState(builder.build()); mHandler.post(() -> notifyProviderState()); //TODO: clean up this // This is required because it is not instantiated in the main thread and // BluetoothRoutesUpdatedListener can be called before this function synchronized (mLock) { updateSessionInfosIfNeededLocked(); } } private void updateAudioRoutes(AudioRoutesInfo newRoutes) { private void updateDefaultRoute(AudioRoutesInfo newRoutes) { int name = R.string.default_audio_route_name; if (newRoutes != null) { mCurAudioRoutesInfo.mainType = newRoutes.mainType; if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0 || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { Loading @@ -222,7 +184,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { name = com.android.internal.R.string.default_audio_route_name_usb; } } mDefaultRoute = new MediaRoute2Info.Builder( DEFAULT_ROUTE_ID, mContext.getResources().getText(name).toString()) .setVolumeHandling(mAudioManager.isVolumeFixed() Loading @@ -232,9 +194,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) .addFeature(FEATURE_LIVE_AUDIO) .addFeature(FEATURE_LIVE_VIDEO) .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) .build(); updateProviderState(); } publishRoutes(); private void updateProviderState() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); if (mBtRouteProvider != null) { for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) { builder.addRoute(route); } } setProviderState(builder.build()); } /** Loading @@ -246,20 +219,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( SYSTEM_SESSION_ID, "" /* clientPackageName */) .setSystemSession(true); String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId(); mSelectedRouteId = TextUtils.isEmpty(activeBtDeviceAddress) ? mDefaultRoute.getId() : activeBtDeviceAddress; builder.addSelectedRoute(mSelectedRouteId); if (!TextUtils.isEmpty(activeBtDeviceAddress)) { MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute(); if (selectedRoute == null) { selectedRoute = mDefaultRoute; } else { builder.addTransferableRoute(mDefaultRoute.getId()); } mSelectedRouteId = selectedRoute.getId(); builder.addSelectedRoute(mSelectedRouteId); for (MediaRoute2Info route : mBluetoothRoutes) { if (!TextUtils.equals(mSelectedRouteId, route.getId())) { for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { builder.addTransferableRoute(route.getId()); } } RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build(); if (Objects.equals(oldSessionInfo, newSessionInfo)) { Loading @@ -271,13 +244,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } } void publishRoutes() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } setAndNotifyProviderState(builder.build()); void publishProviderState() { updateProviderState(); notifyProviderState(); } void notifySessionInfoUpdated() { Loading Loading @@ -306,24 +275,14 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); if (newVolume != oldVolume) { String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId(); if (!TextUtils.isEmpty(activeBtDeviceAddress)) { for (int i = mBluetoothRoutes.size() - 1; i >= 0; i--) { MediaRoute2Info route = mBluetoothRoutes.get(i); if (TextUtils.equals(activeBtDeviceAddress, route.getId())) { mBluetoothRoutes.set(i, new MediaRoute2Info.Builder(route) .setVolume(newVolume) .build()); break; } } } else { if (TextUtils.equals(mDefaultRoute.getId(), mSelectedRouteId)) { mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) .setVolume(newVolume) .build(); } else { mBtRouteProvider.setSelectedRouteVolume(newVolume); } publishRoutes(); publishProviderState(); } } } Loading Loading
services/core/java/com/android/server/media/BluetoothRouteProvider.java +20 −3 Original line number Diff line number Diff line Loading @@ -166,6 +166,20 @@ class BluetoothRouteProvider { } } @Nullable MediaRoute2Info getSelectedRoute() { return (mSelectedRoute == null) ? null : mSelectedRoute.route; } @NonNull List<MediaRoute2Info> getTransferableRoutes() { List<MediaRoute2Info> routes = getAllBluetoothRoutes(); if (mSelectedRoute != null) { routes.remove(mSelectedRoute.route); } return routes; } @NonNull List<MediaRoute2Info> getAllBluetoothRoutes() { ArrayList<MediaRoute2Info> routes = new ArrayList<>(); Loading @@ -175,9 +189,12 @@ class BluetoothRouteProvider { return routes; } @Nullable String getSelectedRouteId() { return mSelectedRoute == null ? null : mSelectedRoute.route.getId(); boolean setSelectedRouteVolume(int volume) { if (mSelectedRoute == null) return false; mSelectedRoute.route = new MediaRoute2Info.Builder(mSelectedRoute.route) .setVolume(volume) .build(); return true; } private void notifyBluetoothRoutesUpdated() { Loading
services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +59 −100 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.server.media; import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO; import static android.media.MediaRoute2Info.FEATURE_LIVE_VIDEO; import android.annotation.NonNull; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; Loading @@ -42,15 +41,13 @@ import android.text.TextUtils; import android.util.Log; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers. */ // TODO: check thread safety. We may need to use lock to protect variables. class SystemMediaRoute2Provider extends MediaRoute2Provider { private static final String TAG = "MR2SystemProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); Loading @@ -68,19 +65,16 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { SystemMediaRoute2Provider.class.getPackageName$(), SystemMediaRoute2Provider.class.getName()); @GuardedBy("mLock") private String mSelectedRouteId; MediaRoute2Info mDefaultRoute; @NonNull List<MediaRoute2Info> mBluetoothRoutes = Collections.EMPTY_LIST; final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo(); final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() { @Override public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) { mHandler.post(new Runnable() { @Override public void run() { updateAudioRoutes(newRoutes); } mHandler.post(() -> { updateDefaultRoute(newRoutes); notifyProviderState(); }); } }; Loading @@ -97,11 +91,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); AudioRoutesInfo newAudioRoutes = null; try { newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); } catch (RemoteException e) { } updateDefaultRoute(newAudioRoutes); initializeDefaultRoute(); mBtRouteProvider = BluetoothRouteProvider.getInstance(context, (routes) -> { mBluetoothRoutes = routes; publishRoutes(); publishProviderState(); boolean sessionInfoChanged; synchronized (mLock) { Loading @@ -111,7 +109,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { notifySessionInfoUpdated(); } }); initializeSessionInfo(); mHandler.post(() -> notifyProviderState()); //TODO: clean up this // This is required because it is not instantiated in the main thread and // BluetoothRoutesUpdatedListener can be called before here synchronized (mLock) { updateSessionInfosIfNeededLocked(); } mContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); Loading Loading @@ -164,53 +170,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { // Do nothing since we don't support grouping volume yet. } private void initializeDefaultRoute() { mDefaultRoute = new MediaRoute2Info.Builder( DEFAULT_ROUTE_ID, mContext.getResources().getText(R.string.default_audio_route_name).toString()) .setVolumeHandling(mAudioManager.isVolumeFixed() ? MediaRoute2Info.PLAYBACK_VOLUME_FIXED : MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE) .setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) .addFeature(FEATURE_LIVE_AUDIO) .addFeature(FEATURE_LIVE_VIDEO) .build(); AudioRoutesInfo newAudioRoutes = null; try { newAudioRoutes = mAudioService.startWatchingRoutes(mAudioRoutesObserver); } catch (RemoteException e) { } if (newAudioRoutes != null) { // This will select the active BT route if there is one and the current // selected route is the default system route, or if there is no selected // route yet. updateAudioRoutes(newAudioRoutes); } } private void initializeSessionInfo() { mBluetoothRoutes = mBtRouteProvider.getAllBluetoothRoutes(); MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } setProviderState(builder.build()); mHandler.post(() -> notifyProviderState()); //TODO: clean up this // This is required because it is not instantiated in the main thread and // BluetoothRoutesUpdatedListener can be called before this function synchronized (mLock) { updateSessionInfosIfNeededLocked(); } } private void updateAudioRoutes(AudioRoutesInfo newRoutes) { private void updateDefaultRoute(AudioRoutesInfo newRoutes) { int name = R.string.default_audio_route_name; if (newRoutes != null) { mCurAudioRoutesInfo.mainType = newRoutes.mainType; if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0 || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) { Loading @@ -222,7 +184,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) { name = com.android.internal.R.string.default_audio_route_name_usb; } } mDefaultRoute = new MediaRoute2Info.Builder( DEFAULT_ROUTE_ID, mContext.getResources().getText(name).toString()) .setVolumeHandling(mAudioManager.isVolumeFixed() Loading @@ -232,9 +194,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { .setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC)) .addFeature(FEATURE_LIVE_AUDIO) .addFeature(FEATURE_LIVE_VIDEO) .setConnectionState(MediaRoute2Info.CONNECTION_STATE_CONNECTED) .build(); updateProviderState(); } publishRoutes(); private void updateProviderState() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); if (mBtRouteProvider != null) { for (MediaRoute2Info route : mBtRouteProvider.getAllBluetoothRoutes()) { builder.addRoute(route); } } setProviderState(builder.build()); } /** Loading @@ -246,20 +219,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( SYSTEM_SESSION_ID, "" /* clientPackageName */) .setSystemSession(true); String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId(); mSelectedRouteId = TextUtils.isEmpty(activeBtDeviceAddress) ? mDefaultRoute.getId() : activeBtDeviceAddress; builder.addSelectedRoute(mSelectedRouteId); if (!TextUtils.isEmpty(activeBtDeviceAddress)) { MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute(); if (selectedRoute == null) { selectedRoute = mDefaultRoute; } else { builder.addTransferableRoute(mDefaultRoute.getId()); } mSelectedRouteId = selectedRoute.getId(); builder.addSelectedRoute(mSelectedRouteId); for (MediaRoute2Info route : mBluetoothRoutes) { if (!TextUtils.equals(mSelectedRouteId, route.getId())) { for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { builder.addTransferableRoute(route.getId()); } } RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build(); if (Objects.equals(oldSessionInfo, newSessionInfo)) { Loading @@ -271,13 +244,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { } } void publishRoutes() { MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); builder.addRoute(mDefaultRoute); for (MediaRoute2Info route : mBluetoothRoutes) { builder.addRoute(route); } setAndNotifyProviderState(builder.build()); void publishProviderState() { updateProviderState(); notifyProviderState(); } void notifySessionInfoUpdated() { Loading Loading @@ -306,24 +275,14 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0); if (newVolume != oldVolume) { String activeBtDeviceAddress = mBtRouteProvider.getSelectedRouteId(); if (!TextUtils.isEmpty(activeBtDeviceAddress)) { for (int i = mBluetoothRoutes.size() - 1; i >= 0; i--) { MediaRoute2Info route = mBluetoothRoutes.get(i); if (TextUtils.equals(activeBtDeviceAddress, route.getId())) { mBluetoothRoutes.set(i, new MediaRoute2Info.Builder(route) .setVolume(newVolume) .build()); break; } } } else { if (TextUtils.equals(mDefaultRoute.getId(), mSelectedRouteId)) { mDefaultRoute = new MediaRoute2Info.Builder(mDefaultRoute) .setVolume(newVolume) .build(); } else { mBtRouteProvider.setSelectedRouteVolume(newVolume); } publishRoutes(); publishProviderState(); } } } Loading