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