Make AudioMix, AudioMixMatchCriterion & AudioMixingRule Parcelable
Bug: 293874525
Test: atest AudioMixUnitTests AudioMixingRuleUnitTests
Test: atest AudioHostTest AudioServiceHostTest
Change-Id: Id84c587f1edf5754496ed7f803c217017b43e605
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2137f47..ddf0607 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -7276,8 +7276,11 @@
package android.media.audiopolicy {
- public class AudioMix {
+ public class AudioMix implements android.os.Parcelable {
+ method public int describeContents();
method public int getMixState();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMix> CREATOR;
field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
field public static final int MIX_STATE_IDLE = 0; // 0x0
field public static final int MIX_STATE_MIXING = 1; // 0x1
@@ -7286,15 +7289,18 @@
}
public static class AudioMix.Builder {
- ctor public AudioMix.Builder(android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
+ ctor public AudioMix.Builder(@NonNull android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
- method public android.media.audiopolicy.AudioMix.Builder setFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+ method public android.media.audiopolicy.AudioMix.Builder setFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
}
- public class AudioMixingRule {
+ public class AudioMixingRule implements android.os.Parcelable {
+ method public int describeContents();
method public int getTargetMixRole();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMixingRule> CREATOR;
field public static final int MIX_ROLE_INJECTOR = 1; // 0x1
field public static final int MIX_ROLE_PLAYERS = 0; // 0x0
field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
diff --git a/media/java/android/media/audiopolicy/AudioMix.aidl b/media/java/android/media/audiopolicy/AudioMix.aidl
new file mode 100644
index 0000000..d17a644
--- /dev/null
+++ b/media/java/android/media/audiopolicy/AudioMix.aidl
@@ -0,0 +1,3 @@
+package android.media.audiopolicy;
+
+parcelable AudioMix;
\ No newline at end of file
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index d0270d3..d592cf2 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -21,12 +21,15 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioSystem;
import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,12 +41,12 @@
* @hide
*/
@SystemApi
-public class AudioMix {
+public class AudioMix implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private AudioMixingRule mRule;
+ private @NonNull AudioMixingRule mRule;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private AudioFormat mFormat;
+ private @NonNull AudioFormat mFormat;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private int mRouteFlags;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -54,7 +57,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
int mCallbackFlags;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- String mDeviceAddress;
+ @NonNull String mDeviceAddress;
// initialized in constructor, read by AudioPolicyConfig
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -63,10 +66,11 @@
/**
* All parameters are guaranteed valid through the Builder.
*/
- private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags,
- int deviceType, String deviceAddress) {
- mRule = rule;
- mFormat = format;
+ private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
+ int routeFlags, int callbackFlags,
+ int deviceType, @Nullable String deviceAddress) {
+ mRule = Objects.requireNonNull(rule);
+ mFormat = Objects.requireNonNull(format);
mRouteFlags = routeFlags;
mMixType = rule.getTargetMixType();
mCallbackFlags = callbackFlags;
@@ -269,6 +273,49 @@
return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // write mix route flags
+ dest.writeInt(mRouteFlags);
+ // write callback flags
+ dest.writeInt(mCallbackFlags);
+ // write device information
+ dest.writeInt(mDeviceSystemType);
+ dest.writeString8(mDeviceAddress);
+ mFormat.writeToParcel(dest, flags);
+ mRule.writeToParcel(dest, flags);
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
+ /**
+ * Rebuilds an AudioMix previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the AudioMix from
+ * @return a new AudioMix created from the data in the parcel
+ */
+ public AudioMix createFromParcel(Parcel p) {
+ final AudioMix.Builder mixBuilder = new AudioMix.Builder();
+ // read mix route flags
+ mixBuilder.setRouteFlags(p.readInt());
+ // read callback flags
+ mixBuilder.setCallbackFlags(p.readInt());
+ // read device information
+ mixBuilder.setDevice(p.readInt(), p.readString8());
+ mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p));
+ mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
+ return mixBuilder.build();
+ }
+
+ public AudioMix[] newArray(int size) {
+ return new AudioMix[size];
+ }
+ };
+
/** @hide */
@IntDef(flag = true,
value = { ROUTE_FLAG_RENDER, ROUTE_FLAG_LOOP_BACK } )
@@ -298,7 +345,7 @@
* @param rule a non-null {@link AudioMixingRule} instance.
* @throws IllegalArgumentException
*/
- public Builder(AudioMixingRule rule)
+ public Builder(@NonNull AudioMixingRule rule)
throws IllegalArgumentException {
if (rule == null) {
throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -313,7 +360,7 @@
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
- Builder setMixingRule(AudioMixingRule rule)
+ Builder setMixingRule(@NonNull AudioMixingRule rule)
throws IllegalArgumentException {
if (rule == null) {
throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -358,7 +405,7 @@
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
- public Builder setFormat(AudioFormat format)
+ public Builder setFormat(@NonNull AudioFormat format)
throws IllegalArgumentException {
if (format == null) {
throw new IllegalArgumentException("Illegal null AudioFormat argument");
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.aidl b/media/java/android/media/audiopolicy/AudioMixingRule.aidl
new file mode 100644
index 0000000..5c06538
--- /dev/null
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.aidl
@@ -0,0 +1,3 @@
+package android.media.audiopolicy;
+
+parcelable AudioMixingRule;
\ No newline at end of file
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 9c0b825f..e5debb8 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -26,8 +26,11 @@
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Parcel;
+import android.os.Parcelable;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.Collection;
@@ -50,7 +53,7 @@
* </pre>
*/
@SystemApi
-public class AudioMixingRule {
+public class AudioMixingRule implements Parcelable {
private AudioMixingRule(int mixType, Collection<AudioMixMatchCriterion> criteria,
boolean allowPrivilegedMediaPlaybackCapture,
@@ -130,7 +133,7 @@
RULE_EXCLUSION_MASK | RULE_MATCH_AUDIO_SESSION_ID;
/** @hide */
- public static final class AudioMixMatchCriterion {
+ public static final class AudioMixMatchCriterion implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final AudioAttributes mAttr;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -139,18 +142,44 @@
final int mRule;
/** input parameters must be valid */
- AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
+ @VisibleForTesting
+ public AudioMixMatchCriterion(AudioAttributes attributes, int rule) {
mAttr = attributes;
mIntProp = Integer.MIN_VALUE;
mRule = rule;
}
/** input parameters must be valid */
- AudioMixMatchCriterion(Integer intProp, int rule) {
+ @VisibleForTesting
+ public AudioMixMatchCriterion(Integer intProp, int rule) {
mAttr = null;
mIntProp = intProp.intValue();
mRule = rule;
}
+ private AudioMixMatchCriterion(@NonNull Parcel in) {
+ Objects.requireNonNull(in);
+ mRule = in.readInt();
+ final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
+ switch (match_rule) {
+ case RULE_MATCH_ATTRIBUTE_USAGE:
+ case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
+ mAttr = AudioAttributes.CREATOR.createFromParcel(in);
+ mIntProp = Integer.MIN_VALUE;
+ break;
+ case RULE_MATCH_UID:
+ case RULE_MATCH_USERID:
+ case RULE_MATCH_AUDIO_SESSION_ID:
+ mIntProp = in.readInt();
+ mAttr = null;
+ break;
+ default:
+ // assume there was in int value to read as for now they come in pair
+ in.readInt();
+ throw new IllegalArgumentException(
+ "Illegal rule value " + mRule + " in parcel");
+ }
+ }
+
@Override
public int hashCode() {
return Objects.hash(mAttr, mIntProp, mRule);
@@ -170,7 +199,13 @@
&& Objects.equals(mAttr, other.mAttr);
}
- void writeToParcel(Parcel dest) {
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mRule);
final int match_rule = mRule & ~RULE_EXCLUSION_MASK;
switch (match_rule) {
@@ -190,6 +225,22 @@
}
}
+ public static final @NonNull Parcelable.Creator<AudioMixMatchCriterion> CREATOR =
+ new Parcelable.Creator<>() {
+ /**
+ * Rebuilds an AudioMixMatchCriterion previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the AudioMix from
+ * @return a new AudioMixMatchCriterion created from the data in the parcel
+ */
+ public AudioMixMatchCriterion createFromParcel(Parcel p) {
+ return new AudioMixMatchCriterion(p);
+ }
+ public AudioMixMatchCriterion[] newArray(int size) {
+ return new AudioMixMatchCriterion[size];
+ }
+ };
+
public AudioAttributes getAudioAttributes() { return mAttr; }
public int getIntProp() { return mIntProp; }
public int getRule() { return mRule; }
@@ -605,13 +656,14 @@
if (!(property instanceof AudioAttributes)) {
throw new IllegalArgumentException("Invalid AudioAttributes argument");
}
- return addRuleInternal((AudioAttributes) property, null, rule);
+ return addRuleInternal(
+ new AudioMixMatchCriterion((AudioAttributes) property, rule));
} else {
// implies integer match rule
if (!(property instanceof Integer)) {
throw new IllegalArgumentException("Invalid Integer argument");
}
- return addRuleInternal(null, (Integer) property, rule);
+ return addRuleInternal(new AudioMixMatchCriterion((Integer) property, rule));
}
}
@@ -636,12 +688,13 @@
* @return the same Builder instance.
* @throws IllegalArgumentException
*/
- private Builder addRuleInternal(AudioAttributes attrToMatch, Integer intProp, int rule)
+ private Builder addRuleInternal(AudioMixMatchCriterion criterion)
throws IllegalArgumentException {
// If mix type is invalid and added rule is valid only for the players / recorders,
// adjust the mix type accordingly.
// Otherwise, if the mix type was already deduced or set explicitly, verify the rule
// is valid for the mix type.
+ final int rule = criterion.mRule;
if (mTargetMixType == AudioMix.MIX_TYPE_INVALID) {
if (isPlayerRule(rule)) {
mTargetMixType = AudioMix.MIX_TYPE_PLAYERS;
@@ -655,51 +708,16 @@
}
synchronized (mCriteria) {
int oppositeRule = rule ^ RULE_EXCLUSION_MASK;
- if (mCriteria.stream().anyMatch(criterion -> criterion.mRule == oppositeRule)) {
+ if (mCriteria.stream().anyMatch(
+ otherCriterion -> otherCriterion.mRule == oppositeRule)) {
throw new IllegalArgumentException("AudioMixingRule cannot contain RULE_MATCH_*"
+ " and RULE_EXCLUDE_* for the same dimension.");
}
- int ruleWithoutExclusion = rule & ~RULE_EXCLUSION_MASK;
- switch (ruleWithoutExclusion) {
- case RULE_MATCH_ATTRIBUTE_USAGE:
- case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- mCriteria.add(new AudioMixMatchCriterion(attrToMatch, rule));
- break;
- case RULE_MATCH_UID:
- case RULE_MATCH_USERID:
- case RULE_MATCH_AUDIO_SESSION_ID:
- mCriteria.add(new AudioMixMatchCriterion(intProp, rule));
- break;
- default:
- throw new IllegalStateException("Unreachable code in addRuleInternal()");
- }
+ mCriteria.add(criterion);
}
return this;
}
- Builder addRuleFromParcel(Parcel in) throws IllegalArgumentException {
- final int rule = in.readInt();
- final int match_rule = rule & ~RULE_EXCLUSION_MASK;
- AudioAttributes attr = null;
- Integer intProp = null;
- switch (match_rule) {
- case RULE_MATCH_ATTRIBUTE_USAGE:
- case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
- attr = AudioAttributes.CREATOR.createFromParcel(in);
- break;
- case RULE_MATCH_UID:
- case RULE_MATCH_USERID:
- case RULE_MATCH_AUDIO_SESSION_ID:
- intProp = new Integer(in.readInt());
- break;
- default:
- // assume there was in int value to read as for now they come in pair
- in.readInt();
- throw new IllegalArgumentException("Illegal rule value " + rule + " in parcel");
- }
- return addRuleInternal(attr, intProp, rule);
- }
-
/**
* Combines all of the matching and exclusion rules that have been set and return a new
* {@link AudioMixingRule} object.
@@ -717,4 +735,52 @@
mVoiceCommunicationCaptureAllowed);
}
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // write opt-out respect
+ dest.writeBoolean(mAllowPrivilegedPlaybackCapture);
+ // write voice communication capture allowed flag
+ dest.writeBoolean(mVoiceCommunicationCaptureAllowed);
+ // write specified mix type
+ dest.writeInt(mTargetMixType);
+ // write mix rules
+ dest.writeInt(mCriteria.size());
+ for (AudioMixingRule.AudioMixMatchCriterion criterion : mCriteria) {
+ criterion.writeToParcel(dest, flags);
+ }
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioMixingRule> CREATOR =
+ new Parcelable.Creator<>() {
+
+ @Override
+ public AudioMixingRule createFromParcel(Parcel source) {
+ AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
+ // read opt-out respect
+ ruleBuilder.allowPrivilegedPlaybackCapture(source.readBoolean());
+ // read voice capture allowed flag
+ ruleBuilder.voiceCommunicationCaptureAllowed(source.readBoolean());
+ // read specified mix type
+ ruleBuilder.setTargetMixRole(source.readInt());
+ // read mix rules
+ int nbRules = source.readInt();
+ for (int j = 0; j < nbRules; j++) {
+ // read the matching rules
+ ruleBuilder.addRuleInternal(
+ AudioMixMatchCriterion.CREATOR.createFromParcel(source));
+ }
+ return ruleBuilder.build();
+ }
+
+ @Override
+ public AudioMixingRule[] newArray(int size) {
+ return new AudioMixingRule[size];
+ }
+ };
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 7a85d21..0505b80 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -17,7 +17,6 @@
package android.media.audiopolicy;
import android.annotation.NonNull;
-import android.media.AudioFormat;
import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
import android.os.Parcel;
import android.os.Parcelable;
@@ -85,72 +84,20 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mMixes.size());
for (AudioMix mix : mMixes) {
- // write mix route flags
- dest.writeInt(mix.getRouteFlags());
- // write callback flags
- dest.writeInt(mix.mCallbackFlags);
- // write device information
- dest.writeInt(mix.mDeviceSystemType);
- dest.writeString(mix.mDeviceAddress);
- // write mix format
- dest.writeInt(mix.getFormat().getSampleRate());
- dest.writeInt(mix.getFormat().getEncoding());
- dest.writeInt(mix.getFormat().getChannelMask());
- // write opt-out respect
- dest.writeBoolean(mix.getRule().allowPrivilegedMediaPlaybackCapture());
- // write voice communication capture allowed flag
- dest.writeBoolean(mix.getRule().voiceCommunicationCaptureAllowed());
- // write specified mix type
- dest.writeInt(mix.getRule().getTargetMixRole());
- // write mix rules
- final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
- dest.writeInt(criteria.size());
- for (AudioMixMatchCriterion criterion : criteria) {
- criterion.writeToParcel(dest);
- }
+ mix.writeToParcel(dest, flags);
}
}
private AudioPolicyConfig(Parcel in) {
- mMixes = new ArrayList<AudioMix>();
int nbMixes = in.readInt();
+ mMixes = new ArrayList<>(nbMixes);
for (int i = 0 ; i < nbMixes ; i++) {
- final AudioMix.Builder mixBuilder = new AudioMix.Builder();
- // read mix route flags
- int routeFlags = in.readInt();
- mixBuilder.setRouteFlags(routeFlags);
- // read callback flags
- mixBuilder.setCallbackFlags(in.readInt());
- // read device information
- mixBuilder.setDevice(in.readInt(), in.readString());
- // read mix format
- int sampleRate = in.readInt();
- int encoding = in.readInt();
- int channelMask = in.readInt();
- final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate)
- .setChannelMask(channelMask).setEncoding(encoding).build();
- mixBuilder.setFormat(format);
-
- AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
- // read opt-out respect
- ruleBuilder.allowPrivilegedPlaybackCapture(in.readBoolean());
- // read voice capture allowed flag
- ruleBuilder.voiceCommunicationCaptureAllowed(in.readBoolean());
- // read specified mix type
- ruleBuilder.setTargetMixRole(in.readInt());
- // read mix rules
- int nbRules = in.readInt();
- for (int j = 0 ; j < nbRules ; j++) {
- // read the matching rules
- ruleBuilder.addRuleFromParcel(in);
- }
- mixBuilder.setMixingRule(ruleBuilder.build());
- mMixes.add(mixBuilder.build());
+ mMixes.add(AudioMix.CREATOR.createFromParcel(in));
}
}
- public static final @android.annotation.NonNull Parcelable.Creator<AudioPolicyConfig> CREATOR
- = new Parcelable.Creator<AudioPolicyConfig>() {
+ public static final @android.annotation.NonNull Parcelable.Creator<AudioPolicyConfig> CREATOR =
+ new Parcelable.Creator<>() {
/**
* Rebuilds an AudioPolicyConfig previously stored with writeToParcel().
* @param p Parcel object to read the AudioPolicyConfig from
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
index a26398a..95aa71d 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixUnitTests.java
@@ -31,7 +31,6 @@
import android.media.AudioSystem;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioMixingRule;
-import android.media.audiopolicy.AudioPolicyConfig;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -42,9 +41,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Unit tests for AudioMix.
*
@@ -262,13 +258,13 @@
private static AudioMix writeToAndFromParcel(AudioMix audioMix) {
- AudioPolicyConfig apc = new AudioPolicyConfig(new ArrayList<>(List.of(audioMix)));
Parcel parcel = Parcel.obtain();
- apc.writeToParcel(parcel, /*flags=*/0);
- parcel.setDataPosition(0);
- AudioMix unmarshalledMix =
- AudioPolicyConfig.CREATOR.createFromParcel(parcel).getMixes().get(0);
- parcel.recycle();
- return unmarshalledMix;
+ try {
+ audioMix.writeToParcel(parcel, /*parcelableFlags=*/0);
+ parcel.setDataPosition(0);
+ return AudioMix.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
}
}
diff --git a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java
index 3cbfd50..f04661d 100644
--- a/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java
+++ b/media/tests/AudioPolicyTest/src/com/android/audiopolicytest/AudioMixingRuleUnitTests.java
@@ -39,10 +39,13 @@
import android.media.AudioAttributes;
import android.media.audiopolicy.AudioMixingRule;
import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
+import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.common.testing.EqualsTester;
+
import org.hamcrest.CustomTypeSafeMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
@@ -218,6 +221,94 @@
() -> new AudioMixingRule.Builder().build());
}
+ @Test
+ public void audioMixMatchCriterion_equals_isCorrect() {
+ AudioMixMatchCriterion criterionUsage = new AudioMixMatchCriterion(
+ USAGE_MEDIA_AUDIO_ATTRIBUTES, RULE_MATCH_ATTRIBUTE_USAGE);
+ AudioMixMatchCriterion criterionExcludeUsage = new AudioMixMatchCriterion(
+ USAGE_MEDIA_AUDIO_ATTRIBUTES, RULE_EXCLUDE_ATTRIBUTE_USAGE);
+ AudioMixMatchCriterion criterionCapturePreset = new AudioMixMatchCriterion(
+ CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES,
+ RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET);
+ AudioMixMatchCriterion criterionExcludeCapturePreset = new AudioMixMatchCriterion(
+ CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES,
+ RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET);
+ AudioMixMatchCriterion criterionUid = new AudioMixMatchCriterion(TEST_UID, RULE_MATCH_UID);
+ AudioMixMatchCriterion criterionExcludeUid = new AudioMixMatchCriterion(TEST_UID,
+ RULE_EXCLUDE_UID);
+ AudioMixMatchCriterion criterionSessionId = new AudioMixMatchCriterion(TEST_SESSION_ID,
+ RULE_MATCH_UID);
+ AudioMixMatchCriterion criterionExcludeSessionId = new AudioMixMatchCriterion(
+ TEST_SESSION_ID, RULE_EXCLUDE_UID);
+
+ final EqualsTester equalsTester = new EqualsTester();
+ equalsTester.addEqualityGroup(criterionUsage, writeToAndFromParcel(criterionUsage));
+ equalsTester.addEqualityGroup(criterionExcludeUsage,
+ writeToAndFromParcel(criterionExcludeUsage));
+ equalsTester.addEqualityGroup(criterionCapturePreset,
+ writeToAndFromParcel(criterionCapturePreset));
+ equalsTester.addEqualityGroup(criterionExcludeCapturePreset,
+ writeToAndFromParcel(criterionExcludeCapturePreset));
+ equalsTester.addEqualityGroup(criterionUid, writeToAndFromParcel(criterionUid));
+ equalsTester.addEqualityGroup(criterionExcludeUid,
+ writeToAndFromParcel(criterionExcludeUid));
+ equalsTester.addEqualityGroup(criterionSessionId, writeToAndFromParcel(criterionSessionId));
+ equalsTester.addEqualityGroup(criterionExcludeSessionId,
+ writeToAndFromParcel(criterionExcludeSessionId));
+
+ equalsTester.testEquals();
+ }
+
+ @Test
+ public void audioMixingRule_equals_isCorrect() {
+ final EqualsTester equalsTester = new EqualsTester();
+
+ AudioMixingRule mixRule1 = new AudioMixingRule.Builder().addMixRule(
+ RULE_MATCH_AUDIO_SESSION_ID, TEST_SESSION_ID).excludeMixRule(RULE_MATCH_UID,
+ TEST_UID).build();
+ AudioMixingRule mixRule2 = new AudioMixingRule.Builder().addMixRule(
+ RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
+ CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES).setTargetMixRole(
+ MIX_ROLE_INJECTOR).allowPrivilegedPlaybackCapture(true).build();
+ AudioMixingRule mixRule3 = new AudioMixingRule.Builder().addMixRule(
+ RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
+ CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES).setTargetMixRole(
+ MIX_ROLE_INJECTOR).allowPrivilegedPlaybackCapture(false).build();
+ AudioMixingRule mixRule4 = new AudioMixingRule.Builder().addMixRule(
+ RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET,
+ CAPTURE_PRESET_VOICE_RECOGNITION_AUDIO_ATTRIBUTES).setTargetMixRole(
+ MIX_ROLE_INJECTOR).voiceCommunicationCaptureAllowed(true).build();
+
+ equalsTester.addEqualityGroup(mixRule1, writeToAndFromParcel(mixRule1));
+ equalsTester.addEqualityGroup(mixRule2, writeToAndFromParcel(mixRule2));
+ equalsTester.addEqualityGroup(mixRule3, writeToAndFromParcel(mixRule3));
+ equalsTester.addEqualityGroup(mixRule4, writeToAndFromParcel(mixRule4));
+
+ equalsTester.testEquals();
+ }
+
+ private static AudioMixMatchCriterion writeToAndFromParcel(AudioMixMatchCriterion criterion) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ criterion.writeToParcel(parcel, /*parcelableFlags=*/0);
+ parcel.setDataPosition(0);
+ return AudioMixMatchCriterion.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static AudioMixingRule writeToAndFromParcel(AudioMixingRule audioMixingRule) {
+ Parcel parcel = Parcel.obtain();
+ try {
+ audioMixingRule.writeToParcel(parcel, /*parcelableFlags=*/0);
+ parcel.setDataPosition(0);
+ return AudioMixingRule.CREATOR.createFromParcel(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
private static Matcher isAudioMixUidCriterion(int uid, boolean exclude) {
return new CustomTypeSafeMatcher<AudioMixMatchCriterion>("uid mix criterion") {