1 /*
2  * Copyright 2022 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.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.lang.annotation.Retention;
27 import java.lang.annotation.RetentionPolicy;
28 import java.util.Objects;
29 
30 /**
31  * Represents Bluetooth Audio Policies of a Handsfree (HF) device (if HFP is used) and Call Terminal
32  * (CT) device (if BLE Audio is used), which describes the preferences of allowing or disallowing
33  * audio based on the use cases. The HF/CT devices shall send objects of this class to send its
34  * preference to the AG/CG devices.
35  *
36  * <p>HF/CT side applications on can use {@link BluetoothDevice#requestAudioPolicyAsSink} API to set
37  * and send a {@link BluetoothSinkAudioPolicy} object containing the preference/policy values. This
38  * object will be stored in the memory of HF/CT side, will be send to the AG/CG side using Android
39  * Specific AT Commands and will be stored in the AG side memory and database.
40  *
41  * <p>HF/CT side API {@link BluetoothDevice#getRequestedAudioPolicyAsSink} can be used to retrieve
42  * the stored audio policies currently.
43  *
44  * <p>Note that the setter APIs of this class will only set the values of the object. To actually
45  * set the policies, API {@link BluetoothDevice#requestAudioPolicyAsSink} must need to be invoked
46  * with the {@link BluetoothSinkAudioPolicy} object.
47  *
48  * <p>Note that any API related to this feature should be used after configuring the support of the
49  * AG device and after checking whether the AG device supports this feature or not by invoking
50  * {@link BluetoothDevice#isRequestAudioPolicyAsSinkSupported}. Only after getting a {@link
51  * BluetoothStatusCodes#FEATURE_SUPPORTED} response from the API should the APIs related to this
52  * feature be used.
53  *
54  * @hide
55  */
56 @SystemApi
57 public final class BluetoothSinkAudioPolicy implements Parcelable {
58 
59     /** @hide */
60     @Retention(RetentionPolicy.SOURCE)
61     @IntDef(
62             prefix = {"POLICY_"},
63             value = {
64                 POLICY_UNCONFIGURED,
65                 POLICY_ALLOWED,
66                 POLICY_NOT_ALLOWED,
67             })
68     public @interface AudioPolicyValues {}
69 
70     /**
71      * Audio behavior not configured for the policy.
72      *
73      * <p>If a policy is set with this value, it means that the policy is not configured with a
74      * value yet and should not be used to make any decision.
75      *
76      * @hide
77      */
78     @SystemApi public static final int POLICY_UNCONFIGURED = 0;
79 
80     /**
81      * Audio is preferred by HF device for the policy.
82      *
83      * <p>If a policy is set with this value, then the HF device will prefer the audio for the
84      * policy use case. For example, if the Call Establish audio policy is set with this value, then
85      * the HF will prefer the audio during making or picking up a call.
86      *
87      * @hide
88      */
89     @SystemApi public static final int POLICY_ALLOWED = 1;
90 
91     /**
92      * Audio is not preferred by HF device for the policy.
93      *
94      * <p>If a policy is set with this value, then the HF device will not prefer the audio for the
95      * policy use case. For example, if the Call Establish audio policy is set with this value, then
96      * the HF will not prefer the audio during making or picking up a call.
97      *
98      * @hide
99      */
100     @SystemApi public static final int POLICY_NOT_ALLOWED = 2;
101 
102     /**
103      * The feature ID used in the HFP AT command.
104      *
105      * @hide
106      */
107     public static final String HFP_SET_SINK_AUDIO_POLICY_ID = "SINKAUDIOPOLICY";
108 
109     @AudioPolicyValues private final int mCallEstablishPolicy;
110     @AudioPolicyValues private final int mConnectingTimePolicy;
111     @AudioPolicyValues private final int mInBandRingtonePolicy;
112 
113     /** @hide */
BluetoothSinkAudioPolicy( int callEstablishPolicy, int connectingTimePolicy, int inBandRingtonePolicy)114     public BluetoothSinkAudioPolicy(
115             int callEstablishPolicy, int connectingTimePolicy, int inBandRingtonePolicy) {
116         mCallEstablishPolicy = callEstablishPolicy;
117         mConnectingTimePolicy = connectingTimePolicy;
118         mInBandRingtonePolicy = inBandRingtonePolicy;
119     }
120 
121     /**
122      * Get Call establishment policy audio policy.
123      *
124      * <p>This policy is used to determine the audio preference when the HF device makes or answers
125      * a call. That is, if this device makes or answers a call, is the audio preferred by HF.
126      *
127      * @return the call pick up audio policy value
128      * @hide
129      */
130     @SystemApi
getCallEstablishPolicy()131     public @AudioPolicyValues int getCallEstablishPolicy() {
132         return mCallEstablishPolicy;
133     }
134 
135     /**
136      * Get during connection audio up policy.
137      *
138      * <p>This policy is used to determine the audio preference when the HF device connects with the
139      * AG device. That is, when the HF device gets connected, should the HF become active and get
140      * audio is decided by this policy. This also covers the case of during a call. If the HF
141      * connects with the AG during an ongoing call, should the call audio be routed to the HF will
142      * be decided by this policy.
143      *
144      * @return the during connection audio policy value
145      * @hide
146      */
147     @SystemApi
getActiveDevicePolicyAfterConnection()148     public @AudioPolicyValues int getActiveDevicePolicyAfterConnection() {
149         return mConnectingTimePolicy;
150     }
151 
152     /**
153      * Get In band ringtone audio up policy.
154      *
155      * <p>This policy is used to determine the audio preference of the in band ringtone. That is, if
156      * there is an incoming call, should the inband ringtone audio be routed to the HF will be
157      * decided by this policy.
158      *
159      * @return the in band ringtone audio policy value
160      * @hide
161      */
162     @SystemApi
getInBandRingtonePolicy()163     public @AudioPolicyValues int getInBandRingtonePolicy() {
164         return mInBandRingtonePolicy;
165     }
166 
167     @Override
toString()168     public String toString() {
169         StringBuilder builder = new StringBuilder("BluetoothSinkAudioPolicy{");
170         builder.append("mCallEstablishPolicy: ");
171         builder.append(mCallEstablishPolicy);
172         builder.append(", mConnectingTimePolicy: ");
173         builder.append(mConnectingTimePolicy);
174         builder.append(", mInBandRingtonePolicy: ");
175         builder.append(mInBandRingtonePolicy);
176         builder.append("}");
177         return builder.toString();
178     }
179 
180     /** {@link Parcelable.Creator} interface implementation. */
181     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothSinkAudioPolicy>
182             CREATOR =
183                     new Parcelable.Creator<BluetoothSinkAudioPolicy>() {
184                         @Override
185                         public BluetoothSinkAudioPolicy createFromParcel(@NonNull Parcel in) {
186                             return new BluetoothSinkAudioPolicy(
187                                     in.readInt(), in.readInt(), in.readInt());
188                         }
189 
190                         @Override
191                         public BluetoothSinkAudioPolicy[] newArray(int size) {
192                             return new BluetoothSinkAudioPolicy[size];
193                         }
194                     };
195 
196     @Override
writeToParcel(@onNull Parcel out, int flags)197     public void writeToParcel(@NonNull Parcel out, int flags) {
198         out.writeInt(mCallEstablishPolicy);
199         out.writeInt(mConnectingTimePolicy);
200         out.writeInt(mInBandRingtonePolicy);
201     }
202 
203     /** @hide */
204     @Override
describeContents()205     public int describeContents() {
206         return 0;
207     }
208 
209     @Override
equals(@ullable Object o)210     public boolean equals(@Nullable Object o) {
211         if (o instanceof BluetoothSinkAudioPolicy) {
212             BluetoothSinkAudioPolicy other = (BluetoothSinkAudioPolicy) o;
213             return (other.mCallEstablishPolicy == mCallEstablishPolicy
214                     && other.mConnectingTimePolicy == mConnectingTimePolicy
215                     && other.mInBandRingtonePolicy == mInBandRingtonePolicy);
216         }
217         return false;
218     }
219 
220     /**
221      * Returns a hash representation of this BluetoothCodecConfig based on all the config values.
222      *
223      * @hide
224      */
225     @Override
hashCode()226     public int hashCode() {
227         return Objects.hash(mCallEstablishPolicy, mConnectingTimePolicy, mInBandRingtonePolicy);
228     }
229 
230     /**
231      * Builder for {@link BluetoothSinkAudioPolicy}.
232      *
233      * <p>By default, the audio policy values will be set to {@link
234      * BluetoothSinkAudioPolicy#POLICY_UNCONFIGURED}.
235      */
236     public static final class Builder {
237         private int mCallEstablishPolicy = POLICY_UNCONFIGURED;
238         private int mConnectingTimePolicy = POLICY_UNCONFIGURED;
239         private int mInBandRingtonePolicy = POLICY_UNCONFIGURED;
240 
Builder()241         public Builder() {}
242 
Builder(@onNull BluetoothSinkAudioPolicy policies)243         public Builder(@NonNull BluetoothSinkAudioPolicy policies) {
244             mCallEstablishPolicy = policies.mCallEstablishPolicy;
245             mConnectingTimePolicy = policies.mConnectingTimePolicy;
246             mInBandRingtonePolicy = policies.mInBandRingtonePolicy;
247         }
248 
249         /**
250          * Set Call Establish (pick up and answer) policy.
251          *
252          * <p>This policy is used to determine the audio preference when the HF device makes or
253          * answers a call. That is, if this device makes or answers a call, is the audio preferred
254          * by HF.
255          *
256          * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, answering or making a call
257          * from the HF device will route the call audio to it. If set to {@link
258          * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, answering or making a call from the HF
259          * device will NOT route the call audio to it.
260          *
261          * @return reference to the current object
262          * @hide
263          */
264         @SystemApi
setCallEstablishPolicy(@udioPolicyValues int callEstablishPolicy)265         public @NonNull Builder setCallEstablishPolicy(@AudioPolicyValues int callEstablishPolicy) {
266             mCallEstablishPolicy = callEstablishPolicy;
267             return this;
268         }
269 
270         /**
271          * Set during connection audio up policy.
272          *
273          * <p>This policy is used to determine the audio preference when the HF device connects with
274          * the AG device. That is, when the HF device gets connected, should the HF become active
275          * and get audio is decided by this policy. This also covers the case of during a call. If
276          * the HF connects with the AG during an ongoing call, should the call audio be routed to
277          * the HF will be decided by this policy.
278          *
279          * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, connecting HF during a call
280          * will route the call audio to it. If set to {@link
281          * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, connecting HF during a call will NOT route
282          * the call audio to it.
283          *
284          * @return reference to the current object
285          * @hide
286          */
287         @SystemApi
setActiveDevicePolicyAfterConnection( @udioPolicyValues int connectingTimePolicy)288         public @NonNull Builder setActiveDevicePolicyAfterConnection(
289                 @AudioPolicyValues int connectingTimePolicy) {
290             mConnectingTimePolicy = connectingTimePolicy;
291             return this;
292         }
293 
294         /**
295          * Set In band ringtone audio up policy.
296          *
297          * <p>This policy is used to determine the audio preference of the in band ringtone. That
298          * is, if there is an incoming call, should the inband ringtone audio be routed to the HF
299          * will be decided by this policy.
300          *
301          * <p>If set to {@link BluetoothSinkAudioPolicy#POLICY_ALLOWED}, there will be in band
302          * ringtone in the HF device during an incoming call. If set to {@link
303          * BluetoothSinkAudioPolicy#POLICY_NOT_ALLOWED}, there will NOT be in band ringtone in the
304          * HF device during an incoming call.
305          *
306          * @return reference to the current object
307          * @hide
308          */
309         @SystemApi
setInBandRingtonePolicy( @udioPolicyValues int inBandRingtonePolicy)310         public @NonNull Builder setInBandRingtonePolicy(
311                 @AudioPolicyValues int inBandRingtonePolicy) {
312             mInBandRingtonePolicy = inBandRingtonePolicy;
313             return this;
314         }
315 
316         /**
317          * Build {@link BluetoothSinkAudioPolicy}.
318          *
319          * @return new BluetoothSinkAudioPolicy object
320          * @hide
321          */
322         @SystemApi
build()323         public @NonNull BluetoothSinkAudioPolicy build() {
324             return new BluetoothSinkAudioPolicy(
325                     mCallEstablishPolicy, mConnectingTimePolicy, mInBandRingtonePolicy);
326         }
327     }
328 }
329