blob: 66985e0b25334ba0d59a3914eec03f185f10c030 [file] [log] [blame]
/*
* 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 android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.media.MediaRoute2Info;
import android.os.UserHandle;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* Provides control over bluetooth routes.
*/
/* package */ interface BluetoothRouteController {
/**
* Returns a new instance of {@link LegacyBluetoothRouteController}.
*
* <p>It may return {@link NoOpBluetoothRouteController} if Bluetooth is not supported on this
* hardware platform.
*/
@NonNull
static BluetoothRouteController createInstance(@NonNull Context context,
@NonNull BluetoothRouteController.BluetoothRoutesUpdatedListener listener) {
Objects.requireNonNull(context);
Objects.requireNonNull(listener);
BluetoothManager bluetoothManager = (BluetoothManager)
context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter btAdapter = bluetoothManager.getAdapter();
if (btAdapter == null) {
return new NoOpBluetoothRouteController();
}
MediaFeatureFlagManager flagManager = MediaFeatureFlagManager.getInstance();
boolean isUsingLegacyController = flagManager.getBoolean(
MediaFeatureFlagManager.FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER,
true);
if (isUsingLegacyController) {
return new LegacyBluetoothRouteController(context, btAdapter, listener);
} else {
return new AudioPoliciesBluetoothRouteController(context, btAdapter, listener);
}
}
/**
* Makes the controller to listen to events from Bluetooth stack.
*
* @param userHandle is needed to subscribe for broadcasts on user's behalf.
*/
void start(@NonNull UserHandle userHandle);
/**
* Stops the controller from listening to any Bluetooth events.
*/
void stop();
/**
* Selects the route with the given {@code deviceAddress}.
*
* @param deviceAddress The physical address of the device to select. May be null to unselect
* the currently selected device.
* @return Whether the selection succeeds. If the selection fails, the state of the instance
* remains unaltered.
*/
boolean selectRoute(@Nullable String deviceAddress);
/**
* Transfers Bluetooth output to the given route.
*
* <p>If the route is {@code null} then active route will be deactivated.
*
* @param routeId to switch to or {@code null} to unset the active device.
*/
void transferTo(@Nullable String routeId);
/**
* Returns currently selected Bluetooth route.
*
* @return the selected route or {@code null} if there are no active routes.
*/
@Nullable
MediaRoute2Info getSelectedRoute();
/**
* Returns transferable routes.
*
* <p>A route is considered to be transferable if the bluetooth device is connected but not
* considered as selected.
*
* @return list of transferable routes or an empty list.
*/
@NonNull
List<MediaRoute2Info> getTransferableRoutes();
/**
* Provides all connected Bluetooth routes.
*
* @return list of Bluetooth routes or an empty list.
*/
@NonNull
List<MediaRoute2Info> getAllBluetoothRoutes();
/**
* Updates the volume for all Bluetooth devices for the given profile.
*
* @param devices specifies the profile, may be, {@link android.bluetooth.BluetoothA2dp}, {@link
* android.bluetooth.BluetoothLeAudio}, or {@link android.bluetooth.BluetoothHearingAid}
* @param volume the specific volume value for the given devices or 0 if unknown.
* @return {@code true} if updated successfully and {@code false} otherwise.
*/
boolean updateVolumeForDevices(int devices, int volume);
/**
* Interface for receiving events about Bluetooth routes changes.
*/
interface BluetoothRoutesUpdatedListener {
/**
* Called when Bluetooth routes have changed.
*
* @param routes updated Bluetooth routes list.
*/
void onBluetoothRoutesUpdated(@NonNull List<MediaRoute2Info> routes);
}
/**
* No-op implementation of {@link BluetoothRouteController}.
*
* <p>Useful if the device does not support Bluetooth.
*/
class NoOpBluetoothRouteController implements BluetoothRouteController {
@Override
public void start(UserHandle userHandle) {
// no op
}
@Override
public void stop() {
// no op
}
@Override
public boolean selectRoute(String deviceAddress) {
// no op
return false;
}
@Override
public void transferTo(String routeId) {
// no op
}
@Override
public MediaRoute2Info getSelectedRoute() {
// no op
return null;
}
@Override
public List<MediaRoute2Info> getTransferableRoutes() {
// no op
return Collections.emptyList();
}
@Override
public List<MediaRoute2Info> getAllBluetoothRoutes() {
// no op
return Collections.emptyList();
}
@Override
public boolean updateVolumeForDevices(int devices, int volume) {
// no op
return false;
}
}
}