From 3b18e55af36ba84f71d1d1676b370b4244fc2d3f Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Tue, 8 Nov 2022 02:40:18 +0000 Subject: [PATCH] Hotword: Add HotwordAudioStream list in HotwordDetectedResult - Create the new data class HotwordAudioStream - Add HowordAudioStream list into HotwordDetectedResult - Add @UnsupportedAppUsage and remove some codegen data Test: atest CtsVoiceInteractionTestCases Bug: 243766281 Bug: 243597982 Change-Id: I0953a93195699b17d4a69bba6c4140bc91eecb79 Merged-In: I0953a93195699b17d4a69bba6c4140bc91eecb79 --- .../service/voice/HotwordAudioStream.aidl | 19 + .../service/voice/HotwordAudioStream.java | 434 ++++++++++++++++++ .../service/voice/HotwordDetectedResult.java | 74 ++- 3 files changed, 521 insertions(+), 6 deletions(-) create mode 100644 core/java/android/service/voice/HotwordAudioStream.aidl create mode 100644 core/java/android/service/voice/HotwordAudioStream.java diff --git a/core/java/android/service/voice/HotwordAudioStream.aidl b/core/java/android/service/voice/HotwordAudioStream.aidl new file mode 100644 index 0000000000000..9550c830aeccf --- /dev/null +++ b/core/java/android/service/voice/HotwordAudioStream.aidl @@ -0,0 +1,19 @@ +/* + * 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.service.voice; + +parcelable HotwordAudioStream; diff --git a/core/java/android/service/voice/HotwordAudioStream.java b/core/java/android/service/voice/HotwordAudioStream.java new file mode 100644 index 0000000000000..c44542ceec6b1 --- /dev/null +++ b/core/java/android/service/voice/HotwordAudioStream.java @@ -0,0 +1,434 @@ +/* + * 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.service.voice; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; +import android.media.AudioFormat; +import android.media.AudioRecord; +import android.media.AudioTimestamp; +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; +import android.os.PersistableBundle; + +import java.util.Objects; + +/** + * Represents an audio stream supporting the hotword detection. + * + * @hide + */ +public final class HotwordAudioStream implements Parcelable { + + /** + * The {@link AudioFormat} of the audio stream. + */ + @NonNull + @UnsupportedAppUsage + private final AudioFormat mAudioFormat; + + /** + * This stream starts with the audio bytes used for hotword detection, but continues streaming + * the audio until the stream is shutdown by the {@link HotwordDetectionService}. + */ + @NonNull + @UnsupportedAppUsage + private final ParcelFileDescriptor mAudioStreamParcelFileDescriptor; + + /** + * The timestamp when the audio stream was captured by the Audio platform. + * + *

+ * The {@link HotwordDetectionService} egressing the audio is the owner of the underlying + * AudioRecord. The {@link HotwordDetectionService} is expected to optionally populate this + * field by {@link AudioRecord#getTimestamp}. + *

+ * + *

+ * This timestamp can be used in conjunction with the + * {@link HotwordDetectedResult#getHotwordOffsetMillis()} and + * {@link HotwordDetectedResult#getHotwordDurationMillis()} to translate these durations to + * timestamps. + *

+ * + * @see #getAudioStreamParcelFileDescriptor() + */ + @Nullable + @UnsupportedAppUsage + private final AudioTimestamp mTimestamp; + + private static AudioTimestamp defaultTimestamp() { + return null; + } + + /** + * The metadata associated with the audio stream. + */ + @NonNull + @UnsupportedAppUsage + private final PersistableBundle mMetadata; + + private static PersistableBundle defaultMetadata() { + return new PersistableBundle(); + } + + private String timestampToString() { + if (mTimestamp == null) { + return ""; + } + return "TimeStamp:" + + " framePos=" + mTimestamp.framePosition + + " nanoTime=" + mTimestamp.nanoTime; + } + + private void parcelTimestamp(Parcel dest, int flags) { + if (mTimestamp != null) { + // mTimestamp is not null, we write it to the parcel, set true. + dest.writeBoolean(true); + dest.writeLong(mTimestamp.framePosition); + dest.writeLong(mTimestamp.nanoTime); + } else { + // mTimestamp is null, we don't write any value out, set false. + dest.writeBoolean(false); + } + } + + @Nullable + private static AudioTimestamp unparcelTimestamp(Parcel in) { + // If it is true, it means we wrote the value to the parcel before, parse it. + // Otherwise, return null. + if (in.readBoolean()) { + final AudioTimestamp timeStamp = new AudioTimestamp(); + timeStamp.framePosition = in.readLong(); + timeStamp.nanoTime = in.readLong(); + return timeStamp; + } else { + return null; + } + } + + /* package-private */ + HotwordAudioStream( + @NonNull AudioFormat audioFormat, + @NonNull ParcelFileDescriptor audioStreamParcelFileDescriptor, + @Nullable AudioTimestamp timestamp, + @NonNull PersistableBundle metadata) { + this.mAudioFormat = audioFormat; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioFormat); + this.mAudioStreamParcelFileDescriptor = audioStreamParcelFileDescriptor; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioStreamParcelFileDescriptor); + this.mTimestamp = timestamp; + this.mMetadata = metadata; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMetadata); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The {@link AudioFormat} of the audio stream. + */ + @UnsupportedAppUsage + @NonNull + public AudioFormat getAudioFormat() { + return mAudioFormat; + } + + /** + * This stream starts with the audio bytes used for hotword detection, but continues streaming + * the audio until the stream is shutdown by the {@link HotwordDetectionService}. + */ + @UnsupportedAppUsage + @NonNull + public ParcelFileDescriptor getAudioStreamParcelFileDescriptor() { + return mAudioStreamParcelFileDescriptor; + } + + /** + * The timestamp when the audio stream was captured by the Audio platform. + * + *

+ * The {@link HotwordDetectionService} egressing the audio is the owner of the underlying + * AudioRecord. The {@link HotwordDetectionService} is expected to optionally populate this + * field by {@link AudioRecord#getTimestamp}. + *

+ * + *

+ * This timestamp can be used in conjunction with the + * {@link HotwordDetectedResult#getHotwordOffsetMillis()} and + * {@link HotwordDetectedResult#getHotwordDurationMillis()} to translate these durations to + * timestamps. + *

+ * + * @see #getAudioStreamParcelFileDescriptor() + */ + @UnsupportedAppUsage + @Nullable + public AudioTimestamp getTimestamp() { + return mTimestamp; + } + + /** + * The metadata associated with the audio stream. + */ + @UnsupportedAppUsage + @NonNull + public PersistableBundle getMetadata() { + return mMetadata; + } + + @Override + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "HotwordAudioStream { " + + "audioFormat = " + mAudioFormat + ", " + + "audioStreamParcelFileDescriptor = " + mAudioStreamParcelFileDescriptor + ", " + + "timestamp = " + timestampToString() + ", " + + "metadata = " + mMetadata + " }"; + } + + @Override + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(HotwordAudioStream other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + HotwordAudioStream that = (HotwordAudioStream) o; + //noinspection PointlessBooleanExpression + return Objects.equals(mAudioFormat, that.mAudioFormat) + && Objects.equals(mAudioStreamParcelFileDescriptor, + that.mAudioStreamParcelFileDescriptor) + && Objects.equals(mTimestamp, that.mTimestamp) + && Objects.equals(mMetadata, that.mMetadata); + } + + @Override + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + Objects.hashCode(mAudioFormat); + _hash = 31 * _hash + Objects.hashCode(mAudioStreamParcelFileDescriptor); + _hash = 31 * _hash + Objects.hashCode(mTimestamp); + _hash = 31 * _hash + Objects.hashCode(mMetadata); + return _hash; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mTimestamp != null) flg |= 0x4; + dest.writeByte(flg); + dest.writeTypedObject(mAudioFormat, flags); + dest.writeTypedObject(mAudioStreamParcelFileDescriptor, flags); + parcelTimestamp(dest, flags); + dest.writeTypedObject(mMetadata, flags); + } + + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + /* package-private */ + HotwordAudioStream(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + AudioFormat audioFormat = (AudioFormat) in.readTypedObject(AudioFormat.CREATOR); + ParcelFileDescriptor audioStreamParcelFileDescriptor = + (ParcelFileDescriptor) in.readTypedObject(ParcelFileDescriptor.CREATOR); + AudioTimestamp timestamp = unparcelTimestamp(in); + PersistableBundle metadata = (PersistableBundle) in.readTypedObject( + PersistableBundle.CREATOR); + + this.mAudioFormat = audioFormat; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioFormat); + this.mAudioStreamParcelFileDescriptor = audioStreamParcelFileDescriptor; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioStreamParcelFileDescriptor); + this.mTimestamp = timestamp; + this.mMetadata = metadata; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMetadata); + + // onConstructed(); // You can define this method to get a callback + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public HotwordAudioStream[] newArray(int size) { + return new HotwordAudioStream[size]; + } + + @Override + public HotwordAudioStream createFromParcel(@NonNull Parcel in) { + return new HotwordAudioStream(in); + } + }; + + /** + * A builder for {@link HotwordAudioStream} + */ + @SuppressWarnings("WeakerAccess") + public static final class Builder { + + @NonNull + private AudioFormat mAudioFormat; + @NonNull + private ParcelFileDescriptor mAudioStreamParcelFileDescriptor; + @Nullable + private AudioTimestamp mTimestamp; + @NonNull + private PersistableBundle mMetadata; + + private long mBuilderFieldsSet = 0L; + + /** + * Creates a new Builder. + * + * @param audioFormat The {@link AudioFormat} of the audio stream. + * @param audioStreamParcelFileDescriptor This stream starts with the audio bytes used for + * hotword detection, but continues streaming + * the audio until the stream is shutdown by the + * {@link HotwordDetectionService}. + */ + @UnsupportedAppUsage + public Builder( + @NonNull AudioFormat audioFormat, + @NonNull ParcelFileDescriptor audioStreamParcelFileDescriptor) { + mAudioFormat = audioFormat; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioFormat); + mAudioStreamParcelFileDescriptor = audioStreamParcelFileDescriptor; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioStreamParcelFileDescriptor); + } + + /** + * The {@link AudioFormat} of the audio stream. + */ + @UnsupportedAppUsage + @NonNull + public Builder setAudioFormat(@NonNull AudioFormat value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mAudioFormat = value; + return this; + } + + /** + * This stream starts with the audio bytes used for hotword detection, but continues + * streaming + * the audio until the stream is shutdown by the {@link HotwordDetectionService}. + */ + @UnsupportedAppUsage + @NonNull + public Builder setAudioStreamParcelFileDescriptor(@NonNull ParcelFileDescriptor value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mAudioStreamParcelFileDescriptor = value; + return this; + } + + /** + * The timestamp when the audio stream was captured by the Audio platform. + * + *

+ * The {@link HotwordDetectionService} egressing the audio is the owner of the underlying + * AudioRecord. The {@link HotwordDetectionService} is expected to optionally populate this + * field by {@link AudioRecord#getTimestamp}. + *

+ * + *

+ * This timestamp can be used in conjunction with the + * {@link HotwordDetectedResult#getHotwordOffsetMillis()} and + * {@link HotwordDetectedResult#getHotwordDurationMillis()} to translate these durations to + * timestamps. + *

+ * + * @see #getAudioStreamParcelFileDescriptor() + */ + @UnsupportedAppUsage + @NonNull + public Builder setTimestamp(@NonNull AudioTimestamp value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; + mTimestamp = value; + return this; + } + + /** + * The metadata associated with the audio stream. + */ + @UnsupportedAppUsage + @NonNull + public Builder setMetadata(@NonNull PersistableBundle value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x8; + mMetadata = value; + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + @UnsupportedAppUsage + @NonNull + public HotwordAudioStream build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x10; // Mark builder used + + if ((mBuilderFieldsSet & 0x4) == 0) { + mTimestamp = defaultTimestamp(); + } + if ((mBuilderFieldsSet & 0x8) == 0) { + mMetadata = defaultMetadata(); + } + HotwordAudioStream o = new HotwordAudioStream( + mAudioFormat, + mAudioStreamParcelFileDescriptor, + mTimestamp, + mMetadata); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x10) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } +} diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java index ab71459ed51e0..0468a619b7989 100644 --- a/core/java/android/service/voice/HotwordDetectedResult.java +++ b/core/java/android/service/voice/HotwordDetectedResult.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.media.AudioRecord; import android.media.MediaSyncEvent; @@ -31,6 +32,9 @@ import com.android.internal.R; import com.android.internal.util.DataClass; import com.android.internal.util.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Objects; /** @@ -195,6 +199,17 @@ public final class HotwordDetectedResult implements Parcelable { return 63; } + /** + * The list of the audio streams containing audio bytes that were used for hotword detection. + * + * @hide + */ + @NonNull + private final List mAudioStreams; + private static List defaultAudioStreams() { + return Collections.emptyList(); + } + /** * App-specific extras to support trigger. * @@ -353,6 +368,35 @@ public final class HotwordDetectedResult implements Parcelable { } } + /** + * The list of the audio streams containing audio bytes that were used for hotword detection. + * + * @hide + */ + @UnsupportedAppUsage + public @NonNull List getAudioStreams() { + return List.copyOf(mAudioStreams); + } + + @DataClass.Suppress("addAudioStreams") + abstract static class BaseBuilder { + /** + * The list of the audio streams containing audio bytes that were used for hotword + * detection. + * + * @hide + */ + @UnsupportedAppUsage + public @NonNull Builder setAudioStreams(@NonNull List value) { + Objects.requireNonNull(value, "value should not be null"); + final Builder builder = (Builder) this; + // If the code gen flag in build() is changed, we must update the flag e.g. 0x200 here. + builder.mBuilderFieldsSet |= 0x200; + builder.mAudioStreams = List.copyOf(value); + return builder; + } + } + // Code below generated by codegen v1.0.23. @@ -436,6 +480,7 @@ public final class HotwordDetectedResult implements Parcelable { int score, int personalizedScore, int hotwordPhraseId, + @NonNull List audioStreams, @NonNull PersistableBundle extras) { this.mConfidenceLevel = confidenceLevel; com.android.internal.util.AnnotationValidations.validate( @@ -448,6 +493,9 @@ public final class HotwordDetectedResult implements Parcelable { this.mScore = score; this.mPersonalizedScore = personalizedScore; this.mHotwordPhraseId = hotwordPhraseId; + this.mAudioStreams = audioStreams; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioStreams); this.mExtras = extras; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mExtras); @@ -578,6 +626,7 @@ public final class HotwordDetectedResult implements Parcelable { "score = " + mScore + ", " + "personalizedScore = " + mPersonalizedScore + ", " + "hotwordPhraseId = " + mHotwordPhraseId + ", " + + "audioStreams = " + mAudioStreams + ", " + "extras = " + mExtras + " }"; } @@ -604,6 +653,7 @@ public final class HotwordDetectedResult implements Parcelable { && mScore == that.mScore && mPersonalizedScore == that.mPersonalizedScore && mHotwordPhraseId == that.mHotwordPhraseId + && Objects.equals(mAudioStreams, that.mAudioStreams) && Objects.equals(mExtras, that.mExtras); } @@ -623,6 +673,7 @@ public final class HotwordDetectedResult implements Parcelable { _hash = 31 * _hash + mScore; _hash = 31 * _hash + mPersonalizedScore; _hash = 31 * _hash + mHotwordPhraseId; + _hash = 31 * _hash + Objects.hashCode(mAudioStreams); _hash = 31 * _hash + Objects.hashCode(mExtras); return _hash; } @@ -645,6 +696,7 @@ public final class HotwordDetectedResult implements Parcelable { dest.writeInt(mScore); dest.writeInt(mPersonalizedScore); dest.writeInt(mHotwordPhraseId); + dest.writeParcelableList(mAudioStreams, flags); dest.writeTypedObject(mExtras, flags); } @@ -669,6 +721,8 @@ public final class HotwordDetectedResult implements Parcelable { int score = in.readInt(); int personalizedScore = in.readInt(); int hotwordPhraseId = in.readInt(); + List audioStreams = new ArrayList<>(); + in.readParcelableList(audioStreams, HotwordAudioStream.class.getClassLoader()); PersistableBundle extras = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR); this.mConfidenceLevel = confidenceLevel; @@ -682,6 +736,9 @@ public final class HotwordDetectedResult implements Parcelable { this.mScore = score; this.mPersonalizedScore = personalizedScore; this.mHotwordPhraseId = hotwordPhraseId; + this.mAudioStreams = audioStreams; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAudioStreams); this.mExtras = extras; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mExtras); @@ -708,7 +765,7 @@ public final class HotwordDetectedResult implements Parcelable { */ @SuppressWarnings("WeakerAccess") @DataClass.Generated.Member - public static final class Builder { + public static final class Builder extends BaseBuilder { private @HotwordConfidenceLevelValue int mConfidenceLevel; private @Nullable MediaSyncEvent mMediaSyncEvent; @@ -719,6 +776,7 @@ public final class HotwordDetectedResult implements Parcelable { private int mScore; private int mPersonalizedScore; private int mHotwordPhraseId; + private @NonNull List mAudioStreams; private @NonNull PersistableBundle mExtras; private long mBuilderFieldsSet = 0L; @@ -868,7 +926,7 @@ public final class HotwordDetectedResult implements Parcelable { @DataClass.Generated.Member public @NonNull Builder setExtras(@NonNull PersistableBundle value) { checkNotUsed(); - mBuilderFieldsSet |= 0x200; + mBuilderFieldsSet |= 0x400; mExtras = value; return this; } @@ -876,7 +934,7 @@ public final class HotwordDetectedResult implements Parcelable { /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull HotwordDetectedResult build() { checkNotUsed(); - mBuilderFieldsSet |= 0x400; // Mark builder used + mBuilderFieldsSet |= 0x800; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mConfidenceLevel = defaultConfidenceLevel(); @@ -906,6 +964,9 @@ public final class HotwordDetectedResult implements Parcelable { mHotwordPhraseId = defaultHotwordPhraseId(); } if ((mBuilderFieldsSet & 0x200) == 0) { + mAudioStreams = defaultAudioStreams(); + } + if ((mBuilderFieldsSet & 0x400) == 0) { mExtras = defaultExtras(); } HotwordDetectedResult o = new HotwordDetectedResult( @@ -918,12 +979,13 @@ public final class HotwordDetectedResult implements Parcelable { mScore, mPersonalizedScore, mHotwordPhraseId, + mAudioStreams, mExtras); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x400) != 0) { + if ((mBuilderFieldsSet & 0x800) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -931,10 +993,10 @@ public final class HotwordDetectedResult implements Parcelable { } @DataClass.Generated( - time = 1658357814396L, + time = 1668405106028L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java", - inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\npublic static final java.lang.String EXTRA_PROXIMITY_METERS\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE\nprivate static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE\npublic static final java.lang.String EXTRA_PROXIMITY_METERS\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull java.util.List mAudioStreams\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static java.util.List defaultAudioStreams()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\npublic static int getUsageSize(android.service.voice.HotwordDetectedResult)\nprivate static int bitCount(long)\nprivate void onConstructed()\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull java.util.List getAudioStreams()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull android.service.voice.HotwordDetectedResult.Builder setAudioStreams(java.util.List)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)\npublic @android.compat.annotation.UnsupportedAppUsage @android.annotation.NonNull android.service.voice.HotwordDetectedResult.Builder setAudioStreams(java.util.List)\nclass BaseBuilder extends java.lang.Object implements []") @Deprecated private void __metadata() {}