Loading packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -82,6 +82,13 @@ public abstract class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; private static final String TAG = "InfoMediaManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** Checked exception that signals the specified package is not present in the system. */ public static class PackageNotAvailableException extends Exception { public PackageNotAvailableException(String message) { super(message); } } protected String mPackageName; protected String mPackageName; private MediaDevice mCurrentConnectedDevice; private MediaDevice mCurrentConnectedDevice; private final LocalBluetoothManager mBluetoothManager; private final LocalBluetoothManager mBluetoothManager; Loading packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java 0 → 100644 +320 −0 Original line number Original line Diff line number Diff line /* * 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.settingslib.media; import android.annotation.SuppressLint; import android.app.Notification; import android.content.Context; import android.media.MediaRoute2Info; import android.media.MediaRouter2; import android.media.MediaRouter2.RoutingController; import android.media.MediaRouter2Manager; import android.media.RouteDiscoveryPreference; import android.media.RouteListingPreference; import android.media.RoutingSessionInfo; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.stream.Collectors; /** Implements {@link InfoMediaManager} using {@link MediaRouter2}. */ @SuppressLint("MissingPermission") public final class RouterInfoMediaManager extends InfoMediaManager { private static final String TAG = "RouterInfoMediaManager"; private final MediaRouter2 mRouter; private final MediaRouter2Manager mRouterManager; private final Executor mExecutor = Executors.newSingleThreadExecutor(); private final RouteCallback mRouteCallback = new RouteCallback(); private final TransferCallback mTransferCallback = new TransferCallback(); private final ControllerCallback mControllerCallback = new ControllerCallback(); private final RouteListingPreferenceCallback mRouteListingPreferenceCallback = new RouteListingPreferenceCallback(); // TODO: b/192657812 - Create factory method in InfoMediaManager to return // RouterInfoMediaManager or ManagerInfoMediaManager based on flag. public RouterInfoMediaManager( Context context, String packageName, Notification notification, LocalBluetoothManager localBluetoothManager) throws PackageNotAvailableException { super(context, packageName, notification, localBluetoothManager); // TODO: b/291277292 - Change optional package name for a mandatory uid. if (packageName == null) { packageName = context.getPackageName(); } mRouter = MediaRouter2.getInstance(context, packageName); if (mRouter == null) { throw new PackageNotAvailableException( "Package name " + packageName + " does not exist."); } mRouterManager = MediaRouter2Manager.getInstance(context); } @Override protected void startScanOnRouter() { mRouter.registerRouteCallback(mExecutor, mRouteCallback, RouteDiscoveryPreference.EMPTY); mRouter.registerRouteListingPreferenceCallback(mExecutor, mRouteListingPreferenceCallback); mRouter.registerTransferCallback(mExecutor, mTransferCallback); mRouter.registerControllerCallback(mExecutor, mControllerCallback); mRouter.startScan(); } @Override public void stopScan() { mRouter.stopScan(); mRouter.unregisterControllerCallback(mControllerCallback); mRouter.unregisterTransferCallback(mTransferCallback); mRouter.unregisterRouteListingPreferenceCallback(mRouteListingPreferenceCallback); mRouter.unregisterRouteCallback(mRouteCallback); } @Override protected boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device) { if (device.mRouteInfo == null) { return false; } RoutingController controller = mRouter.getSystemController(); mRouter.transfer(controller, device.mRouteInfo); return true; } @Override protected void transferToRoute(@NonNull MediaRoute2Info route) { mRouter.transferTo(route); } @Override protected void selectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller != null) { controller.selectRoute(route); } } @Override protected void deselectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller != null) { controller.deselectRoute(route); } } @Override protected void releaseSession(@NonNull RoutingSessionInfo sessionInfo) { RoutingController controller = getControllerForSession(sessionInfo); if (controller != null) { controller.release(); } } @NonNull @Override protected List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } // Filter out selected routes. List<String> selectedRouteIds = controller.getRoutingSessionInfo().getSelectedRoutes(); return controller.getSelectableRoutes().stream() .filter(route -> !selectedRouteIds.contains(route.getId())) .collect(Collectors.toList()); } @NonNull @Override protected List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } return controller.getDeselectableRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } return controller.getSelectedRoutes(); } @Override protected void setSessionVolume(@NonNull RoutingSessionInfo info, int volume) { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as // MR2 filters information by package name. mRouterManager.setSessionVolume(info, volume); } @Override protected void setRouteVolume(@NonNull MediaRoute2Info route, int volume) { mRouter.setRouteVolume(route, volume); } @Nullable @Override protected RouteListingPreference getRouteListingPreference() { return mRouter.getRouteListingPreference(); } @NonNull @Override protected List<RoutingSessionInfo> getRemoteSessions() { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as // MR2 filters information by package name. return mRouterManager.getRemoteSessions(); } @NonNull @Override protected List<RoutingSessionInfo> getRoutingSessionsForPackage() { return mRouter.getControllers().stream() .map(RoutingController::getRoutingSessionInfo) .collect(Collectors.toList()); } @Nullable @Override protected RoutingSessionInfo getRoutingSessionById(@NonNull String sessionId) { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager calls as // MR2 filters information by package name. for (RoutingSessionInfo sessionInfo : getRemoteSessions()) { if (TextUtils.equals(sessionInfo.getId(), sessionId)) { return sessionInfo; } } RoutingSessionInfo systemSession = mRouterManager.getSystemRoutingSession(null); return TextUtils.equals(systemSession.getId(), sessionId) ? systemSession : null; } @NonNull @Override protected List<MediaRoute2Info> getAllRoutes() { return mRouter.getAllRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getAvailableRoutesFromRouter() { return mRouter.getRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName) { List<MediaRoute2Info> transferableRoutes = new ArrayList<>(); List<RoutingController> controllers = mRouter.getControllers(); RoutingController activeController = controllers.get(controllers.size() - 1); RoutingSessionInfo sessionInfo = activeController.getRoutingSessionInfo(); List<MediaRoute2Info> routes = mRouter.getRoutes(); for (MediaRoute2Info route : routes) { boolean isCrossDeviceTransfer = sessionInfo.isSystemSession() ^ route.isSystemRoute(); // Always show remote routes if transfer is local -> remote or viceversa regardless of // whether route is in transferable routes list. if (sessionInfo.getTransferableRoutes().contains(route.getId()) || isCrossDeviceTransfer) { transferableRoutes.add(route); } } return transferableRoutes; } @Nullable private RoutingController getControllerForSession(@NonNull RoutingSessionInfo sessionInfo) { return mRouter.getController(sessionInfo.getId()); } private final class RouteCallback extends MediaRouter2.RouteCallback { @Override public void onRoutesUpdated(@NonNull List<MediaRoute2Info> routes) { refreshDevices(); } @Override public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) { refreshDevices(); } } private final class TransferCallback extends MediaRouter2.TransferCallback { @Override public void onTransfer( @NonNull RoutingController oldController, @NonNull RoutingController newController) { rebuildDeviceList(); notifyCurrentConnectedDeviceChanged(); } @Override public void onTransferFailure(@NonNull MediaRoute2Info requestedRoute) { // Do nothing. } @Override public void onStop(@NonNull RoutingController controller) { refreshDevices(); } @Override public void onRequestFailed(int reason) { dispatchOnRequestFailed(reason); } } private final class ControllerCallback extends MediaRouter2.ControllerCallback { @Override public void onControllerUpdated(@NonNull RoutingController controller) { refreshDevices(); } } private final class RouteListingPreferenceCallback extends MediaRouter2.RouteListingPreferenceCallback { @Override public void onRouteListingPreferenceChanged(@Nullable RouteListingPreference preference) { notifyRouteListingPreferenceUpdated(preference); refreshDevices(); } } } Loading
packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -82,6 +82,13 @@ public abstract class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; private static final String TAG = "InfoMediaManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); /** Checked exception that signals the specified package is not present in the system. */ public static class PackageNotAvailableException extends Exception { public PackageNotAvailableException(String message) { super(message); } } protected String mPackageName; protected String mPackageName; private MediaDevice mCurrentConnectedDevice; private MediaDevice mCurrentConnectedDevice; private final LocalBluetoothManager mBluetoothManager; private final LocalBluetoothManager mBluetoothManager; Loading
packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java 0 → 100644 +320 −0 Original line number Original line Diff line number Diff line /* * 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.settingslib.media; import android.annotation.SuppressLint; import android.app.Notification; import android.content.Context; import android.media.MediaRoute2Info; import android.media.MediaRouter2; import android.media.MediaRouter2.RoutingController; import android.media.MediaRouter2Manager; import android.media.RouteDiscoveryPreference; import android.media.RouteListingPreference; import android.media.RoutingSessionInfo; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.settingslib.bluetooth.LocalBluetoothManager; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.stream.Collectors; /** Implements {@link InfoMediaManager} using {@link MediaRouter2}. */ @SuppressLint("MissingPermission") public final class RouterInfoMediaManager extends InfoMediaManager { private static final String TAG = "RouterInfoMediaManager"; private final MediaRouter2 mRouter; private final MediaRouter2Manager mRouterManager; private final Executor mExecutor = Executors.newSingleThreadExecutor(); private final RouteCallback mRouteCallback = new RouteCallback(); private final TransferCallback mTransferCallback = new TransferCallback(); private final ControllerCallback mControllerCallback = new ControllerCallback(); private final RouteListingPreferenceCallback mRouteListingPreferenceCallback = new RouteListingPreferenceCallback(); // TODO: b/192657812 - Create factory method in InfoMediaManager to return // RouterInfoMediaManager or ManagerInfoMediaManager based on flag. public RouterInfoMediaManager( Context context, String packageName, Notification notification, LocalBluetoothManager localBluetoothManager) throws PackageNotAvailableException { super(context, packageName, notification, localBluetoothManager); // TODO: b/291277292 - Change optional package name for a mandatory uid. if (packageName == null) { packageName = context.getPackageName(); } mRouter = MediaRouter2.getInstance(context, packageName); if (mRouter == null) { throw new PackageNotAvailableException( "Package name " + packageName + " does not exist."); } mRouterManager = MediaRouter2Manager.getInstance(context); } @Override protected void startScanOnRouter() { mRouter.registerRouteCallback(mExecutor, mRouteCallback, RouteDiscoveryPreference.EMPTY); mRouter.registerRouteListingPreferenceCallback(mExecutor, mRouteListingPreferenceCallback); mRouter.registerTransferCallback(mExecutor, mTransferCallback); mRouter.registerControllerCallback(mExecutor, mControllerCallback); mRouter.startScan(); } @Override public void stopScan() { mRouter.stopScan(); mRouter.unregisterControllerCallback(mControllerCallback); mRouter.unregisterTransferCallback(mTransferCallback); mRouter.unregisterRouteListingPreferenceCallback(mRouteListingPreferenceCallback); mRouter.unregisterRouteCallback(mRouteCallback); } @Override protected boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device) { if (device.mRouteInfo == null) { return false; } RoutingController controller = mRouter.getSystemController(); mRouter.transfer(controller, device.mRouteInfo); return true; } @Override protected void transferToRoute(@NonNull MediaRoute2Info route) { mRouter.transferTo(route); } @Override protected void selectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller != null) { controller.selectRoute(route); } } @Override protected void deselectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller != null) { controller.deselectRoute(route); } } @Override protected void releaseSession(@NonNull RoutingSessionInfo sessionInfo) { RoutingController controller = getControllerForSession(sessionInfo); if (controller != null) { controller.release(); } } @NonNull @Override protected List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } // Filter out selected routes. List<String> selectedRouteIds = controller.getRoutingSessionInfo().getSelectedRoutes(); return controller.getSelectableRoutes().stream() .filter(route -> !selectedRouteIds.contains(route.getId())) .collect(Collectors.toList()); } @NonNull @Override protected List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } return controller.getDeselectableRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo info) { RoutingController controller = getControllerForSession(info); if (controller == null) { return Collections.emptyList(); } return controller.getSelectedRoutes(); } @Override protected void setSessionVolume(@NonNull RoutingSessionInfo info, int volume) { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as // MR2 filters information by package name. mRouterManager.setSessionVolume(info, volume); } @Override protected void setRouteVolume(@NonNull MediaRoute2Info route, int volume) { mRouter.setRouteVolume(route, volume); } @Nullable @Override protected RouteListingPreference getRouteListingPreference() { return mRouter.getRouteListingPreference(); } @NonNull @Override protected List<RoutingSessionInfo> getRemoteSessions() { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as // MR2 filters information by package name. return mRouterManager.getRemoteSessions(); } @NonNull @Override protected List<RoutingSessionInfo> getRoutingSessionsForPackage() { return mRouter.getControllers().stream() .map(RoutingController::getRoutingSessionInfo) .collect(Collectors.toList()); } @Nullable @Override protected RoutingSessionInfo getRoutingSessionById(@NonNull String sessionId) { // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager calls as // MR2 filters information by package name. for (RoutingSessionInfo sessionInfo : getRemoteSessions()) { if (TextUtils.equals(sessionInfo.getId(), sessionId)) { return sessionInfo; } } RoutingSessionInfo systemSession = mRouterManager.getSystemRoutingSession(null); return TextUtils.equals(systemSession.getId(), sessionId) ? systemSession : null; } @NonNull @Override protected List<MediaRoute2Info> getAllRoutes() { return mRouter.getAllRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getAvailableRoutesFromRouter() { return mRouter.getRoutes(); } @NonNull @Override protected List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName) { List<MediaRoute2Info> transferableRoutes = new ArrayList<>(); List<RoutingController> controllers = mRouter.getControllers(); RoutingController activeController = controllers.get(controllers.size() - 1); RoutingSessionInfo sessionInfo = activeController.getRoutingSessionInfo(); List<MediaRoute2Info> routes = mRouter.getRoutes(); for (MediaRoute2Info route : routes) { boolean isCrossDeviceTransfer = sessionInfo.isSystemSession() ^ route.isSystemRoute(); // Always show remote routes if transfer is local -> remote or viceversa regardless of // whether route is in transferable routes list. if (sessionInfo.getTransferableRoutes().contains(route.getId()) || isCrossDeviceTransfer) { transferableRoutes.add(route); } } return transferableRoutes; } @Nullable private RoutingController getControllerForSession(@NonNull RoutingSessionInfo sessionInfo) { return mRouter.getController(sessionInfo.getId()); } private final class RouteCallback extends MediaRouter2.RouteCallback { @Override public void onRoutesUpdated(@NonNull List<MediaRoute2Info> routes) { refreshDevices(); } @Override public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) { refreshDevices(); } } private final class TransferCallback extends MediaRouter2.TransferCallback { @Override public void onTransfer( @NonNull RoutingController oldController, @NonNull RoutingController newController) { rebuildDeviceList(); notifyCurrentConnectedDeviceChanged(); } @Override public void onTransferFailure(@NonNull MediaRoute2Info requestedRoute) { // Do nothing. } @Override public void onStop(@NonNull RoutingController controller) { refreshDevices(); } @Override public void onRequestFailed(int reason) { dispatchOnRequestFailed(reason); } } private final class ControllerCallback extends MediaRouter2.ControllerCallback { @Override public void onControllerUpdated(@NonNull RoutingController controller) { refreshDevices(); } } private final class RouteListingPreferenceCallback extends MediaRouter2.RouteListingPreferenceCallback { @Override public void onRouteListingPreferenceChanged(@Nullable RouteListingPreference preference) { notifyRouteListingPreferenceUpdated(preference); refreshDevices(); } } }