1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.media; 18 19 import android.content.Context; 20 import android.media.MediaRoute2Info; 21 import android.media.MediaRouter2Manager; 22 import android.media.RouteListingPreference; 23 import android.media.RoutingSessionInfo; 24 import android.media.session.MediaController; 25 import android.os.UserHandle; 26 import android.text.TextUtils; 27 import android.util.Log; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.Nullable; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.settingslib.bluetooth.LocalBluetoothManager; 34 35 import java.util.List; 36 import java.util.concurrent.Executor; 37 import java.util.concurrent.Executors; 38 39 /** 40 * Template implementation of {@link InfoMediaManager} using {@link MediaRouter2Manager}. 41 */ 42 public class ManagerInfoMediaManager extends InfoMediaManager { 43 44 private static final String TAG = "ManagerInfoMediaManager"; 45 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 46 47 @VisibleForTesting 48 /* package */ final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback(); 49 @VisibleForTesting 50 /* package */ MediaRouter2Manager mRouterManager; 51 boolean mIsScanning = false; 52 53 private final Executor mExecutor = Executors.newSingleThreadExecutor(); 54 ManagerInfoMediaManager( Context context, @NonNull String packageName, @NonNull UserHandle userHandle, LocalBluetoothManager localBluetoothManager, @Nullable MediaController mediaController)55 /* package */ ManagerInfoMediaManager( 56 Context context, 57 @NonNull String packageName, 58 @NonNull UserHandle userHandle, 59 LocalBluetoothManager localBluetoothManager, 60 @Nullable MediaController mediaController) { 61 super(context, packageName, userHandle, localBluetoothManager, mediaController); 62 63 mRouterManager = MediaRouter2Manager.getInstance(context); 64 } 65 66 @Override startScanOnRouter()67 protected void startScanOnRouter() { 68 if (!mIsScanning) { 69 mRouterManager.registerScanRequest(); 70 mIsScanning = true; 71 } 72 } 73 74 @Override registerRouter()75 protected void registerRouter() { 76 mRouterManager.registerCallback(mExecutor, mMediaRouterCallback); 77 } 78 79 @Override stopScanOnRouter()80 protected void stopScanOnRouter() { 81 if (mIsScanning) { 82 mRouterManager.unregisterScanRequest(); 83 mIsScanning = false; 84 } 85 } 86 87 @Override unregisterRouter()88 protected void unregisterRouter() { 89 mRouterManager.unregisterCallback(mMediaRouterCallback); 90 } 91 92 @Override transferToRoute(@onNull MediaRoute2Info route)93 protected void transferToRoute(@NonNull MediaRoute2Info route) { 94 mRouterManager.transfer(mPackageName, route, mUserHandle); 95 } 96 97 @Override selectRoute(@onNull MediaRoute2Info route, @NonNull RoutingSessionInfo info)98 protected void selectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { 99 mRouterManager.selectRoute(info, route); 100 } 101 102 @Override deselectRoute(@onNull MediaRoute2Info route, @NonNull RoutingSessionInfo info)103 protected void deselectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { 104 mRouterManager.deselectRoute(info, route); 105 } 106 107 @Override releaseSession(@onNull RoutingSessionInfo sessionInfo)108 protected void releaseSession(@NonNull RoutingSessionInfo sessionInfo) { 109 mRouterManager.releaseSession(sessionInfo); 110 } 111 112 @Override 113 @NonNull getSelectableRoutes(@onNull RoutingSessionInfo info)114 protected List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo info) { 115 return mRouterManager.getSelectableRoutes(info); 116 } 117 118 @Override 119 @NonNull getDeselectableRoutes(@onNull RoutingSessionInfo info)120 protected List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo info) { 121 return mRouterManager.getDeselectableRoutes(info); 122 } 123 124 @Override 125 @NonNull getSelectedRoutes(@onNull RoutingSessionInfo info)126 protected List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo info) { 127 return mRouterManager.getSelectedRoutes(info); 128 } 129 130 @Override setSessionVolume(@onNull RoutingSessionInfo info, int volume)131 protected void setSessionVolume(@NonNull RoutingSessionInfo info, int volume) { 132 mRouterManager.setSessionVolume(info, volume); 133 } 134 135 @Override setRouteVolume(@onNull MediaRoute2Info route, int volume)136 protected void setRouteVolume(@NonNull MediaRoute2Info route, int volume) { 137 mRouterManager.setRouteVolume(route, volume); 138 } 139 140 @Override 141 @Nullable getRouteListingPreference()142 protected RouteListingPreference getRouteListingPreference() { 143 return mRouterManager.getRouteListingPreference(mPackageName); 144 } 145 146 @Override 147 @NonNull getRoutingSessionsForPackage()148 protected List<RoutingSessionInfo> getRoutingSessionsForPackage() { 149 return mRouterManager.getRoutingSessions(mPackageName); 150 } 151 152 @Override 153 @NonNull getRemoteSessions()154 protected List<RoutingSessionInfo> getRemoteSessions() { 155 return mRouterManager.getRemoteSessions(); 156 } 157 158 @Nullable 159 @Override getRoutingSessionById(@onNull String sessionId)160 protected RoutingSessionInfo getRoutingSessionById(@NonNull String sessionId) { 161 for (RoutingSessionInfo sessionInfo : getRemoteSessions()) { 162 if (TextUtils.equals(sessionInfo.getId(), sessionId)) { 163 return sessionInfo; 164 } 165 } 166 167 RoutingSessionInfo systemSession = mRouterManager.getSystemRoutingSession(null); 168 169 return TextUtils.equals(systemSession.getId(), sessionId) ? systemSession : null; 170 } 171 172 @Override 173 @NonNull getAvailableRoutesFromRouter()174 protected List<MediaRoute2Info> getAvailableRoutesFromRouter() { 175 return mRouterManager.getAvailableRoutes(mPackageName); 176 } 177 178 @Override 179 @NonNull getTransferableRoutes(@onNull String packageName)180 protected List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName) { 181 return mRouterManager.getTransferableRoutes(packageName); 182 } 183 184 @VisibleForTesting 185 /* package */ final class RouterManagerCallback implements MediaRouter2Manager.Callback { 186 187 @Override onRoutesUpdated()188 public void onRoutesUpdated() { 189 refreshDevices(); 190 } 191 192 @Override onPreferredFeaturesChanged(String packageName, List<String> preferredFeatures)193 public void onPreferredFeaturesChanged(String packageName, List<String> preferredFeatures) { 194 if (TextUtils.equals(mPackageName, packageName)) { 195 refreshDevices(); 196 } 197 } 198 199 @Override onTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession)200 public void onTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession) { 201 if (DEBUG) { 202 Log.d( 203 TAG, 204 "onTransferred() oldSession : " 205 + oldSession.getName() 206 + ", newSession : " 207 + newSession.getName()); 208 } 209 rebuildDeviceList(); 210 notifyCurrentConnectedDeviceChanged(); 211 } 212 213 /** 214 * Ignore callback here since we'll also receive{@link 215 * MediaRouter2Manager.Callback#onRequestFailed onRequestFailed} with reason code. 216 */ 217 @Override onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route)218 public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {} 219 220 @Override onRequestFailed(int reason)221 public void onRequestFailed(int reason) { 222 dispatchOnRequestFailed(reason); 223 } 224 225 @Override onSessionUpdated(RoutingSessionInfo sessionInfo)226 public void onSessionUpdated(RoutingSessionInfo sessionInfo) { 227 refreshDevices(); 228 } 229 230 @Override onSessionReleased(@onNull RoutingSessionInfo session)231 public void onSessionReleased(@NonNull RoutingSessionInfo session) { 232 refreshDevices(); 233 } 234 235 @Override onRouteListingPreferenceUpdated( String packageName, RouteListingPreference routeListingPreference)236 public void onRouteListingPreferenceUpdated( 237 String packageName, RouteListingPreference routeListingPreference) { 238 if (!TextUtils.equals(mPackageName, packageName)) { 239 return; 240 } 241 notifyRouteListingPreferenceUpdated(routeListingPreference); 242 refreshDevices(); 243 } 244 } 245 } 246