• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.RequiresPermission;
23 import android.bluetooth.BluetoothAdapter;
24 import android.bluetooth.BluetoothManager;
25 import android.content.Context;
26 import android.media.AudioManager;
27 import android.media.IAudioService;
28 import android.media.MediaRoute2Info;
29 import android.media.audiopolicy.AudioProductStrategy;
30 import android.os.Looper;
31 import android.os.ServiceManager;
32 import android.os.UserHandle;
33 
34 import com.android.media.flags.Flags;
35 
36 import java.util.List;
37 
38 /**
39  * Controls device routes.
40  *
41  * <p>A device route is a system wired route, for example, built-in speaker, wired
42  * headsets and headphones, dock, hdmi, or usb devices.
43  *
44  * @see SystemMediaRoute2Provider
45  */
46 /* package */ interface DeviceRouteController {
47 
48     /** Returns a new instance of {@link DeviceRouteController}. */
49     @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING)
createInstance( @onNull Context context, @NonNull Looper looper, @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener)50     /* package */ static DeviceRouteController createInstance(
51             @NonNull Context context,
52             @NonNull Looper looper,
53             @NonNull OnDeviceRouteChangedListener onDeviceRouteChangedListener) {
54         AudioManager audioManager = context.getSystemService(AudioManager.class);
55         AudioProductStrategy strategyForMedia = AudioRoutingUtils.getMediaAudioProductStrategy();
56 
57         BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class);
58         BluetoothAdapter btAdapter =
59                 bluetoothManager != null ? bluetoothManager.getAdapter() : null;
60 
61         // TODO: b/305199571 - Make the audio policies implementation work without the need for a
62         // bluetooth adapter or a strategy for media. If no strategy for media is available we can
63         // disallow media router transfers, and without a bluetooth adapter we can remove support
64         // for transfers to inactive bluetooth routes.
65         if (strategyForMedia != null
66                 && btAdapter != null
67                 && Flags.enableAudioPoliciesDeviceAndBluetoothController()) {
68             AudioManagerRouteController controller =
69                     AudioManagerRouteController.getInstance(
70                             context, audioManager, looper, strategyForMedia, btAdapter);
71             controller.registerRouteChangeListener(onDeviceRouteChangedListener);
72             return controller;
73         } else {
74             IAudioService audioService =
75                     IAudioService.Stub.asInterface(
76                             ServiceManager.getService(Context.AUDIO_SERVICE));
77             return new LegacyDeviceRouteController(
78                     context, audioManager, audioService, onDeviceRouteChangedListener);
79         }
80     }
81 
82     /** Returns device route availability status. */
83     @MediaRoute2Info.SuitabilityStatus
getBuiltInSpeakerSuitabilityStatus(@onNull Context context)84     static int getBuiltInSpeakerSuitabilityStatus(@NonNull Context context) {
85         if (!Flags.enableBuiltInSpeakerRouteSuitabilityStatuses()) {
86             // Route is always suitable if the flag is disabled.
87             return MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
88         }
89 
90         int availabilityStatus =
91                 context.getResources()
92                         .getInteger(
93                                 com.android.internal.R.integer
94                                         .config_mediaRouter_builtInSpeakerSuitability);
95 
96         switch (availabilityStatus) {
97             case MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER:
98             case MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_MANUAL_TRANSFER:
99             case MediaRoute2Info.SUITABILITY_STATUS_NOT_SUITABLE_FOR_TRANSFER:
100                 return availabilityStatus;
101             default:
102                 return MediaRoute2Info.SUITABILITY_STATUS_SUITABLE_FOR_DEFAULT_TRANSFER;
103         }
104     }
105 
106     /** Returns the currently selected device (built-in or wired) route. */
107     @NonNull
getSelectedRoute()108     MediaRoute2Info getSelectedRoute();
109 
110     /**
111      * Returns all available routes.
112      *
113      * <p>Note that this method returns available routes including the selected route because (a)
114      * this interface doesn't guarantee that the internal state of the controller won't change
115      * between calls to {@link #getSelectedRoute()} and this method and (b) {@link
116      * #getSelectedRoute()} may be treated as a transferable route (not a selected route) if the
117      * selected route is from {@link BluetoothRouteController}.
118      */
getAvailableRoutes()119     List<MediaRoute2Info> getAvailableRoutes();
120 
121     /**
122      * Transfers device output to the given route.
123      *
124      * <p>If the route is {@code null} then active route will be deactivated.
125      *
126      * @param routeId to switch to or {@code null} to unset the active device.
127      */
transferTo(@ullable String routeId)128     void transferTo(@Nullable String routeId);
129 
130     /**
131      * Updates device route volume.
132      *
133      * @param volume specifies a volume for the device route or 0 for unknown.
134      * @return {@code true} if updated successfully and {@code false} otherwise.
135      */
updateVolume(int volume)136     boolean updateVolume(int volume);
137 
138     /**
139      * Starts listening for changes in the system to keep an up to date view of available and
140      * selected devices.
141      */
start(UserHandle mUser)142     void start(UserHandle mUser);
143 
144     /**
145      * Stops keeping the internal state up to date with the system, releasing any resources acquired
146      * in {@link #start}
147      */
stop()148     void stop();
149 
150     /**
151      * Interface for receiving events when device route has changed.
152      */
153     interface OnDeviceRouteChangedListener {
154 
155         /** Called when device route has changed. */
onDeviceRouteChanged()156         void onDeviceRouteChanged();
157     }
158 
159 }
160