Added audio focus entry unit test
Also added an audio focus entry copy builder.
Test: atest AudioFocusEntryUnitTest
Bug: 240615622
CTS-Coverage-Bug: 260005572
Change-Id: I021a6e70de1447fb6dc4d96683f35a0d80c7b194
Merged-In: I021a6e70de1447fb6dc4d96683f35a0d80c7b194
(cherry picked from commit 93441f82311af44362d79d35e04eafa7fd8f8d6b)
diff --git a/car-lib-module/api/system-current.txt b/car-lib-module/api/system-current.txt
index 7752531..7f13564 100644
--- a/car-lib-module/api/system-current.txt
+++ b/car-lib-module/api/system-current.txt
@@ -1176,6 +1176,7 @@
}
public static final class AudioFocusEntry.Builder {
+ ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
method @NonNull public android.car.oem.AudioFocusEntry build();
method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 7752531..7f13564 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -1176,6 +1176,7 @@
}
public static final class AudioFocusEntry.Builder {
+ ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
method @NonNull public android.car.oem.AudioFocusEntry build();
method @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
diff --git a/car-lib/api/test-current.txt b/car-lib/api/test-current.txt
index 988cc50..d8a6034 100644
--- a/car-lib/api/test-current.txt
+++ b/car-lib/api/test-current.txt
@@ -1244,6 +1244,7 @@
}
@android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) public static final class AudioFocusEntry.Builder {
+ ctor public AudioFocusEntry.Builder(@NonNull android.car.oem.AudioFocusEntry);
ctor public AudioFocusEntry.Builder(@NonNull android.media.AudioFocusInfo, int, int, int);
method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry build();
method @android.car.annotation.ApiRequirements(minCarVersion=android.car.annotation.ApiRequirements.CarVersion.TIRAMISU_1, minPlatformVersion=android.car.annotation.ApiRequirements.PlatformVersion.TIRAMISU_0) @NonNull public android.car.oem.AudioFocusEntry.Builder setAudioContextId(int);
diff --git a/car-lib/src/android/car/oem/AudioFocusEntry.java b/car-lib/src/android/car/oem/AudioFocusEntry.java
index d61edd1..183a983 100644
--- a/car-lib/src/android/car/oem/AudioFocusEntry.java
+++ b/car-lib/src/android/car/oem/AudioFocusEntry.java
@@ -22,6 +22,10 @@
import android.media.AudioFocusInfo;
import android.os.Parcelable;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
/**
* Class to encapsulate the focus information of evaluation from a car oem audio focus service
*
@@ -43,7 +47,8 @@
int audioContextId,
int audioVolumeGroupId,
int focusResult) {
- mAudioFocusInfo = audioFocusInfo;
+ mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+ "Audio focus info can not be null");
mAudioContextId = audioContextId;
mAudioVolumeGroupId = audioVolumeGroupId;
mAudioFocusResult = focusResult;
@@ -113,7 +118,7 @@
@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- dest.writeTypedObject(mAudioFocusInfo, flags);
+ mAudioFocusInfo.writeToParcel(dest, flags);
dest.writeInt(mAudioContextId);
dest.writeInt(mAudioVolumeGroupId);
dest.writeInt(mAudioFocusResult);
@@ -128,8 +133,9 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
- private AudioFocusEntry(@NonNull android.os.Parcel in) {
- AudioFocusInfo audioFocusInfo = in.readTypedObject(AudioFocusInfo.CREATOR);
+ @VisibleForTesting
+ public AudioFocusEntry(@NonNull android.os.Parcel in) {
+ AudioFocusInfo audioFocusInfo = AudioFocusInfo.CREATOR.createFromParcel(in);
int audioContextId = in.readInt();
int audioVolumeGroupId = in.readInt();
int focusResult = in.readInt();
@@ -156,6 +162,34 @@
}
};
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof AudioFocusEntry)) {
+ return false;
+ }
+
+ AudioFocusEntry that = (AudioFocusEntry) o;
+
+ return mAudioContextId == that.mAudioContextId
+ && mAudioFocusResult == that.mAudioFocusResult
+ && mAudioVolumeGroupId == that.mAudioVolumeGroupId
+ && mAudioFocusInfo.equals(that.mAudioFocusInfo);
+ }
+
+ @Override
+ @ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_2,
+ minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
+ public int hashCode() {
+ return Objects.hash(mAudioFocusInfo.hashCode(), mAudioContextId, mAudioFocusResult,
+ mAudioVolumeGroupId);
+ }
+
/**
* A builder for {@link AudioFocusEntry}
*/
@@ -171,13 +205,19 @@
private long mBuilderFieldsSet = 0L;
+ public Builder(@NonNull AudioFocusEntry entry) {
+ this(Objects.requireNonNull(entry, "Audio focus entry can not be null")
+ .mAudioFocusInfo, entry.mAudioContextId, entry.mAudioVolumeGroupId,
+ entry.mAudioFocusResult);
+ }
public Builder(
@NonNull AudioFocusInfo audioFocusInfo,
int audioContextId,
int audioVolumeGroupId,
int focusResult) {
- mAudioFocusInfo = audioFocusInfo;
+ mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+ "Audio focus info can not be null");
mAudioContextId = audioContextId;
mAudioVolumeGroupId = audioVolumeGroupId;
mAudioFocusResult = focusResult;
@@ -186,10 +226,11 @@
/** see {@link AudioFocusEntry#getAudioFocusInfo()} */
@ApiRequirements(minCarVersion = ApiRequirements.CarVersion.TIRAMISU_1,
minPlatformVersion = ApiRequirements.PlatformVersion.TIRAMISU_0)
- public @NonNull Builder setAudioFocusInfo(@NonNull AudioFocusInfo value) {
+ public @NonNull Builder setAudioFocusInfo(@NonNull AudioFocusInfo audioFocusInfo) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
- mAudioFocusInfo = value;
+ mAudioFocusInfo = Objects.requireNonNull(audioFocusInfo,
+ "Audio focus info can not be null");
return this;
}
diff --git a/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java b/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java
new file mode 100644
index 0000000..ef86bf0
--- /dev/null
+++ b/tests/carservice_unit_test/src/android/car/oem/AudioFocusEntryUnitTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.oem;
+
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+import static android.media.AudioAttributes.USAGE_MEDIA;
+import static android.os.Build.VERSION.SDK_INT;
+
+import static org.junit.Assert.assertThrows;
+
+import android.car.test.AbstractExpectableTestCase;
+import android.media.AudioAttributes;
+import android.media.AudioFocusInfo;
+import android.media.AudioManager;
+import android.os.Parcel;
+
+import org.junit.Test;
+
+public final class AudioFocusEntryUnitTest extends AbstractExpectableTestCase {
+
+ private static final AudioFocusInfo TEST_AUDIO_FOCUS_INFO = createAudioFocusInfoForMedia();
+ private static final int TEST_PARCEL_FLAGS = 0;
+ private static final int MEDIA_EMPTY_FLAG = 0;
+ private static final int TEST_AUDIO_CONTEXT = 1;
+ private static final int TEST_VOLUME_GROUP_ID = 2;
+ private static final int MEDIA_APP_UID = 100000;
+ private static final String MEDIA_CLIENT_ID = "client-id";
+ private static final String MEDIA_PACKAGE_NAME = "android.car.oem";
+
+ @Test
+ public void build() {
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+
+ expectWithMessage("Audio focus info from builder").that(entry.getAudioFocusInfo())
+ .isEqualTo(TEST_AUDIO_FOCUS_INFO);
+ expectWithMessage("Audio context from builder").that(entry.getAudioContextId())
+ .isEqualTo(TEST_AUDIO_CONTEXT);
+ expectWithMessage("Volume group id from builder").that(entry.getAudioVolumeGroupId())
+ .isEqualTo(TEST_VOLUME_GROUP_ID);
+ expectWithMessage("Audio focus results from builder").that(entry.getAudioFocusResult())
+ .isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
+ }
+
+ @Test
+ public void writeToParcel() {
+ Parcel parcel = Parcel.obtain();
+
+ AudioFocusEntry entry = createAndWriteEntryToParcel(parcel);
+
+ expectWithMessage("Car volume entry from parcel")
+ .that(new AudioFocusEntry(parcel)).isEqualTo(entry);
+ }
+
+ @Test
+ public void createFromParcel() {
+ Parcel parcel = Parcel.obtain();
+
+ AudioFocusEntry entry = createAndWriteEntryToParcel(parcel);
+
+ expectWithMessage("Car volume entry created from parcel")
+ .that(AudioFocusEntry.CREATOR.createFromParcel(parcel)).isEqualTo(entry);
+ }
+
+ @Test
+ public void setAudioFocusEntry() {
+ AudioFocusInfo testSecondInfo = createAudioFocusInfo(USAGE_ASSISTANCE_NAVIGATION_GUIDANCE);
+
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioFocusInfo(testSecondInfo).build();
+
+ expectWithMessage("Second audio focus entry from builder").that(entry.getAudioFocusInfo())
+ .isEqualTo(testSecondInfo);
+ }
+
+ @Test
+ public void setAudioFocusEntry_withNullInfo_fails() {
+ NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+ new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioFocusInfo(/* audioFocusInfo= */ null)
+ );
+
+ expectWithMessage("Null audio focus name exception")
+ .that(thrown).hasMessageThat().contains("Audio focus info");
+ }
+
+ @Test
+ public void setAudioContextId() {
+ int testAudioContext = 10;
+
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioContextId(testAudioContext).build();
+
+ expectWithMessage("Set audio context from builder").that(entry.getAudioContextId())
+ .isEqualTo(testAudioContext);
+ }
+
+ @Test
+ public void setAudioVolumeGroupId() {
+ int testVolumeGroupId = 6;
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioVolumeGroupId(testVolumeGroupId).build();
+
+ expectWithMessage("Set audio volume group from builder")
+ .that(entry.getAudioVolumeGroupId()).isEqualTo(testVolumeGroupId);
+ }
+
+ @Test
+ public void setAudioFocusResult() {
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioFocusResult(AudioManager.AUDIOFOCUS_LOSS).build();
+
+ expectWithMessage("Set audio focus results from builder")
+ .that(entry.getAudioFocusResult()).isEqualTo(AudioManager.AUDIOFOCUS_LOSS);
+ }
+
+ @Test
+ public void builder_withReuse_fails() {
+ AudioFocusEntry.Builder builder = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN)
+ .setAudioFocusResult(AudioManager.AUDIOFOCUS_LOSS);
+ builder.build();
+
+ IllegalStateException thrown = assertThrows(IllegalStateException.class, () ->
+ builder.build()
+ );
+
+ expectWithMessage("Reuse builder exception")
+ .that(thrown).hasMessageThat().contains("should not be reused");
+ }
+
+ @Test
+ public void builder_withAudioFocusEntry() {
+ AudioFocusEntry testEntry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(testEntry).build();
+
+ expectWithMessage("Audio focus info from copy builder")
+ .that(entry.getAudioFocusInfo()).isEqualTo(TEST_AUDIO_FOCUS_INFO);
+ expectWithMessage("Audio context from copy builder").that(entry.getAudioContextId())
+ .isEqualTo(TEST_AUDIO_CONTEXT);
+ expectWithMessage("Volume group id from copy builder")
+ .that(entry.getAudioVolumeGroupId()).isEqualTo(TEST_VOLUME_GROUP_ID);
+ expectWithMessage("Audio focus results from copy builder")
+ .that(entry.getAudioFocusResult()).isEqualTo(AudioManager.AUDIOFOCUS_GAIN);
+ }
+
+ @Test
+ public void builder_withNullEntry_fails() {
+ NullPointerException thrown = assertThrows(NullPointerException.class, () ->
+ new AudioFocusEntry.Builder(/* entry= */ null)
+ );
+
+ expectWithMessage("Null audio focus name exception")
+ .that(thrown).hasMessageThat().contains("Audio focus entry");
+ }
+
+ private static AudioFocusInfo createAudioFocusInfoForMedia() {
+ return createAudioFocusInfo(USAGE_MEDIA);
+ }
+
+ private static AudioFocusInfo createAudioFocusInfo(int usage) {
+ AudioAttributes.Builder builder = new AudioAttributes.Builder();
+ builder.setUsage(usage);
+
+ return new AudioFocusInfo(builder.build(), MEDIA_APP_UID, MEDIA_CLIENT_ID,
+ MEDIA_PACKAGE_NAME, AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_LOSS,
+ MEDIA_EMPTY_FLAG, SDK_INT);
+ }
+
+ private AudioFocusEntry createAndWriteEntryToParcel(Parcel parcel) {
+ AudioFocusEntry entry = new AudioFocusEntry.Builder(TEST_AUDIO_FOCUS_INFO,
+ TEST_AUDIO_CONTEXT, TEST_VOLUME_GROUP_ID, AudioManager.AUDIOFOCUS_GAIN).build();
+ entry.writeToParcel(parcel, TEST_PARCEL_FLAGS);
+ parcel.setDataPosition(/* position= */ 0);
+ return entry;
+ }
+}