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.server.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothManager; 23 import android.content.Context; 24 import android.media.MediaRoute2Info; 25 import android.os.UserHandle; 26 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Objects; 30 31 /** 32 * Provides control over bluetooth routes. 33 */ 34 /* package */ interface BluetoothRouteController { 35 36 /** 37 * Returns a new instance of {@link LegacyBluetoothRouteController}. 38 * 39 * <p>It may return {@link NoOpBluetoothRouteController} if Bluetooth is not supported on this 40 * hardware platform. 41 */ 42 @NonNull createInstance(@onNull Context context, @NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener)43 static BluetoothRouteController createInstance(@NonNull Context context, 44 @NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) { 45 Objects.requireNonNull(context); 46 Objects.requireNonNull(listener); 47 48 BluetoothManager bluetoothManager = (BluetoothManager) 49 context.getSystemService(Context.BLUETOOTH_SERVICE); 50 BluetoothAdapter btAdapter = bluetoothManager.getAdapter(); 51 52 if (btAdapter == null) { 53 return new NoOpBluetoothRouteController(); 54 } 55 56 MediaFeatureFlagManager flagManager = MediaFeatureFlagManager.getInstance(); 57 boolean isUsingLegacyController = flagManager.getBoolean( 58 MediaFeatureFlagManager.FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER, 59 true); 60 61 if (isUsingLegacyController) { 62 return new LegacyBluetoothRouteController(context, btAdapter, listener); 63 } else { 64 return new AudioPoliciesBluetoothRouteController(context, btAdapter, listener); 65 } 66 } 67 68 /** 69 * Makes the controller to listen to events from Bluetooth stack. 70 * 71 * @param userHandle is needed to subscribe for broadcasts on user's behalf. 72 */ start(@onNull UserHandle userHandle)73 void start(@NonNull UserHandle userHandle); 74 75 /** 76 * Stops the controller from listening to any Bluetooth events. 77 */ stop()78 void stop(); 79 80 81 /** 82 * Selects the route with the given {@code deviceAddress}. 83 * 84 * @param deviceAddress The physical address of the device to select. May be null to unselect 85 * the currently selected device. 86 * @return Whether the selection succeeds. If the selection fails, the state of the instance 87 * remains unaltered. 88 */ selectRoute(@ullable String deviceAddress)89 boolean selectRoute(@Nullable String deviceAddress); 90 91 /** 92 * Transfers Bluetooth output to the given route. 93 * 94 * <p>If the route is {@code null} then active route will be deactivated. 95 * 96 * @param routeId to switch to or {@code null} to unset the active device. 97 */ transferTo(@ullable String routeId)98 void transferTo(@Nullable String routeId); 99 100 /** 101 * Returns currently selected Bluetooth route. 102 * 103 * @return the selected route or {@code null} if there are no active routes. 104 */ 105 @Nullable getSelectedRoute()106 MediaRoute2Info getSelectedRoute(); 107 108 /** 109 * Returns transferable routes. 110 * 111 * <p>A route is considered to be transferable if the bluetooth device is connected but not 112 * considered as selected. 113 * 114 * @return list of transferable routes or an empty list. 115 */ 116 @NonNull getTransferableRoutes()117 List<MediaRoute2Info> getTransferableRoutes(); 118 119 /** 120 * Provides all connected Bluetooth routes. 121 * 122 * @return list of Bluetooth routes or an empty list. 123 */ 124 @NonNull getAllBluetoothRoutes()125 List<MediaRoute2Info> getAllBluetoothRoutes(); 126 127 /** 128 * Updates the volume for all Bluetooth devices for the given profile. 129 * 130 * @param devices specifies the profile, may be, {@link android.bluetooth.BluetoothA2dp}, {@link 131 * android.bluetooth.BluetoothLeAudio}, or {@link android.bluetooth.BluetoothHearingAid} 132 * @param volume the specific volume value for the given devices or 0 if unknown. 133 * @return {@code true} if updated successfully and {@code false} otherwise. 134 */ updateVolumeForDevices(int devices, int volume)135 boolean updateVolumeForDevices(int devices, int volume); 136 137 /** 138 * Interface for receiving events about Bluetooth routes changes. 139 */ 140 interface BluetoothRoutesUpdatedListener { 141 142 /** 143 * Called when Bluetooth routes have changed. 144 * 145 * @param routes updated Bluetooth routes list. 146 */ onBluetoothRoutesUpdated(@onNull List<MediaRoute2Info> routes)147 void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes); 148 } 149 150 /** 151 * No-op implementation of {@link BluetoothRouteController}. 152 * 153 * <p>Useful if the device does not support Bluetooth. 154 */ 155 class NoOpBluetoothRouteController implements BluetoothRouteController { 156 157 @Override start(UserHandle userHandle)158 public void start(UserHandle userHandle) { 159 // no op 160 } 161 162 @Override stop()163 public void stop() { 164 // no op 165 } 166 167 @Override selectRoute(String deviceAddress)168 public boolean selectRoute(String deviceAddress) { 169 // no op 170 return false; 171 } 172 173 @Override transferTo(String routeId)174 public void transferTo(String routeId) { 175 // no op 176 } 177 178 @Override getSelectedRoute()179 public MediaRoute2Info getSelectedRoute() { 180 // no op 181 return null; 182 } 183 184 @Override getTransferableRoutes()185 public List<MediaRoute2Info> getTransferableRoutes() { 186 // no op 187 return Collections.emptyList(); 188 } 189 190 @Override getAllBluetoothRoutes()191 public List<MediaRoute2Info> getAllBluetoothRoutes() { 192 // no op 193 return Collections.emptyList(); 194 } 195 196 @Override updateVolumeForDevices(int devices, int volume)197 public boolean updateVolumeForDevices(int devices, int volume) { 198 // no op 199 return false; 200 } 201 } 202 } 203