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.telecom;
18 
19 import static com.android.server.telecom.CallAudioRouteAdapter.PENDING_ROUTE_FAILED;
20 import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
21 import static com.android.server.telecom.CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE;
22 
23 import android.bluetooth.BluetoothDevice;
24 import android.media.AudioManager;
25 import android.telecom.Log;
26 import android.util.ArraySet;
27 import android.util.Pair;
28 
29 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
30 
31 import java.util.Set;
32 
33 /**
34  * Used to represent the intermediate state during audio route switching.
35  * Usually, audio route switching start with a communication device setting request to audio
36  * framework and will be completed with corresponding success broadcasts or messages. Instance of
37  * this class is responsible for tracking the pending success signals according to the original
38  * audio route and the destination audio route of this switching.
39  */
40 public class PendingAudioRoute {
41     private CallAudioRouteController mCallAudioRouteController;
42     private AudioManager mAudioManager;
43     private BluetoothRouteManager mBluetoothRouteManager;
44     /**
45      * The {@link AudioRoute} that this pending audio switching started with
46      */
47     private AudioRoute mOrigRoute;
48     /**
49      * The expected destination {@link AudioRoute} of this pending audio switching, can be changed
50      * by new switching request during the ongoing switching
51      */
52     private AudioRoute mDestRoute;
53     private Set<Pair<Integer, String>> mPendingMessages;
54     private boolean mActive;
55     /**
56      * The device that has been set for communication by Telecom
57      */
58     private @AudioRoute.AudioRouteType int mCommunicationDeviceType = AudioRoute.TYPE_INVALID;
59 
PendingAudioRoute(CallAudioRouteController controller, AudioManager audioManager, BluetoothRouteManager bluetoothRouteManager)60     PendingAudioRoute(CallAudioRouteController controller, AudioManager audioManager,
61             BluetoothRouteManager bluetoothRouteManager) {
62         mCallAudioRouteController = controller;
63         mAudioManager = audioManager;
64         mBluetoothRouteManager = bluetoothRouteManager;
65         mPendingMessages = new ArraySet<>();
66         mActive = false;
67         mCommunicationDeviceType = AudioRoute.TYPE_INVALID;
68     }
69 
setOrigRoute(boolean active, AudioRoute origRoute)70     void setOrigRoute(boolean active, AudioRoute origRoute) {
71         origRoute.onOrigRouteAsPendingRoute(active, this, mAudioManager, mBluetoothRouteManager);
72         mOrigRoute = origRoute;
73     }
74 
getOrigRoute()75     AudioRoute getOrigRoute() {
76         return mOrigRoute;
77     }
78 
setDestRoute(boolean active, AudioRoute destRoute, BluetoothDevice device, boolean isScoAudioConnected)79     void setDestRoute(boolean active, AudioRoute destRoute, BluetoothDevice device,
80             boolean isScoAudioConnected) {
81         destRoute.onDestRouteAsPendingRoute(active, this, device,
82                 mAudioManager, mBluetoothRouteManager, isScoAudioConnected);
83         mActive = active;
84         mDestRoute = destRoute;
85     }
86 
getDestRoute()87     public AudioRoute getDestRoute() {
88         return mDestRoute;
89     }
90 
addMessage(int message, String bluetoothDevice)91     public void addMessage(int message, String bluetoothDevice) {
92         mPendingMessages.add(new Pair<>(message, bluetoothDevice));
93     }
94 
onMessageReceived(Pair<Integer, String> message, String btAddressToExclude)95     public void onMessageReceived(Pair<Integer, String> message, String btAddressToExclude) {
96         Log.i(this, "onMessageReceived: message - %s", message);
97         if (message.first == PENDING_ROUTE_FAILED) {
98             // Fallback to base route
99             mCallAudioRouteController.sendMessageWithSessionInfo(
100                     SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE, btAddressToExclude);
101             return;
102         }
103 
104         // Removes the first occurrence of the specified message from this list, if it is present.
105         mPendingMessages.remove(message);
106         evaluatePendingState();
107     }
108 
evaluatePendingState()109     public void evaluatePendingState() {
110         if (mPendingMessages.isEmpty()) {
111             mCallAudioRouteController.sendMessageWithSessionInfo(
112                     CallAudioRouteAdapter.EXIT_PENDING_ROUTE);
113         } else {
114             Log.i(this, "evaluatePendingState: mPendingMessages - %s", mPendingMessages);
115         }
116     }
117 
clearPendingMessages()118     public void clearPendingMessages() {
119         mPendingMessages.clear();
120     }
121 
clearPendingMessage(Pair<Integer, String> message)122     public void clearPendingMessage(Pair<Integer, String> message) {
123         mPendingMessages.remove(message);
124     }
125 
isActive()126     public boolean isActive() {
127         return mActive;
128     }
129 
getCommunicationDeviceType()130     public @AudioRoute.AudioRouteType int getCommunicationDeviceType() {
131         return mCommunicationDeviceType;
132     }
133 
setCommunicationDeviceType( @udioRoute.AudioRouteType int communicationDeviceType)134     public void setCommunicationDeviceType(
135             @AudioRoute.AudioRouteType int communicationDeviceType) {
136         mCommunicationDeviceType = communicationDeviceType;
137     }
138 
overrideDestRoute(AudioRoute route)139     public void overrideDestRoute(AudioRoute route) {
140         mDestRoute = route;
141     }
142 }
143