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