• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.car.oem;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.car.annotation.ApiRequirements;
25 import android.car.media.CarVolumeGroupInfo;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 
29 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.internal.util.Preconditions;
32 
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.Objects;
36 
37 /**
38  * Class to encapsulate the audio focus evaluation to the OEM audio service
39  *
40  * @hide
41  */
42 @SystemApi
43 @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
44         minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
45 public final class OemCarAudioFocusEvaluationRequest implements Parcelable {
46 
47     private @Nullable final AudioFocusEntry mAudioFocusRequest;
48     private @NonNull final List<CarVolumeGroupInfo>  mMutedVolumeGroups;
49     private @NonNull final List<AudioFocusEntry> mFocusHolders;
50     private @NonNull final List<AudioFocusEntry> mFocusLosers;
51     private final int mAudioZoneId;
52 
53     /**
54      * @hide
55      */
56     @VisibleForTesting
OemCarAudioFocusEvaluationRequest(Parcel in)57     public OemCarAudioFocusEvaluationRequest(Parcel in) {
58         byte flg = in.readByte();
59         mAudioFocusRequest = (flg & Builder.FOCUS_REQUEST_FIELDS_SET) == 0
60                 ? null : AudioFocusEntry.CREATOR.createFromParcel(in);
61         mMutedVolumeGroups = new ArrayList<>();
62         in.readParcelableList(mMutedVolumeGroups, CarVolumeGroupInfo.class.getClassLoader());
63         mFocusHolders = new ArrayList<>();
64         in.readParcelableList(mFocusHolders, AudioFocusEntry.class.getClassLoader());
65         mFocusLosers = new ArrayList<>();
66         in.readParcelableList(mFocusLosers, AudioFocusEntry.class.getClassLoader());
67         mAudioZoneId = in.readInt();
68     }
69 
70     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
71             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
72     @NonNull
73     public static final Creator<OemCarAudioFocusEvaluationRequest> CREATOR =
74             new Creator<>() {
75                 @Override
76                 public OemCarAudioFocusEvaluationRequest createFromParcel(Parcel in) {
77                     return new OemCarAudioFocusEvaluationRequest(in);
78                 }
79 
80                 @Override
81                 public OemCarAudioFocusEvaluationRequest[] newArray(int size) {
82                     return new OemCarAudioFocusEvaluationRequest[size];
83                 }
84             };
85 
86 
87     @Override
88     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
89     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
90             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
describeContents()91     public int describeContents() {
92         return 0;
93     }
94 
95     @Override
96     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
97     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
98             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
writeToParcel(@onNull Parcel dest, int flags)99     public void writeToParcel(@NonNull Parcel dest, int flags) {
100         byte flg = 0;
101         if (mAudioFocusRequest != null) {
102             flg = (byte) (flg | Builder.FOCUS_REQUEST_FIELDS_SET);
103         }
104         dest.writeByte(flg);
105         if (mAudioFocusRequest != null) {
106             mAudioFocusRequest.writeToParcel(dest, flags);
107         }
108         dest.writeParcelableList(mMutedVolumeGroups, flags);
109         dest.writeParcelableList(mFocusHolders, flags);
110         dest.writeParcelableList(mFocusLosers, flags);
111         dest.writeInt(mAudioZoneId);
112     }
113 
114     /**
115      * Returns the audio zone id for the request
116      */
117     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
118             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
getAudioZoneId()119     public int getAudioZoneId() {
120         return mAudioZoneId;
121     }
122 
123     /**
124      * Returns the current audio focus info to evaluate,
125      * in cases where the audio focus info is null
126      * the request is to re-evaluate current focus holder and losers.
127      */
128     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
129             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
getAudioFocusRequest()130     public @Nullable AudioFocusEntry getAudioFocusRequest() {
131         return mAudioFocusRequest;
132     }
133 
134     /**
135      * Returns the currently muted volume groups
136      */
137     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
138             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
getMutedVolumeGroups()139     public @NonNull List<CarVolumeGroupInfo> getMutedVolumeGroups() {
140         return mMutedVolumeGroups;
141     }
142 
143     /**
144      * Returns the current focus holder
145      */
146     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
147             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
getFocusHolders()148     public @NonNull List<AudioFocusEntry> getFocusHolders() {
149         return mFocusHolders;
150     }
151 
152     /**
153      * Returns the current focus losers (.i.e focus request that have transiently lost focus)
154      */
155     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
156             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
getFocusLosers()157     public @NonNull List<AudioFocusEntry> getFocusLosers() {
158         return mFocusLosers;
159     }
160 
161     @Override
equals(Object o)162     public boolean equals(Object o) {
163         if (this == o) {
164             return true;
165         }
166 
167         if (!(o instanceof OemCarAudioFocusEvaluationRequest)) {
168             return false;
169         }
170 
171         OemCarAudioFocusEvaluationRequest that = (OemCarAudioFocusEvaluationRequest) o;
172 
173         return safeEquals(mAudioFocusRequest, that.mAudioFocusRequest)
174                 && mFocusHolders.equals(that.mFocusHolders)
175                 && mFocusLosers.equals(that.mFocusLosers)
176                 && mMutedVolumeGroups.equals(that.mMutedVolumeGroups)
177                 && mAudioZoneId == that.mAudioZoneId;
178     }
179 
180     @Override
hashCode()181     public int hashCode() {
182         return Objects.hash(mAudioFocusRequest, mFocusHolders, mFocusLosers, mMutedVolumeGroups,
183                 mAudioZoneId);
184     }
185 
186     /**
187      * @hide
188      */
189     @VisibleForTesting
OemCarAudioFocusEvaluationRequest( @ullable AudioFocusEntry audioFocusEntry, @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups, @NonNull List<AudioFocusEntry> focusHolders, @NonNull List<AudioFocusEntry> focusLosers, int audioZoneId)190     public OemCarAudioFocusEvaluationRequest(
191             @Nullable AudioFocusEntry audioFocusEntry,
192             @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
193             @NonNull List<AudioFocusEntry> focusHolders,
194             @NonNull List<AudioFocusEntry> focusLosers,
195             int audioZoneId) {
196         this.mAudioFocusRequest = audioFocusEntry;
197         Preconditions.checkArgument(mutedVolumeGroups != null,
198                 "Muted volume groups can not be null");
199         Preconditions.checkArgument(focusHolders != null,
200                 "Focus holders can not be null");
201         Preconditions.checkArgument(focusLosers != null,
202                 "Focus losers can not be null");
203         this.mMutedVolumeGroups = mutedVolumeGroups;
204         this.mFocusHolders = focusHolders;
205         this.mFocusLosers = focusLosers;
206         this.mAudioZoneId = audioZoneId;
207     }
208 
209     @Override
toString()210     public String toString() {
211         return new StringBuilder().append("OemCarAudioFocusEvaluationRequest {audioZoneId = ")
212                 .append(mAudioZoneId).append(", audioFocusInfo = ").append(mAudioFocusRequest)
213                 .append(", mutedVolumeGroups = ").append(mMutedVolumeGroups)
214                 .append(", focusHolders = ").append(mFocusHolders)
215                 .append(", focusLosers = ").append(mFocusLosers)
216                 .append(" }").toString();
217     }
218 
219     /**
220      * A builder for {@link OemCarAudioFocusEvaluationRequest}
221      */
222     @SuppressWarnings("WeakerAccess")
223     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
224             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
225     public static final class Builder {
226 
227         private static final int FOCUS_REQUEST_FIELDS_SET = 0x1;
228         private static final int MUTED_VOLUME_GROUPS_FIELDS_SET = 0x2;
229         private static final int FOCUS_HOLDERS_FIELDS_SET = 0x4;
230         private static final int FOCUS_LOSERS_FIELDS_SET = 0x8;
231         private static final int ZONE_ID_FIELDS_SET = 0x10;
232         private static final int BUILDER_USED_FIELDS_SET = 0x20;
233 
234         private int mAudioZoneId;
235         private @Nullable AudioFocusEntry mAudioFocusRequest;
236         private @NonNull List<CarVolumeGroupInfo> mMutedVolumeGroups;
237         private @NonNull List<AudioFocusEntry> mFocusHolders;
238         private @NonNull List<AudioFocusEntry> mFocusLosers;
239 
240         private long mBuilderFieldsSet = 0L;
241 
Builder( @onNull List<CarVolumeGroupInfo> mutedVolumeGroups, @NonNull List<AudioFocusEntry> focusHolders, @NonNull List<AudioFocusEntry> focusLosers, int audioZoneId)242         public Builder(
243                 @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
244                 @NonNull List<AudioFocusEntry> focusHolders,
245                 @NonNull List<AudioFocusEntry> focusLosers,
246                 int audioZoneId) {
247             Preconditions.checkArgument(mutedVolumeGroups != null,
248                     "Muted volume groups can not be null");
249             Preconditions.checkArgument(focusHolders != null,
250                     " Focus holders can not be null");
251             Preconditions.checkArgument(focusLosers != null,
252                     "Focus losers can not be null");
253             mMutedVolumeGroups = mutedVolumeGroups;
254             mFocusHolders = focusHolders;
255             mFocusLosers = focusLosers;
256             mAudioZoneId = audioZoneId;
257         }
258 
259         /**
260          * set the audio zone id
261          */
262         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
263                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setAudioZoneId(int value)264         public @NonNull Builder setAudioZoneId(int value) {
265             checkNotUsed();
266             mBuilderFieldsSet |= ZONE_ID_FIELDS_SET;
267             mAudioZoneId = value;
268             return this;
269         }
270 
271         /**
272          * Sets the current focus info to evaluate
273          */
274         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
275                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
276         @NonNull
setAudioFocusRequest(@onNull AudioFocusEntry audioFocusRequest)277         public Builder setAudioFocusRequest(@NonNull AudioFocusEntry audioFocusRequest) {
278             Preconditions.checkArgument(audioFocusRequest != null,
279                     "Audio focus request can not be null");
280             checkNotUsed();
281             mBuilderFieldsSet |= FOCUS_REQUEST_FIELDS_SET;
282             mAudioFocusRequest = audioFocusRequest;
283             return this;
284         }
285 
286         /**
287          * Sets the currently muted group volumes
288          */
289         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
290                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
291         @NonNull
setMutedVolumeGroups( @onNull List<CarVolumeGroupInfo> mutedVolumeGroups)292         public Builder setMutedVolumeGroups(
293                 @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups) {
294             Preconditions.checkArgument(mutedVolumeGroups != null,
295                     "Muted volume groups can not be null");
296             checkNotUsed();
297             mBuilderFieldsSet |= MUTED_VOLUME_GROUPS_FIELDS_SET;
298             mMutedVolumeGroups = mutedVolumeGroups;
299             return this;
300         }
301 
302         /** @see #setMutedVolumeGroups */
303         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
304                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addMutedVolumeGroups(@onNull CarVolumeGroupInfo mutedVolumeGroup)305         public @NonNull Builder addMutedVolumeGroups(@NonNull CarVolumeGroupInfo mutedVolumeGroup) {
306             Preconditions.checkArgument(mutedVolumeGroup != null,
307                     "Muted volume group can not be null");
308             if (mMutedVolumeGroups == null) setMutedVolumeGroups(new ArrayList<>());
309             mMutedVolumeGroups.add(mutedVolumeGroup);
310             return this;
311         }
312 
313         /**
314          * Sets the focus holders
315          */
316         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
317                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setFocusHolders(@onNull List<AudioFocusEntry> focusHolders)318         public @NonNull Builder setFocusHolders(@NonNull List<AudioFocusEntry> focusHolders) {
319             Preconditions.checkArgument(focusHolders != null,
320                     "Focus holders can not be null");
321             checkNotUsed();
322             mBuilderFieldsSet |= FOCUS_HOLDERS_FIELDS_SET;
323             mFocusHolders = focusHolders;
324             return this;
325         }
326 
327         /** @see #setFocusHolders */
328         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
329                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addFocusHolders(@onNull AudioFocusEntry focusHolder)330         public @NonNull Builder addFocusHolders(@NonNull AudioFocusEntry focusHolder) {
331             Preconditions.checkArgument(focusHolder != null,
332                     "Focus holder can not be null");
333             if (mFocusHolders == null) setFocusHolders(new ArrayList<>());
334             mFocusHolders.add(focusHolder);
335             return this;
336         }
337 
338         /**
339          * Sets the focus losers
340          */
341         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
342                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setFocusLosers(@onNull List<AudioFocusEntry> focusLosers)343         public @NonNull Builder setFocusLosers(@NonNull List<AudioFocusEntry> focusLosers) {
344             Preconditions.checkArgument(focusLosers != null,
345                     "Focus losers can not be null");
346             checkNotUsed();
347             mBuilderFieldsSet |= FOCUS_LOSERS_FIELDS_SET;
348             mFocusLosers = focusLosers;
349             return this;
350         }
351 
352         /** @see #setFocusLosers */
353         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
354                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addFocusLosers(@onNull AudioFocusEntry focusLoser)355         public @NonNull Builder addFocusLosers(@NonNull AudioFocusEntry focusLoser) {
356             Preconditions.checkArgument(focusLoser != null,
357                     "Focus loser can not be null");
358             if (mFocusLosers == null) setFocusLosers(new ArrayList<>());
359             mFocusLosers.add(focusLoser);
360             return this;
361         }
362 
363         /** Builds the instance. This builder should not be touched after calling this! */
364         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
365                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
366         @NonNull
build()367         public OemCarAudioFocusEvaluationRequest build() {
368             checkNotUsed();
369             mBuilderFieldsSet |= BUILDER_USED_FIELDS_SET; // Mark builder used
370 
371             OemCarAudioFocusEvaluationRequest o = new OemCarAudioFocusEvaluationRequest(
372                     mAudioFocusRequest,
373                     mMutedVolumeGroups,
374                     mFocusHolders,
375                     mFocusLosers,
376                     mAudioZoneId);
377             return o;
378         }
379 
checkNotUsed()380         private void checkNotUsed() {
381             if ((mBuilderFieldsSet & BUILDER_USED_FIELDS_SET) != 0) {
382                 throw new IllegalStateException(
383                         "This Builder should not be reused. Use a new Builder instance instead");
384             }
385         }
386     }
387 
safeEquals(Object a, Object b)388     private static boolean safeEquals(Object a, Object b) {
389         return a == b || (a != null && a.equals(b));
390     }
391 }
392