1 /*
2  * Copyright (C) 2017 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 android.bluetooth;
18 
19 import android.annotation.Nullable;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 import java.util.Arrays;
24 import java.util.Objects;
25 
26 /**
27  * Represents the codec status (configuration and capability) for a Bluetooth
28  * A2DP source device.
29  *
30  * {@see BluetoothA2dp}
31  *
32  * {@hide}
33  */
34 public final class BluetoothCodecStatus implements Parcelable {
35     /**
36      * Extra for the codec configuration intents of the individual profiles.
37      *
38      * This extra represents the current codec status of the A2DP
39      * profile.
40      */
41     public static final String EXTRA_CODEC_STATUS =
42             "android.bluetooth.extra.CODEC_STATUS";
43 
44     private final @Nullable BluetoothCodecConfig mCodecConfig;
45     private final BluetoothCodecConfig[] mCodecsLocalCapabilities;
46     private final BluetoothCodecConfig[] mCodecsSelectableCapabilities;
47 
BluetoothCodecStatus(@ullable BluetoothCodecConfig codecConfig, @Nullable BluetoothCodecConfig[] codecsLocalCapabilities, @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities)48     public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig,
49             @Nullable BluetoothCodecConfig[] codecsLocalCapabilities,
50             @Nullable BluetoothCodecConfig[] codecsSelectableCapabilities) {
51         mCodecConfig = codecConfig;
52         mCodecsLocalCapabilities = codecsLocalCapabilities;
53         mCodecsSelectableCapabilities = codecsSelectableCapabilities;
54     }
55 
56     @Override
equals(Object o)57     public boolean equals(Object o) {
58         if (o instanceof BluetoothCodecStatus) {
59             BluetoothCodecStatus other = (BluetoothCodecStatus) o;
60             return (Objects.equals(other.mCodecConfig, mCodecConfig)
61                     && sameCapabilities(other.mCodecsLocalCapabilities, mCodecsLocalCapabilities)
62                     && sameCapabilities(other.mCodecsSelectableCapabilities,
63                     mCodecsSelectableCapabilities));
64         }
65         return false;
66     }
67 
68     /**
69      * Checks whether two arrays of capabilities contain same capabilities.
70      * The order of the capabilities in each array is ignored.
71      *
72      * @param c1 the first array of capabilities to compare
73      * @param c2 the second array of capabilities to compare
74      * @return true if both arrays contain same capabilities
75      * @hide
76      */
sameCapabilities(BluetoothCodecConfig[] c1, BluetoothCodecConfig[] c2)77     public static boolean sameCapabilities(BluetoothCodecConfig[] c1,
78                                            BluetoothCodecConfig[] c2) {
79         if (c1 == null) {
80             return (c2 == null);
81         }
82         if (c2 == null) {
83             return false;
84         }
85         if (c1.length != c2.length) {
86             return false;
87         }
88         return Arrays.asList(c1).containsAll(Arrays.asList(c2));
89     }
90 
91     /**
92      * Checks whether the codec config matches the selectable capabilities.
93      * Any parameters of the codec config with NONE value will be considered a wildcard matching.
94      *
95      * @param codecConfig the codec config to compare against
96      * @return true if the codec config matches, otherwise false
97      * @hide
98      */
isCodecConfigSelectable(BluetoothCodecConfig codecConfig)99     public boolean isCodecConfigSelectable(BluetoothCodecConfig codecConfig) {
100         if (codecConfig == null || !codecConfig.hasSingleSampleRate()
101                 || !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
102             return false;
103         }
104         for (BluetoothCodecConfig selectableConfig : mCodecsSelectableCapabilities) {
105             if (codecConfig.getCodecType() != selectableConfig.getCodecType()) {
106                 continue;
107             }
108             int sampleRate = codecConfig.getSampleRate();
109             if ((sampleRate & selectableConfig.getSampleRate()) == 0
110                     && sampleRate != BluetoothCodecConfig.SAMPLE_RATE_NONE) {
111                 continue;
112             }
113             int bitsPerSample = codecConfig.getBitsPerSample();
114             if ((bitsPerSample & selectableConfig.getBitsPerSample()) == 0
115                     && bitsPerSample != BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
116                 continue;
117             }
118             int channelMode = codecConfig.getChannelMode();
119             if ((channelMode & selectableConfig.getChannelMode()) == 0
120                     && channelMode != BluetoothCodecConfig.CHANNEL_MODE_NONE) {
121                 continue;
122             }
123             return true;
124         }
125         return false;
126     }
127 
128     /**
129      * Returns a hash based on the codec config and local capabilities
130      *
131      * @return a hash based on the config values
132      * @hide
133      */
134     @Override
hashCode()135     public int hashCode() {
136         return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
137                 mCodecsLocalCapabilities);
138     }
139 
140     @Override
toString()141     public String toString() {
142         return "{mCodecConfig:" + mCodecConfig
143                 + ",mCodecsLocalCapabilities:" + Arrays.toString(mCodecsLocalCapabilities)
144                 + ",mCodecsSelectableCapabilities:" + Arrays.toString(mCodecsSelectableCapabilities)
145                 + "}";
146     }
147 
148     /**
149      * Always returns 0
150      *
151      * @return 0
152      * @hide
153      */
154     @Override
describeContents()155     public int describeContents() {
156         return 0;
157     }
158 
159     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecStatus> CREATOR =
160             new Parcelable.Creator<BluetoothCodecStatus>() {
161                 public BluetoothCodecStatus createFromParcel(Parcel in) {
162                     final BluetoothCodecConfig codecConfig = in.readTypedObject(
163                             BluetoothCodecConfig.CREATOR);
164                     final BluetoothCodecConfig[] codecsLocalCapabilities = in.createTypedArray(
165                             BluetoothCodecConfig.CREATOR);
166                     final BluetoothCodecConfig[] codecsSelectableCapabilities = in.createTypedArray(
167                             BluetoothCodecConfig.CREATOR);
168 
169                     return new BluetoothCodecStatus(codecConfig,
170                             codecsLocalCapabilities,
171                             codecsSelectableCapabilities);
172                 }
173 
174                 public BluetoothCodecStatus[] newArray(int size) {
175                     return new BluetoothCodecStatus[size];
176                 }
177             };
178 
179     /**
180      * Flattens the object to a parcel
181      *
182      * @param out The Parcel in which the object should be written.
183      * @param flags Additional flags about how the object should be written.
184      *
185      * @hide
186      */
187     @Override
writeToParcel(Parcel out, int flags)188     public void writeToParcel(Parcel out, int flags) {
189         out.writeTypedObject(mCodecConfig, 0);
190         out.writeTypedArray(mCodecsLocalCapabilities, 0);
191         out.writeTypedArray(mCodecsSelectableCapabilities, 0);
192     }
193 
194     /**
195      * Gets the current codec configuration.
196      *
197      * @return the current codec configuration
198      */
getCodecConfig()199     public @Nullable BluetoothCodecConfig getCodecConfig() {
200         return mCodecConfig;
201     }
202 
203     /**
204      * Gets the codecs local capabilities.
205      *
206      * @return an array with the codecs local capabilities
207      */
getCodecsLocalCapabilities()208     public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
209         return mCodecsLocalCapabilities;
210     }
211 
212     /**
213      * Gets the codecs selectable capabilities.
214      *
215      * @return an array with the codecs selectable capabilities
216      */
getCodecsSelectableCapabilities()217     public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
218         return mCodecsSelectableCapabilities;
219     }
220 }
221