blob: 4b827d2e29a234b3b7c6972d769dadf4b9affc73 [file] [log] [blame]
Yorke Lee4af59352015-05-13 14:14:54 -07001/*
2 * Copyright (C) 2014 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
17package android.telecom;
18
Hall Liua98f58b52017-11-07 17:59:28 -080019import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.bluetooth.BluetoothDevice;
Yorke Lee4af59352015-05-13 14:14:54 -070023import android.os.Parcel;
24import android.os.Parcelable;
25
Hall Liua98f58b52017-11-07 17:59:28 -080026import java.lang.annotation.Retention;
27import java.lang.annotation.RetentionPolicy;
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.List;
Yorke Lee4af59352015-05-13 14:14:54 -070033import java.util.Locale;
Hall Liua98f58b52017-11-07 17:59:28 -080034import java.util.Objects;
35import java.util.stream.Collectors;
Yorke Lee4af59352015-05-13 14:14:54 -070036
37/**
38 * Encapsulates the telecom audio state, including the current audio routing, supported audio
39 * routing and mute.
40 */
41public final class CallAudioState implements Parcelable {
Hall Liua98f58b52017-11-07 17:59:28 -080042 /** @hide */
43 @Retention(RetentionPolicy.SOURCE)
44 @IntDef(value={ROUTE_EARPIECE, ROUTE_BLUETOOTH, ROUTE_WIRED_HEADSET, ROUTE_SPEAKER},
45 flag=true)
46 public @interface CallAudioRoute {}
47
Yorke Lee4af59352015-05-13 14:14:54 -070048 /** Direct the audio stream through the device's earpiece. */
49 public static final int ROUTE_EARPIECE = 0x00000001;
50
51 /** Direct the audio stream through Bluetooth. */
52 public static final int ROUTE_BLUETOOTH = 0x00000002;
53
54 /** Direct the audio stream through a wired headset. */
55 public static final int ROUTE_WIRED_HEADSET = 0x00000004;
56
57 /** Direct the audio stream through the device's speakerphone. */
58 public static final int ROUTE_SPEAKER = 0x00000008;
59
60 /**
61 * Direct the audio stream through the device's earpiece or wired headset if one is
62 * connected.
63 */
64 public static final int ROUTE_WIRED_OR_EARPIECE = ROUTE_EARPIECE | ROUTE_WIRED_HEADSET;
65
Christine Hallstrom4e22d6d2016-11-30 16:06:42 -080066 /**
67 * Bit mask of all possible audio routes.
68 *
69 * @hide
70 **/
71 public static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
Yorke Lee4af59352015-05-13 14:14:54 -070072 ROUTE_SPEAKER;
73
74 private final boolean isMuted;
75 private final int route;
76 private final int supportedRouteMask;
Hall Liua98f58b52017-11-07 17:59:28 -080077 private final BluetoothDevice activeBluetoothDevice;
78 private final Collection<BluetoothDevice> supportedBluetoothDevices;
Yorke Lee4af59352015-05-13 14:14:54 -070079
80 /**
81 * Constructor for a {@link CallAudioState} object.
82 *
83 * @param muted {@code true} if the call is muted, {@code false} otherwise.
84 * @param route The current audio route being used.
85 * Allowed values:
86 * {@link #ROUTE_EARPIECE}
87 * {@link #ROUTE_BLUETOOTH}
88 * {@link #ROUTE_WIRED_HEADSET}
89 * {@link #ROUTE_SPEAKER}
90 * @param supportedRouteMask Bit mask of all routes supported by this call. This should be a
91 * bitwise combination of the following values:
92 * {@link #ROUTE_EARPIECE}
93 * {@link #ROUTE_BLUETOOTH}
94 * {@link #ROUTE_WIRED_HEADSET}
95 * {@link #ROUTE_SPEAKER}
96 */
Hall Liua98f58b52017-11-07 17:59:28 -080097 public CallAudioState(boolean muted, @CallAudioRoute int route,
98 @CallAudioRoute int supportedRouteMask) {
99 this(muted, route, supportedRouteMask, null, Collections.emptyList());
100 }
101
102 /** @hide */
103 public CallAudioState(boolean isMuted, @CallAudioRoute int route,
104 @CallAudioRoute int supportedRouteMask,
105 @Nullable BluetoothDevice activeBluetoothDevice,
106 @NonNull Collection<BluetoothDevice> supportedBluetoothDevices) {
107 this.isMuted = isMuted;
Yorke Lee4af59352015-05-13 14:14:54 -0700108 this.route = route;
109 this.supportedRouteMask = supportedRouteMask;
Hall Liua98f58b52017-11-07 17:59:28 -0800110 this.activeBluetoothDevice = activeBluetoothDevice;
111 this.supportedBluetoothDevices = supportedBluetoothDevices;
Yorke Lee4af59352015-05-13 14:14:54 -0700112 }
113
114 /** @hide */
115 public CallAudioState(CallAudioState state) {
116 isMuted = state.isMuted();
117 route = state.getRoute();
118 supportedRouteMask = state.getSupportedRouteMask();
Hall Liua98f58b52017-11-07 17:59:28 -0800119 activeBluetoothDevice = state.activeBluetoothDevice;
120 supportedBluetoothDevices = state.getSupportedBluetoothDevices();
Yorke Lee4af59352015-05-13 14:14:54 -0700121 }
122
123 /** @hide */
124 @SuppressWarnings("deprecation")
125 public CallAudioState(AudioState state) {
126 isMuted = state.isMuted();
127 route = state.getRoute();
128 supportedRouteMask = state.getSupportedRouteMask();
Hall Liua98f58b52017-11-07 17:59:28 -0800129 activeBluetoothDevice = null;
130 supportedBluetoothDevices = Collections.emptyList();
Yorke Lee4af59352015-05-13 14:14:54 -0700131 }
132
133 @Override
134 public boolean equals(Object obj) {
135 if (obj == null) {
136 return false;
137 }
138 if (!(obj instanceof CallAudioState)) {
139 return false;
140 }
141 CallAudioState state = (CallAudioState) obj;
Hall Liua98f58b52017-11-07 17:59:28 -0800142 if (supportedBluetoothDevices.size() != state.supportedBluetoothDevices.size()) {
143 return false;
144 }
145 for (BluetoothDevice device : supportedBluetoothDevices) {
146 if (!state.supportedBluetoothDevices.contains(device)) {
147 return false;
148 }
149 }
150 return Objects.equals(activeBluetoothDevice, state.activeBluetoothDevice) && isMuted() ==
151 state.isMuted() && getRoute() == state.getRoute() && getSupportedRouteMask() ==
152 state.getSupportedRouteMask();
Yorke Lee4af59352015-05-13 14:14:54 -0700153 }
154
155 @Override
156 public String toString() {
Hall Liua98f58b52017-11-07 17:59:28 -0800157 String bluetoothDeviceList = supportedBluetoothDevices.stream()
158 .map(BluetoothDevice::getAddress).collect(Collectors.joining(", "));
159
Yorke Lee4af59352015-05-13 14:14:54 -0700160 return String.format(Locale.US,
Hall Liua98f58b52017-11-07 17:59:28 -0800161 "[AudioState isMuted: %b, route: %s, supportedRouteMask: %s, " +
162 "activeBluetoothDevice: [%s], supportedBluetoothDevices: [%s]]",
Yorke Lee4af59352015-05-13 14:14:54 -0700163 isMuted,
164 audioRouteToString(route),
Hall Liua98f58b52017-11-07 17:59:28 -0800165 audioRouteToString(supportedRouteMask),
166 activeBluetoothDevice,
167 bluetoothDeviceList);
Yorke Lee4af59352015-05-13 14:14:54 -0700168 }
169
170 /**
171 * @return {@code true} if the call is muted, {@code false} otherwise.
172 */
173 public boolean isMuted() {
174 return isMuted;
175 }
176
177 /**
178 * @return The current audio route being used.
179 */
Hall Liua98f58b52017-11-07 17:59:28 -0800180 @CallAudioRoute
Yorke Lee4af59352015-05-13 14:14:54 -0700181 public int getRoute() {
182 return route;
183 }
184
185 /**
186 * @return Bit mask of all routes supported by this call.
187 */
Hall Liua98f58b52017-11-07 17:59:28 -0800188 @CallAudioRoute
Yorke Lee4af59352015-05-13 14:14:54 -0700189 public int getSupportedRouteMask() {
190 return supportedRouteMask;
191 }
192
193 /**
Hall Liua98f58b52017-11-07 17:59:28 -0800194 * @return The {@link BluetoothDevice} through which audio is being routed.
195 * Will not be {@code null} if {@link #getRoute()} returns {@link #ROUTE_BLUETOOTH}.
196 */
197 public BluetoothDevice getActiveBluetoothDevice() {
198 return activeBluetoothDevice;
199 }
200
201 /**
202 * @return {@link List} of {@link BluetoothDevice}s that can be used for this call.
203 */
204 public Collection<BluetoothDevice> getSupportedBluetoothDevices() {
205 return supportedBluetoothDevices;
206 }
207
208 /**
Yorke Lee4af59352015-05-13 14:14:54 -0700209 * Converts the provided audio route into a human readable string representation.
210 *
211 * @param route to convert into a string.
212 *
213 * @return String representation of the provided audio route.
214 */
215 public static String audioRouteToString(int route) {
216 if (route == 0 || (route & ~ROUTE_ALL) != 0x0) {
217 return "UNKNOWN";
218 }
219
220 StringBuffer buffer = new StringBuffer();
221 if ((route & ROUTE_EARPIECE) == ROUTE_EARPIECE) {
222 listAppend(buffer, "EARPIECE");
223 }
224 if ((route & ROUTE_BLUETOOTH) == ROUTE_BLUETOOTH) {
225 listAppend(buffer, "BLUETOOTH");
226 }
227 if ((route & ROUTE_WIRED_HEADSET) == ROUTE_WIRED_HEADSET) {
228 listAppend(buffer, "WIRED_HEADSET");
229 }
230 if ((route & ROUTE_SPEAKER) == ROUTE_SPEAKER) {
231 listAppend(buffer, "SPEAKER");
232 }
233
234 return buffer.toString();
235 }
236
237 /**
238 * Responsible for creating AudioState objects for deserialized Parcels.
239 */
240 public static final Parcelable.Creator<CallAudioState> CREATOR =
241 new Parcelable.Creator<CallAudioState> () {
242
243 @Override
244 public CallAudioState createFromParcel(Parcel source) {
245 boolean isMuted = source.readByte() == 0 ? false : true;
246 int route = source.readInt();
247 int supportedRouteMask = source.readInt();
Hall Liua98f58b52017-11-07 17:59:28 -0800248 BluetoothDevice activeBluetoothDevice = source.readParcelable(
249 ClassLoader.getSystemClassLoader());
250 List<BluetoothDevice> supportedBluetoothDevices = new ArrayList<>();
251 source.readParcelableList(supportedBluetoothDevices,
252 ClassLoader.getSystemClassLoader());
253 return new CallAudioState(isMuted, route,
254 supportedRouteMask, activeBluetoothDevice, supportedBluetoothDevices);
Yorke Lee4af59352015-05-13 14:14:54 -0700255 }
256
257 @Override
258 public CallAudioState[] newArray(int size) {
259 return new CallAudioState[size];
260 }
261 };
262
263 /**
264 * {@inheritDoc}
265 */
266 @Override
267 public int describeContents() {
268 return 0;
269 }
270
271 /**
272 * Writes AudioState object into a serializeable Parcel.
273 */
274 @Override
275 public void writeToParcel(Parcel destination, int flags) {
276 destination.writeByte((byte) (isMuted ? 1 : 0));
277 destination.writeInt(route);
278 destination.writeInt(supportedRouteMask);
Hall Liua98f58b52017-11-07 17:59:28 -0800279 destination.writeParcelable(activeBluetoothDevice, 0);
280 destination.writeParcelableList(new ArrayList<>(supportedBluetoothDevices), 0);
Yorke Lee4af59352015-05-13 14:14:54 -0700281 }
282
283 private static void listAppend(StringBuffer buffer, String str) {
284 if (buffer.length() > 0) {
285 buffer.append(", ");
286 }
287 buffer.append(str);
288 }
289}