• 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
162     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
163             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
equals(Object o)164     public boolean equals(Object o) {
165         if (this == o) {
166             return true;
167         }
168 
169         if (!(o instanceof OemCarAudioFocusEvaluationRequest)) {
170             return false;
171         }
172 
173         OemCarAudioFocusEvaluationRequest that = (OemCarAudioFocusEvaluationRequest) o;
174 
175         return safeEquals(mAudioFocusRequest, that.mAudioFocusRequest)
176                 && mFocusHolders.equals(that.mFocusHolders)
177                 && mFocusLosers.equals(that.mFocusLosers)
178                 && mMutedVolumeGroups.equals(that.mMutedVolumeGroups)
179                 && mAudioZoneId == that.mAudioZoneId;
180     }
181 
182     @Override
183     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
184             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
hashCode()185     public int hashCode() {
186         return Objects.hash(mAudioFocusRequest, mFocusHolders, mFocusLosers, mMutedVolumeGroups,
187                 mAudioZoneId);
188     }
189 
190     /**
191      * @hide
192      */
193     @VisibleForTesting
OemCarAudioFocusEvaluationRequest( @ullable AudioFocusEntry audioFocusEntry, @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups, @NonNull List<AudioFocusEntry> focusHolders, @NonNull List<AudioFocusEntry> focusLosers, int audioZoneId)194     public OemCarAudioFocusEvaluationRequest(
195             @Nullable AudioFocusEntry audioFocusEntry,
196             @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
197             @NonNull List<AudioFocusEntry> focusHolders,
198             @NonNull List<AudioFocusEntry> focusLosers,
199             int audioZoneId) {
200         this.mAudioFocusRequest = audioFocusEntry;
201         Preconditions.checkArgument(mutedVolumeGroups != null,
202                 "Muted volume groups can not be null");
203         Preconditions.checkArgument(focusHolders != null,
204                 "Focus holders can not be null");
205         Preconditions.checkArgument(focusLosers != null,
206                 "Focus losers can not be null");
207         this.mMutedVolumeGroups = mutedVolumeGroups;
208         this.mFocusHolders = focusHolders;
209         this.mFocusLosers = focusLosers;
210         this.mAudioZoneId = audioZoneId;
211     }
212 
213     @Override
214     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
215             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
toString()216     public String toString() {
217         return new StringBuilder().append("OemCarAudioFocusEvaluationRequest {audioZoneId = ")
218                 .append(mAudioZoneId).append(", audioFocusInfo = ").append(mAudioFocusRequest)
219                 .append(", mutedVolumeGroups = ").append(mMutedVolumeGroups)
220                 .append(", focusHolders = ").append(mFocusHolders)
221                 .append(", focusLosers = ").append(mFocusLosers)
222                 .append(" }").toString();
223     }
224 
225     /**
226      * A builder for {@link OemCarAudioFocusEvaluationRequest}
227      */
228     @SuppressWarnings("WeakerAccess")
229     @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
230             minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
231     public static final class Builder {
232 
233         private static final int FOCUS_REQUEST_FIELDS_SET = 0x1;
234         private static final int MUTED_VOLUME_GROUPS_FIELDS_SET = 0x2;
235         private static final int FOCUS_HOLDERS_FIELDS_SET = 0x4;
236         private static final int FOCUS_LOSERS_FIELDS_SET = 0x8;
237         private static final int ZONE_ID_FIELDS_SET = 0x10;
238         private static final int BUILDER_USED_FIELDS_SET = 0x20;
239 
240         private int mAudioZoneId;
241         private @Nullable AudioFocusEntry mAudioFocusRequest;
242         private @NonNull List<CarVolumeGroupInfo> mMutedVolumeGroups;
243         private @NonNull List<AudioFocusEntry> mFocusHolders;
244         private @NonNull List<AudioFocusEntry> mFocusLosers;
245 
246         private long mBuilderFieldsSet = 0L;
247 
Builder( @onNull List<CarVolumeGroupInfo> mutedVolumeGroups, @NonNull List<AudioFocusEntry> focusHolders, @NonNull List<AudioFocusEntry> focusLosers, int audioZoneId)248         public Builder(
249                 @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups,
250                 @NonNull List<AudioFocusEntry> focusHolders,
251                 @NonNull List<AudioFocusEntry> focusLosers,
252                 int audioZoneId) {
253             Preconditions.checkArgument(mutedVolumeGroups != null,
254                     "Muted volume groups can not be null");
255             Preconditions.checkArgument(focusHolders != null,
256                     " Focus holders can not be null");
257             Preconditions.checkArgument(focusLosers != null,
258                     "Focus losers can not be null");
259             mMutedVolumeGroups = mutedVolumeGroups;
260             mFocusHolders = focusHolders;
261             mFocusLosers = focusLosers;
262             mAudioZoneId = audioZoneId;
263         }
264 
265         /**
266          * set the audio zone id
267          */
268         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
269                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setAudioZoneId(int value)270         public @NonNull Builder setAudioZoneId(int value) {
271             checkNotUsed();
272             mBuilderFieldsSet |= ZONE_ID_FIELDS_SET;
273             mAudioZoneId = value;
274             return this;
275         }
276 
277         /**
278          * Sets the current focus info to evaluate
279          */
280         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
281                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
282         @NonNull
setAudioFocusRequest(@onNull AudioFocusEntry audioFocusRequest)283         public Builder setAudioFocusRequest(@NonNull AudioFocusEntry audioFocusRequest) {
284             Preconditions.checkArgument(audioFocusRequest != null,
285                     "Audio focus request can not be null");
286             checkNotUsed();
287             mBuilderFieldsSet |= FOCUS_REQUEST_FIELDS_SET;
288             mAudioFocusRequest = audioFocusRequest;
289             return this;
290         }
291 
292         /**
293          * Sets the currently muted group volumes
294          */
295         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
296                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
297         @NonNull
setMutedVolumeGroups( @onNull List<CarVolumeGroupInfo> mutedVolumeGroups)298         public Builder setMutedVolumeGroups(
299                 @NonNull List<CarVolumeGroupInfo> mutedVolumeGroups) {
300             Preconditions.checkArgument(mutedVolumeGroups != null,
301                     "Muted volume groups can not be null");
302             checkNotUsed();
303             mBuilderFieldsSet |= MUTED_VOLUME_GROUPS_FIELDS_SET;
304             mMutedVolumeGroups = mutedVolumeGroups;
305             return this;
306         }
307 
308         /** @see #setMutedVolumeGroups */
309         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
310                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addMutedVolumeGroups(@onNull CarVolumeGroupInfo mutedVolumeGroup)311         public @NonNull Builder addMutedVolumeGroups(@NonNull CarVolumeGroupInfo mutedVolumeGroup) {
312             Preconditions.checkArgument(mutedVolumeGroup != null,
313                     "Muted volume group can not be null");
314             if (mMutedVolumeGroups == null) setMutedVolumeGroups(new ArrayList<>());
315             mMutedVolumeGroups.add(mutedVolumeGroup);
316             return this;
317         }
318 
319         /**
320          * Sets the focus holders
321          */
322         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
323                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setFocusHolders(@onNull List<AudioFocusEntry> focusHolders)324         public @NonNull Builder setFocusHolders(@NonNull List<AudioFocusEntry> focusHolders) {
325             Preconditions.checkArgument(focusHolders != null,
326                     "Focus holders can not be null");
327             checkNotUsed();
328             mBuilderFieldsSet |= FOCUS_HOLDERS_FIELDS_SET;
329             mFocusHolders = focusHolders;
330             return this;
331         }
332 
333         /** @see #setFocusHolders */
334         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
335                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addFocusHolders(@onNull AudioFocusEntry focusHolder)336         public @NonNull Builder addFocusHolders(@NonNull AudioFocusEntry focusHolder) {
337             Preconditions.checkArgument(focusHolder != null,
338                     "Focus holder can not be null");
339             if (mFocusHolders == null) setFocusHolders(new ArrayList<>());
340             mFocusHolders.add(focusHolder);
341             return this;
342         }
343 
344         /**
345          * Sets the focus losers
346          */
347         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
348                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
setFocusLosers(@onNull List<AudioFocusEntry> focusLosers)349         public @NonNull Builder setFocusLosers(@NonNull List<AudioFocusEntry> focusLosers) {
350             Preconditions.checkArgument(focusLosers != null,
351                     "Focus losers can not be null");
352             checkNotUsed();
353             mBuilderFieldsSet |= FOCUS_LOSERS_FIELDS_SET;
354             mFocusLosers = focusLosers;
355             return this;
356         }
357 
358         /** @see #setFocusLosers */
359         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
360                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
addFocusLosers(@onNull AudioFocusEntry focusLoser)361         public @NonNull Builder addFocusLosers(@NonNull AudioFocusEntry focusLoser) {
362             Preconditions.checkArgument(focusLoser != null,
363                     "Focus loser can not be null");
364             if (mFocusLosers == null) setFocusLosers(new ArrayList<>());
365             mFocusLosers.add(focusLoser);
366             return this;
367         }
368 
369         /** Builds the instance. This builder should not be touched after calling this! */
370         @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_3,
371                 minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
372         @NonNull
build()373         public OemCarAudioFocusEvaluationRequest build() {
374             checkNotUsed();
375             mBuilderFieldsSet |= BUILDER_USED_FIELDS_SET; // Mark builder used
376 
377             OemCarAudioFocusEvaluationRequest o = new OemCarAudioFocusEvaluationRequest(
378                     mAudioFocusRequest,
379                     mMutedVolumeGroups,
380                     mFocusHolders,
381                     mFocusLosers,
382                     mAudioZoneId);
383             return o;
384         }
385 
checkNotUsed()386         private void checkNotUsed() {
387             if ((mBuilderFieldsSet & BUILDER_USED_FIELDS_SET) != 0) {
388                 throw new IllegalStateException(
389                         "This Builder should not be reused. Use a new Builder instance instead");
390             }
391         }
392     }
393 
safeEquals(Object a, Object b)394     private static boolean safeEquals(Object a, Object b) {
395         return a == b || (a != null && a.equals(b));
396     }
397 }
398