1 /*
2  * Copyright (C) 2021 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.service.voice;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.SystemApi;
23 import android.content.res.Resources;
24 import android.media.AudioRecord;
25 import android.media.MediaSyncEvent;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 import android.os.PersistableBundle;
29 
30 import com.android.internal.R;
31 import com.android.internal.util.DataClass;
32 import com.android.internal.util.Preconditions;
33 
34 import java.util.Objects;
35 
36 /**
37  * Represents a result supporting the hotword detection.
38  *
39  * @hide
40  */
41 @DataClass(
42         genConstructor = false,
43         genBuilder = true,
44         genEqualsHashCode = true,
45         genHiddenConstDefs = true,
46         genParcelable = true,
47         genToString = true
48 )
49 @SystemApi
50 public final class HotwordDetectedResult implements Parcelable {
51 
52     /** No confidence in hotword detector result. */
53     public static final int CONFIDENCE_LEVEL_NONE = 0;
54 
55     /** Low confidence in hotword detector result. */
56     public static final int CONFIDENCE_LEVEL_LOW = 1;
57 
58     /** Low-to-medium confidence in hotword detector result. */
59     public static final int CONFIDENCE_LEVEL_LOW_MEDIUM = 2;
60 
61     /** Medium confidence in hotword detector result. */
62     public static final int CONFIDENCE_LEVEL_MEDIUM = 3;
63 
64     /** Medium-to-high confidence in hotword detector result. */
65     public static final int CONFIDENCE_LEVEL_MEDIUM_HIGH = 4;
66 
67     /** High confidence in hotword detector result. */
68     public static final int CONFIDENCE_LEVEL_HIGH = 5;
69 
70     /** Very high confidence in hotword detector result. */
71     public static final int CONFIDENCE_LEVEL_VERY_HIGH = 6;
72 
73     /** @hide */
74     @IntDef(prefix = {"CONFIDENCE_LEVEL_"}, value = {
75             CONFIDENCE_LEVEL_NONE,
76             CONFIDENCE_LEVEL_LOW,
77             CONFIDENCE_LEVEL_LOW_MEDIUM,
78             CONFIDENCE_LEVEL_MEDIUM,
79             CONFIDENCE_LEVEL_MEDIUM_HIGH,
80             CONFIDENCE_LEVEL_HIGH,
81             CONFIDENCE_LEVEL_VERY_HIGH
82     })
83     @interface HotwordConfidenceLevelValue {
84     }
85 
86     /** Represents unset value for the hotword offset. */
87     public static final int HOTWORD_OFFSET_UNSET = -1;
88 
89     /** Represents unset value for the triggered audio channel. */
90     public static final int AUDIO_CHANNEL_UNSET = -1;
91 
92     /** Limits the max value for the hotword offset. */
93     private static final int LIMIT_HOTWORD_OFFSET_MAX_VALUE = 60 * 60 * 1000; // 1 hour
94 
95     /** Limits the max value for the triggered audio channel. */
96     private static final int LIMIT_AUDIO_CHANNEL_MAX_VALUE = 63;
97 
98     /** Confidence level in the trigger outcome. */
99     @HotwordConfidenceLevelValue
100     private final int mConfidenceLevel;
defaultConfidenceLevel()101     private static int defaultConfidenceLevel() {
102         return CONFIDENCE_LEVEL_NONE;
103     }
104 
105     /**
106      * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
107      * that contains the hotword trigger. This must be obtained using
108      * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
109      */
110     @Nullable
111     private MediaSyncEvent mMediaSyncEvent = null;
112 
113     /**
114      * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
115      * phrase).
116      *
117      * <p>Only value between 0 and 3600000 (inclusive) is accepted.
118      */
119     private int mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
120 
121     /**
122      * Duration in milliseconds of the hotword trigger phrase.
123      *
124      * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
125      * (inclusive) are accepted.
126      */
127     private int mHotwordDurationMillis = 0;
128 
129     /**
130      * Audio channel containing the highest-confidence hotword signal.
131      *
132      * <p>Only value between 0 and 63 (inclusive) is accepted.
133      */
134     private int mAudioChannel = AUDIO_CHANNEL_UNSET;
135 
136     /**
137      * Returns whether the trigger has happened due to model having been personalized to fit user's
138      * voice.
139      */
140     private boolean mHotwordDetectionPersonalized = false;
141 
142     /**
143      * Score for the hotword trigger.
144      *
145      * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
146      */
147     private final int mScore;
defaultScore()148     private static int defaultScore() {
149         return 0;
150     }
151 
152     /**
153      * Score for the hotword trigger for device user.
154      *
155      * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
156      */
157     private final int mPersonalizedScore;
defaultPersonalizedScore()158     private static int defaultPersonalizedScore() {
159         return 0;
160     }
161 
162     /**
163      * Returns the maximum values of {@link #getScore} and {@link #getPersonalizedScore}.
164      * <p>
165      * The float value should be calculated as {@code getScore() / getMaxScore()}.
166      */
getMaxScore()167     public static int getMaxScore() {
168         return 255;
169     }
170 
171     /**
172      * An ID representing the keyphrase that triggered the successful detection.
173      *
174      * <p>Only values between 0 and {@link #getMaxHotwordPhraseId()} (inclusive) are accepted.
175      */
176     private final int mHotwordPhraseId;
defaultHotwordPhraseId()177     private static int defaultHotwordPhraseId() {
178         return 0;
179     }
180 
181     /**
182      * Returns the maximum value of {@link #getHotwordPhraseId()}.
183      */
getMaxHotwordPhraseId()184     public static int getMaxHotwordPhraseId() {
185         return 63;
186     }
187 
188     /**
189      * App-specific extras to support trigger.
190      *
191      * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
192      * bundles will be rejected.
193      *
194      * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
195      * bundle.
196      *
197      * <p>The use of this method is discouraged, and support for it will be removed in future
198      * versions of Android.
199      *
200      * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
201      * that can be used to communicate with other processes.
202      */
203     @NonNull
204     private final PersistableBundle mExtras;
defaultExtras()205     private static PersistableBundle defaultExtras() {
206         return new PersistableBundle();
207     }
208 
209     private static int sMaxBundleSize = -1;
210 
211     /**
212      * Returns the maximum byte size of the information contained in the bundle.
213      *
214      * <p>The total size will be calculated by how much bundle data should be written into the
215      * Parcel.
216      */
getMaxBundleSize()217     public static int getMaxBundleSize() {
218         if (sMaxBundleSize < 0) {
219             sMaxBundleSize = Resources.getSystem().getInteger(
220                     R.integer.config_hotwordDetectedResultMaxBundleSize);
221         }
222         return sMaxBundleSize;
223     }
224 
225     /**
226      * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
227      * that contains the hotword trigger. This must be obtained using
228      * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
229      * <p>
230      * This can be {@code null} if reprocessing the hotword trigger isn't required.
231      */
232     // Suppress codegen to make javadoc consistent. Getter returns @Nullable, setter accepts
233     // @NonNull only, and by default codegen would use the same javadoc on both.
getMediaSyncEvent()234     public @Nullable MediaSyncEvent getMediaSyncEvent() {
235         return mMediaSyncEvent;
236     }
237 
238     /**
239      * Returns how many bytes should be written into the Parcel
240      *
241      * @hide
242      */
getParcelableSize(@onNull Parcelable parcelable)243     public static int getParcelableSize(@NonNull Parcelable parcelable) {
244         final Parcel p = Parcel.obtain();
245         parcelable.writeToParcel(p, 0);
246         p.setDataPosition(0);
247         final int size = p.dataSize();
248         p.recycle();
249         return size;
250     }
251 
252     /**
253      * Returns how many bits have been written into the HotwordDetectedResult.
254      *
255      * @hide
256      */
getUsageSize(@onNull HotwordDetectedResult hotwordDetectedResult)257     public static int getUsageSize(@NonNull HotwordDetectedResult hotwordDetectedResult) {
258         int totalBits = 0;
259 
260         if (hotwordDetectedResult.getConfidenceLevel() != defaultConfidenceLevel()) {
261             totalBits += bitCount(CONFIDENCE_LEVEL_VERY_HIGH);
262         }
263         if (hotwordDetectedResult.getHotwordOffsetMillis() != HOTWORD_OFFSET_UNSET) {
264             totalBits += bitCount(LIMIT_HOTWORD_OFFSET_MAX_VALUE);
265         }
266         if (hotwordDetectedResult.getHotwordDurationMillis() != 0) {
267             totalBits += bitCount(AudioRecord.getMaxSharedAudioHistoryMillis());
268         }
269         if (hotwordDetectedResult.getAudioChannel() != AUDIO_CHANNEL_UNSET) {
270             totalBits += bitCount(LIMIT_AUDIO_CHANNEL_MAX_VALUE);
271         }
272 
273         // Add one bit for HotwordDetectionPersonalized
274         totalBits += 1;
275 
276         if (hotwordDetectedResult.getScore() != defaultScore()) {
277             totalBits += bitCount(HotwordDetectedResult.getMaxScore());
278         }
279         if (hotwordDetectedResult.getPersonalizedScore() != defaultPersonalizedScore()) {
280             totalBits += bitCount(HotwordDetectedResult.getMaxScore());
281         }
282         if (hotwordDetectedResult.getHotwordPhraseId() != defaultHotwordPhraseId()) {
283             totalBits += bitCount(HotwordDetectedResult.getMaxHotwordPhraseId());
284         }
285         PersistableBundle persistableBundle = hotwordDetectedResult.getExtras();
286         if (!persistableBundle.isEmpty()) {
287             totalBits += getParcelableSize(persistableBundle) * Byte.SIZE;
288         }
289         return totalBits;
290     }
291 
bitCount(long value)292     private static int bitCount(long value) {
293         int bits = 0;
294         while (value > 0) {
295             bits++;
296             value = value >> 1;
297         }
298         return bits;
299     }
300 
onConstructed()301     private void onConstructed() {
302         Preconditions.checkArgumentInRange(mScore, 0, getMaxScore(), "score");
303         Preconditions.checkArgumentInRange(mPersonalizedScore, 0, getMaxScore(),
304                 "personalizedScore");
305         Preconditions.checkArgumentInRange(mHotwordPhraseId, 0, getMaxHotwordPhraseId(),
306                 "hotwordPhraseId");
307         Preconditions.checkArgumentInRange((long) mHotwordDurationMillis, 0,
308                 AudioRecord.getMaxSharedAudioHistoryMillis(), "hotwordDurationMillis");
309         if (mHotwordOffsetMillis != HOTWORD_OFFSET_UNSET) {
310             Preconditions.checkArgumentInRange(mHotwordOffsetMillis, 0,
311                     LIMIT_HOTWORD_OFFSET_MAX_VALUE, "hotwordOffsetMillis");
312         }
313         if (mAudioChannel != AUDIO_CHANNEL_UNSET) {
314             Preconditions.checkArgumentInRange(mAudioChannel, 0, LIMIT_AUDIO_CHANNEL_MAX_VALUE,
315                     "audioChannel");
316         }
317         if (!mExtras.isEmpty()) {
318             Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(),
319                     "extras");
320         }
321     }
322 
323 
324 
325     // Code below generated by codegen v1.0.23.
326     //
327     // DO NOT MODIFY!
328     // CHECKSTYLE:OFF Generated code
329     //
330     // To regenerate run:
331     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java
332     //
333     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
334     //   Settings > Editor > Code Style > Formatter Control
335     //@formatter:off
336 
337 
338     /** @hide */
339     @IntDef(prefix = "CONFIDENCE_LEVEL_", value = {
340         CONFIDENCE_LEVEL_NONE,
341         CONFIDENCE_LEVEL_LOW,
342         CONFIDENCE_LEVEL_LOW_MEDIUM,
343         CONFIDENCE_LEVEL_MEDIUM,
344         CONFIDENCE_LEVEL_MEDIUM_HIGH,
345         CONFIDENCE_LEVEL_HIGH,
346         CONFIDENCE_LEVEL_VERY_HIGH
347     })
348     @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
349     @DataClass.Generated.Member
350     public @interface ConfidenceLevel {}
351 
352     /** @hide */
353     @DataClass.Generated.Member
confidenceLevelToString(@onfidenceLevel int value)354     public static String confidenceLevelToString(@ConfidenceLevel int value) {
355         switch (value) {
356             case CONFIDENCE_LEVEL_NONE:
357                     return "CONFIDENCE_LEVEL_NONE";
358             case CONFIDENCE_LEVEL_LOW:
359                     return "CONFIDENCE_LEVEL_LOW";
360             case CONFIDENCE_LEVEL_LOW_MEDIUM:
361                     return "CONFIDENCE_LEVEL_LOW_MEDIUM";
362             case CONFIDENCE_LEVEL_MEDIUM:
363                     return "CONFIDENCE_LEVEL_MEDIUM";
364             case CONFIDENCE_LEVEL_MEDIUM_HIGH:
365                     return "CONFIDENCE_LEVEL_MEDIUM_HIGH";
366             case CONFIDENCE_LEVEL_HIGH:
367                     return "CONFIDENCE_LEVEL_HIGH";
368             case CONFIDENCE_LEVEL_VERY_HIGH:
369                     return "CONFIDENCE_LEVEL_VERY_HIGH";
370             default: return Integer.toHexString(value);
371         }
372     }
373 
374     /** @hide */
375     @IntDef(prefix = "LIMIT_", value = {
376         LIMIT_HOTWORD_OFFSET_MAX_VALUE,
377         LIMIT_AUDIO_CHANNEL_MAX_VALUE
378     })
379     @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
380     @DataClass.Generated.Member
381     /* package-private */ @interface Limit {}
382 
383     /** @hide */
384     @DataClass.Generated.Member
limitToString(@imit int value)385     /* package-private */ static String limitToString(@Limit int value) {
386         switch (value) {
387             case LIMIT_HOTWORD_OFFSET_MAX_VALUE:
388                     return "LIMIT_HOTWORD_OFFSET_MAX_VALUE";
389             case LIMIT_AUDIO_CHANNEL_MAX_VALUE:
390                     return "LIMIT_AUDIO_CHANNEL_MAX_VALUE";
391             default: return Integer.toHexString(value);
392         }
393     }
394 
395     @DataClass.Generated.Member
HotwordDetectedResult( @otwordConfidenceLevelValue int confidenceLevel, @Nullable MediaSyncEvent mediaSyncEvent, int hotwordOffsetMillis, int hotwordDurationMillis, int audioChannel, boolean hotwordDetectionPersonalized, int score, int personalizedScore, int hotwordPhraseId, @NonNull PersistableBundle extras)396     /* package-private */ HotwordDetectedResult(
397             @HotwordConfidenceLevelValue int confidenceLevel,
398             @Nullable MediaSyncEvent mediaSyncEvent,
399             int hotwordOffsetMillis,
400             int hotwordDurationMillis,
401             int audioChannel,
402             boolean hotwordDetectionPersonalized,
403             int score,
404             int personalizedScore,
405             int hotwordPhraseId,
406             @NonNull PersistableBundle extras) {
407         this.mConfidenceLevel = confidenceLevel;
408         com.android.internal.util.AnnotationValidations.validate(
409                 HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
410         this.mMediaSyncEvent = mediaSyncEvent;
411         this.mHotwordOffsetMillis = hotwordOffsetMillis;
412         this.mHotwordDurationMillis = hotwordDurationMillis;
413         this.mAudioChannel = audioChannel;
414         this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
415         this.mScore = score;
416         this.mPersonalizedScore = personalizedScore;
417         this.mHotwordPhraseId = hotwordPhraseId;
418         this.mExtras = extras;
419         com.android.internal.util.AnnotationValidations.validate(
420                 NonNull.class, null, mExtras);
421 
422         onConstructed();
423     }
424 
425     /**
426      * Confidence level in the trigger outcome.
427      */
428     @DataClass.Generated.Member
getConfidenceLevel()429     public @HotwordConfidenceLevelValue int getConfidenceLevel() {
430         return mConfidenceLevel;
431     }
432 
433     /**
434      * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
435      * phrase).
436      *
437      * <p>Only value between 0 and 3600000 (inclusive) is accepted.
438      */
439     @DataClass.Generated.Member
getHotwordOffsetMillis()440     public int getHotwordOffsetMillis() {
441         return mHotwordOffsetMillis;
442     }
443 
444     /**
445      * Duration in milliseconds of the hotword trigger phrase.
446      *
447      * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
448      * (inclusive) are accepted.
449      */
450     @DataClass.Generated.Member
getHotwordDurationMillis()451     public int getHotwordDurationMillis() {
452         return mHotwordDurationMillis;
453     }
454 
455     /**
456      * Audio channel containing the highest-confidence hotword signal.
457      *
458      * <p>Only value between 0 and 63 (inclusive) is accepted.
459      */
460     @DataClass.Generated.Member
getAudioChannel()461     public int getAudioChannel() {
462         return mAudioChannel;
463     }
464 
465     /**
466      * Returns whether the trigger has happened due to model having been personalized to fit user's
467      * voice.
468      */
469     @DataClass.Generated.Member
isHotwordDetectionPersonalized()470     public boolean isHotwordDetectionPersonalized() {
471         return mHotwordDetectionPersonalized;
472     }
473 
474     /**
475      * Score for the hotword trigger.
476      *
477      * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
478      */
479     @DataClass.Generated.Member
getScore()480     public int getScore() {
481         return mScore;
482     }
483 
484     /**
485      * Score for the hotword trigger for device user.
486      *
487      * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
488      */
489     @DataClass.Generated.Member
getPersonalizedScore()490     public int getPersonalizedScore() {
491         return mPersonalizedScore;
492     }
493 
494     /**
495      * An ID representing the keyphrase that triggered the successful detection.
496      *
497      * <p>Only values between 0 and {@link #getMaxHotwordPhraseId()} (inclusive) are accepted.
498      */
499     @DataClass.Generated.Member
getHotwordPhraseId()500     public int getHotwordPhraseId() {
501         return mHotwordPhraseId;
502     }
503 
504     /**
505      * App-specific extras to support trigger.
506      *
507      * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
508      * bundles will be rejected.
509      *
510      * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
511      * bundle.
512      *
513      * <p>The use of this method is discouraged, and support for it will be removed in future
514      * versions of Android.
515      *
516      * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
517      * that can be used to communicate with other processes.
518      */
519     @DataClass.Generated.Member
getExtras()520     public @NonNull PersistableBundle getExtras() {
521         return mExtras;
522     }
523 
524     @Override
525     @DataClass.Generated.Member
toString()526     public String toString() {
527         // You can override field toString logic by defining methods like:
528         // String fieldNameToString() { ... }
529 
530         return "HotwordDetectedResult { " +
531                 "confidenceLevel = " + mConfidenceLevel + ", " +
532                 "mediaSyncEvent = " + mMediaSyncEvent + ", " +
533                 "hotwordOffsetMillis = " + mHotwordOffsetMillis + ", " +
534                 "hotwordDurationMillis = " + mHotwordDurationMillis + ", " +
535                 "audioChannel = " + mAudioChannel + ", " +
536                 "hotwordDetectionPersonalized = " + mHotwordDetectionPersonalized + ", " +
537                 "score = " + mScore + ", " +
538                 "personalizedScore = " + mPersonalizedScore + ", " +
539                 "hotwordPhraseId = " + mHotwordPhraseId + ", " +
540                 "extras = " + mExtras +
541         " }";
542     }
543 
544     @Override
545     @DataClass.Generated.Member
equals(@ullable Object o)546     public boolean equals(@Nullable Object o) {
547         // You can override field equality logic by defining either of the methods like:
548         // boolean fieldNameEquals(HotwordDetectedResult other) { ... }
549         // boolean fieldNameEquals(FieldType otherValue) { ... }
550 
551         if (this == o) return true;
552         if (o == null || getClass() != o.getClass()) return false;
553         @SuppressWarnings("unchecked")
554         HotwordDetectedResult that = (HotwordDetectedResult) o;
555         //noinspection PointlessBooleanExpression
556         return true
557                 && mConfidenceLevel == that.mConfidenceLevel
558                 && Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
559                 && mHotwordOffsetMillis == that.mHotwordOffsetMillis
560                 && mHotwordDurationMillis == that.mHotwordDurationMillis
561                 && mAudioChannel == that.mAudioChannel
562                 && mHotwordDetectionPersonalized == that.mHotwordDetectionPersonalized
563                 && mScore == that.mScore
564                 && mPersonalizedScore == that.mPersonalizedScore
565                 && mHotwordPhraseId == that.mHotwordPhraseId
566                 && Objects.equals(mExtras, that.mExtras);
567     }
568 
569     @Override
570     @DataClass.Generated.Member
hashCode()571     public int hashCode() {
572         // You can override field hashCode logic by defining methods like:
573         // int fieldNameHashCode() { ... }
574 
575         int _hash = 1;
576         _hash = 31 * _hash + mConfidenceLevel;
577         _hash = 31 * _hash + Objects.hashCode(mMediaSyncEvent);
578         _hash = 31 * _hash + mHotwordOffsetMillis;
579         _hash = 31 * _hash + mHotwordDurationMillis;
580         _hash = 31 * _hash + mAudioChannel;
581         _hash = 31 * _hash + Boolean.hashCode(mHotwordDetectionPersonalized);
582         _hash = 31 * _hash + mScore;
583         _hash = 31 * _hash + mPersonalizedScore;
584         _hash = 31 * _hash + mHotwordPhraseId;
585         _hash = 31 * _hash + Objects.hashCode(mExtras);
586         return _hash;
587     }
588 
589     @Override
590     @DataClass.Generated.Member
writeToParcel(@onNull Parcel dest, int flags)591     public void writeToParcel(@NonNull Parcel dest, int flags) {
592         // You can override field parcelling by defining methods like:
593         // void parcelFieldName(Parcel dest, int flags) { ... }
594 
595         int flg = 0;
596         if (mHotwordDetectionPersonalized) flg |= 0x20;
597         if (mMediaSyncEvent != null) flg |= 0x2;
598         dest.writeInt(flg);
599         dest.writeInt(mConfidenceLevel);
600         if (mMediaSyncEvent != null) dest.writeTypedObject(mMediaSyncEvent, flags);
601         dest.writeInt(mHotwordOffsetMillis);
602         dest.writeInt(mHotwordDurationMillis);
603         dest.writeInt(mAudioChannel);
604         dest.writeInt(mScore);
605         dest.writeInt(mPersonalizedScore);
606         dest.writeInt(mHotwordPhraseId);
607         dest.writeTypedObject(mExtras, flags);
608     }
609 
610     @Override
611     @DataClass.Generated.Member
describeContents()612     public int describeContents() { return 0; }
613 
614     /** @hide */
615     @SuppressWarnings({"unchecked", "RedundantCast"})
616     @DataClass.Generated.Member
HotwordDetectedResult(@onNull Parcel in)617     /* package-private */ HotwordDetectedResult(@NonNull Parcel in) {
618         // You can override field unparcelling by defining methods like:
619         // static FieldType unparcelFieldName(Parcel in) { ... }
620 
621         int flg = in.readInt();
622         boolean hotwordDetectionPersonalized = (flg & 0x20) != 0;
623         int confidenceLevel = in.readInt();
624         MediaSyncEvent mediaSyncEvent = (flg & 0x2) == 0 ? null : (MediaSyncEvent) in.readTypedObject(MediaSyncEvent.CREATOR);
625         int hotwordOffsetMillis = in.readInt();
626         int hotwordDurationMillis = in.readInt();
627         int audioChannel = in.readInt();
628         int score = in.readInt();
629         int personalizedScore = in.readInt();
630         int hotwordPhraseId = in.readInt();
631         PersistableBundle extras = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR);
632 
633         this.mConfidenceLevel = confidenceLevel;
634         com.android.internal.util.AnnotationValidations.validate(
635                 HotwordConfidenceLevelValue.class, null, mConfidenceLevel);
636         this.mMediaSyncEvent = mediaSyncEvent;
637         this.mHotwordOffsetMillis = hotwordOffsetMillis;
638         this.mHotwordDurationMillis = hotwordDurationMillis;
639         this.mAudioChannel = audioChannel;
640         this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
641         this.mScore = score;
642         this.mPersonalizedScore = personalizedScore;
643         this.mHotwordPhraseId = hotwordPhraseId;
644         this.mExtras = extras;
645         com.android.internal.util.AnnotationValidations.validate(
646                 NonNull.class, null, mExtras);
647 
648         onConstructed();
649     }
650 
651     @DataClass.Generated.Member
652     public static final @NonNull Parcelable.Creator<HotwordDetectedResult> CREATOR
653             = new Parcelable.Creator<HotwordDetectedResult>() {
654         @Override
655         public HotwordDetectedResult[] newArray(int size) {
656             return new HotwordDetectedResult[size];
657         }
658 
659         @Override
660         public HotwordDetectedResult createFromParcel(@NonNull Parcel in) {
661             return new HotwordDetectedResult(in);
662         }
663     };
664 
665     /**
666      * A builder for {@link HotwordDetectedResult}
667      */
668     @SuppressWarnings("WeakerAccess")
669     @DataClass.Generated.Member
670     public static final class Builder {
671 
672         private @HotwordConfidenceLevelValue int mConfidenceLevel;
673         private @Nullable MediaSyncEvent mMediaSyncEvent;
674         private int mHotwordOffsetMillis;
675         private int mHotwordDurationMillis;
676         private int mAudioChannel;
677         private boolean mHotwordDetectionPersonalized;
678         private int mScore;
679         private int mPersonalizedScore;
680         private int mHotwordPhraseId;
681         private @NonNull PersistableBundle mExtras;
682 
683         private long mBuilderFieldsSet = 0L;
684 
Builder()685         public Builder() {
686         }
687 
688         /**
689          * Confidence level in the trigger outcome.
690          */
691         @DataClass.Generated.Member
setConfidenceLevel(@otwordConfidenceLevelValue int value)692         public @NonNull Builder setConfidenceLevel(@HotwordConfidenceLevelValue int value) {
693             checkNotUsed();
694             mBuilderFieldsSet |= 0x1;
695             mConfidenceLevel = value;
696             return this;
697         }
698 
699         /**
700          * A {@code MediaSyncEvent} that allows the {@link HotwordDetector} to recapture the audio
701          * that contains the hotword trigger. This must be obtained using
702          * {@link android.media.AudioRecord#shareAudioHistory(String, long)}.
703          */
704         @DataClass.Generated.Member
setMediaSyncEvent(@onNull MediaSyncEvent value)705         public @NonNull Builder setMediaSyncEvent(@NonNull MediaSyncEvent value) {
706             checkNotUsed();
707             mBuilderFieldsSet |= 0x2;
708             mMediaSyncEvent = value;
709             return this;
710         }
711 
712         /**
713          * Offset in milliseconds the audio stream when the trigger event happened (end of hotword
714          * phrase).
715          *
716          * <p>Only value between 0 and 3600000 (inclusive) is accepted.
717          */
718         @DataClass.Generated.Member
setHotwordOffsetMillis(int value)719         public @NonNull Builder setHotwordOffsetMillis(int value) {
720             checkNotUsed();
721             mBuilderFieldsSet |= 0x4;
722             mHotwordOffsetMillis = value;
723             return this;
724         }
725 
726         /**
727          * Duration in milliseconds of the hotword trigger phrase.
728          *
729          * <p>Only values between 0 and {@link android.media.AudioRecord#getMaxSharedAudioHistoryMillis}
730          * (inclusive) are accepted.
731          */
732         @DataClass.Generated.Member
setHotwordDurationMillis(int value)733         public @NonNull Builder setHotwordDurationMillis(int value) {
734             checkNotUsed();
735             mBuilderFieldsSet |= 0x8;
736             mHotwordDurationMillis = value;
737             return this;
738         }
739 
740         /**
741          * Audio channel containing the highest-confidence hotword signal.
742          *
743          * <p>Only value between 0 and 63 (inclusive) is accepted.
744          */
745         @DataClass.Generated.Member
setAudioChannel(int value)746         public @NonNull Builder setAudioChannel(int value) {
747             checkNotUsed();
748             mBuilderFieldsSet |= 0x10;
749             mAudioChannel = value;
750             return this;
751         }
752 
753         /**
754          * Returns whether the trigger has happened due to model having been personalized to fit user's
755          * voice.
756          */
757         @DataClass.Generated.Member
setHotwordDetectionPersonalized(boolean value)758         public @NonNull Builder setHotwordDetectionPersonalized(boolean value) {
759             checkNotUsed();
760             mBuilderFieldsSet |= 0x20;
761             mHotwordDetectionPersonalized = value;
762             return this;
763         }
764 
765         /**
766          * Score for the hotword trigger.
767          *
768          * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
769          */
770         @DataClass.Generated.Member
setScore(int value)771         public @NonNull Builder setScore(int value) {
772             checkNotUsed();
773             mBuilderFieldsSet |= 0x40;
774             mScore = value;
775             return this;
776         }
777 
778         /**
779          * Score for the hotword trigger for device user.
780          *
781          * <p>Only values between 0 and {@link #getMaxScore} (inclusive) are accepted.
782          */
783         @DataClass.Generated.Member
setPersonalizedScore(int value)784         public @NonNull Builder setPersonalizedScore(int value) {
785             checkNotUsed();
786             mBuilderFieldsSet |= 0x80;
787             mPersonalizedScore = value;
788             return this;
789         }
790 
791         /**
792          * An ID representing the keyphrase that triggered the successful detection.
793          *
794          * <p>Only values between 0 and {@link #getMaxHotwordPhraseId()} (inclusive) are accepted.
795          */
796         @DataClass.Generated.Member
setHotwordPhraseId(int value)797         public @NonNull Builder setHotwordPhraseId(int value) {
798             checkNotUsed();
799             mBuilderFieldsSet |= 0x100;
800             mHotwordPhraseId = value;
801             return this;
802         }
803 
804         /**
805          * App-specific extras to support trigger.
806          *
807          * <p>The size of this bundle will be limited to {@link #getMaxBundleSize}. Results will larger
808          * bundles will be rejected.
809          *
810          * <p>Only primitive types are supported in this bundle. Complex types will be removed from the
811          * bundle.
812          *
813          * <p>The use of this method is discouraged, and support for it will be removed in future
814          * versions of Android.
815          *
816          * <p>This is a PersistableBundle so it doesn't allow any remotable objects or other contents
817          * that can be used to communicate with other processes.
818          */
819         @DataClass.Generated.Member
setExtras(@onNull PersistableBundle value)820         public @NonNull Builder setExtras(@NonNull PersistableBundle value) {
821             checkNotUsed();
822             mBuilderFieldsSet |= 0x200;
823             mExtras = value;
824             return this;
825         }
826 
827         /** Builds the instance. This builder should not be touched after calling this! */
build()828         public @NonNull HotwordDetectedResult build() {
829             checkNotUsed();
830             mBuilderFieldsSet |= 0x400; // Mark builder used
831 
832             if ((mBuilderFieldsSet & 0x1) == 0) {
833                 mConfidenceLevel = defaultConfidenceLevel();
834             }
835             if ((mBuilderFieldsSet & 0x2) == 0) {
836                 mMediaSyncEvent = null;
837             }
838             if ((mBuilderFieldsSet & 0x4) == 0) {
839                 mHotwordOffsetMillis = HOTWORD_OFFSET_UNSET;
840             }
841             if ((mBuilderFieldsSet & 0x8) == 0) {
842                 mHotwordDurationMillis = 0;
843             }
844             if ((mBuilderFieldsSet & 0x10) == 0) {
845                 mAudioChannel = AUDIO_CHANNEL_UNSET;
846             }
847             if ((mBuilderFieldsSet & 0x20) == 0) {
848                 mHotwordDetectionPersonalized = false;
849             }
850             if ((mBuilderFieldsSet & 0x40) == 0) {
851                 mScore = defaultScore();
852             }
853             if ((mBuilderFieldsSet & 0x80) == 0) {
854                 mPersonalizedScore = defaultPersonalizedScore();
855             }
856             if ((mBuilderFieldsSet & 0x100) == 0) {
857                 mHotwordPhraseId = defaultHotwordPhraseId();
858             }
859             if ((mBuilderFieldsSet & 0x200) == 0) {
860                 mExtras = defaultExtras();
861             }
862             HotwordDetectedResult o = new HotwordDetectedResult(
863                     mConfidenceLevel,
864                     mMediaSyncEvent,
865                     mHotwordOffsetMillis,
866                     mHotwordDurationMillis,
867                     mAudioChannel,
868                     mHotwordDetectionPersonalized,
869                     mScore,
870                     mPersonalizedScore,
871                     mHotwordPhraseId,
872                     mExtras);
873             return o;
874         }
875 
checkNotUsed()876         private void checkNotUsed() {
877             if ((mBuilderFieldsSet & 0x400) != 0) {
878                 throw new IllegalStateException(
879                         "This Builder should not be reused. Use a new Builder instance instead");
880             }
881         }
882     }
883 
884     @DataClass.Generated(
885             time = 1625541522353L,
886             codegenVersion = "1.0.23",
887             sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
888             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\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)")
889     @Deprecated
__metadata()890     private void __metadata() {}
891 
892 
893     //@formatter:on
894     // End of generated code
895 
896 }
897