AudioAttributes.java revision 7b41467704f941b11af6aace3e40993afc7f6c6f
1/* 2 * Copyright (C) 2014 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 17package android.media; 18 19import android.annotation.IntDef; 20import android.os.Parcel; 21import android.os.Parcelable; 22import android.util.Log; 23 24import java.lang.annotation.Retention; 25import java.lang.annotation.RetentionPolicy; 26import java.util.Collections; 27import java.util.HashSet; 28import java.util.Iterator; 29import java.util.Set; 30 31/** 32 * A class to encapsulate a collection of attributes describing information about an audio 33 * player or recorder. 34 */ 35public final class AudioAttributes implements Parcelable { 36 private final static String TAG = "AudioAttributes"; 37 38 /** 39 * Content type value to use when the content type is unknown, or other than the ones defined. 40 */ 41 public final static int CONTENT_TYPE_UNKNOWN = 0; 42 /** 43 * Content type value to use when the content type is speech. 44 */ 45 public final static int CONTENT_TYPE_SPEECH = 1; 46 /** 47 * Content type value to use when the content type is music. 48 */ 49 public final static int CONTENT_TYPE_MUSIC = 2; 50 /** 51 * Content type value to use when the content type is a soundtrack, typically accompanying 52 * a movie or TV program. 53 */ 54 public final static int CONTENT_TYPE_MOVIE = 3; 55 /** 56 * Content type value to use when the content type is a sound used to accompany a user 57 * action, such as a beep or sound effect expressing a key click, or event, such as the 58 * type of a sound for a bonus being received in a game. These sounds are mostly synthesized 59 * or short Foley sounds. 60 */ 61 public final static int CONTENT_TYPE_SONIFICATION = 4; 62 63 /** 64 * Usage value to use when the usage is unknown. 65 */ 66 public final static int USAGE_UNKNOWN = 0; 67 /** 68 * Usage value to use when the usage is media, such as music, or movie 69 * soundtracks. 70 */ 71 public final static int USAGE_MEDIA = 1; 72 /** 73 * Usage value to use when the usage is voice communications, such as telephony 74 * or VoIP. 75 */ 76 public final static int USAGE_VOICE_COMMUNICATION = 2; 77 /** 78 * Usage value to use when the usage is in-call signalling, such as with 79 * a "busy" beep, or DTMF tones. 80 */ 81 public final static int USAGE_VOICE_COMMUNICATION_SIGNALLING = 3; 82 /** 83 * Usage value to use when the usage is an alarm (e.g. wake-up alarm). 84 */ 85 public final static int USAGE_ALARM = 4; 86 /** 87 * Usage value to use when the usage is notification. See other 88 * notification usages for more specialized uses. 89 */ 90 public final static int USAGE_NOTIFICATION = 5; 91 /** 92 * Usage value to use when the usage is telephony ringtone. 93 */ 94 public final static int USAGE_NOTIFICATION_TELEPHONY_RINGTONE = 6; 95 /** 96 * Usage value to use when the usage is a request to enter/end a 97 * communication, such as a VoIP communication or video-conference. 98 */ 99 public final static int USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7; 100 /** 101 * Usage value to use when the usage is notification for an "instant" 102 * communication such as a chat, or SMS. 103 */ 104 public final static int USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8; 105 /** 106 * Usage value to use when the usage is notification for a 107 * non-immediate type of communication such as e-mail. 108 */ 109 public final static int USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9; 110 /** 111 * Usage value to use when the usage is to attract the user's attention, 112 * such as a reminder or low battery warning. 113 */ 114 public final static int USAGE_NOTIFICATION_EVENT = 10; 115 /** 116 * Usage value to use when the usage is for accessibility, such as with 117 * a screen reader. 118 */ 119 public final static int USAGE_ASSISTANCE_ACCESSIBILITY = 11; 120 /** 121 * Usage value to use when the usage is driving or navigation directions. 122 */ 123 public final static int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; 124 /** 125 * Usage value to use when the usage is sonification, such as with user 126 * interface sounds. 127 */ 128 public final static int USAGE_ASSISTANCE_SONIFICATION = 13; 129 /** 130 * Usage value to use when the usage is for game audio. 131 */ 132 public final static int USAGE_GAME = 14; 133 134 /** 135 * Flag defining a behavior where the audibility of the sound will be ensured by the system. 136 */ 137 public final static int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0; 138 /** 139 * @hide 140 * Flag defining a behavior where the playback of the sound is ensured without 141 * degradation only when going to a secure sink. 142 */ 143 // FIXME not guaranteed yet 144 // TODO add OR to getFlags() when supported and in public API 145 public final static int FLAG_SECURE = 0x1 << 1; 146 /** 147 * @hide 148 * Flag to enable when the stream is associated with SCO usage. 149 * Internal use only for dealing with legacy STREAM_BLUETOOTH_SCO 150 */ 151 public final static int FLAG_SCO = 0x1 << 2; 152 153 154 private int mUsage = USAGE_UNKNOWN; 155 private int mContentType = CONTENT_TYPE_UNKNOWN; 156 private int mFlags = 0x0; 157 private HashSet<String> mTags; 158 private String mFormattedTags; 159 160 private AudioAttributes() { 161 } 162 163 /** 164 * Return the content type. 165 * @return one of the values that can be set in {@link Builder#setContentType(int)} 166 */ 167 public int getContentType() { 168 return mContentType; 169 } 170 171 /** 172 * Return the usage. 173 * @return one of the values that can be set in {@link Builder#setUsage(int)} 174 */ 175 public int getUsage() { 176 return mUsage; 177 } 178 179 /** 180 * Return the flags. 181 * @return a combined mask of all flags 182 */ 183 public int getFlags() { 184 // only return the flags that are public 185 return (mFlags & (FLAG_AUDIBILITY_ENFORCED)); 186 } 187 188 /** 189 * @hide 190 * Return all the flags, even the non-public ones. 191 * Internal use only 192 * @return a combined mask of all flags 193 */ 194 public int getAllFlags() { 195 return mFlags; 196 } 197 198 /** 199 * @hide 200 * Return the set of tags. 201 * @return a read-only set of all tags stored as strings. 202 */ 203 public Set<String> getTags() { 204 return Collections.unmodifiableSet(mTags); 205 } 206 207 /** 208 * Builder class for {@link AudioAttributes} objects. 209 */ 210 public static class Builder { 211 private int mUsage = USAGE_UNKNOWN; 212 private int mContentType = CONTENT_TYPE_UNKNOWN; 213 private int mFlags = 0x0; 214 private HashSet<String> mTags = new HashSet<String>(); 215 216 /** 217 * Constructs a new Builder with the defaults. 218 */ 219 public Builder() { 220 } 221 222 /** 223 * Constructs a new Builder from a given AudioAttributes 224 * @param aa the AudioAttributes object whose data will be reused in the new Builder. 225 */ 226 @SuppressWarnings("unchecked") // for cloning of mTags 227 public Builder(AudioAttributes aa) { 228 mUsage = aa.mUsage; 229 mContentType = aa.mContentType; 230 mFlags = aa.mFlags; 231 mTags = (HashSet<String>) aa.mTags.clone(); 232 } 233 234 /** 235 * Combines all of the attributes that have been set and return a new 236 * {@link AudioAttributes} object. 237 * @return a new {@link AudioAttributes} object 238 */ 239 @SuppressWarnings("unchecked") // for cloning of mTags 240 public AudioAttributes build() { 241 AudioAttributes aa = new AudioAttributes(); 242 aa.mContentType = mContentType; 243 aa.mUsage = mUsage; 244 aa.mFlags = mFlags; 245 aa.mTags = (HashSet<String>) mTags.clone(); 246 final Iterator<String> tagIterator = mTags.iterator(); 247 String allTagsInOne = new String(); 248 while (tagIterator.hasNext()) { 249 allTagsInOne += tagIterator.next() + ";"; 250 } 251 aa.mFormattedTags = allTagsInOne; 252 return aa; 253 } 254 255 /** 256 * Sets the attribute describing what is the intended use of the the audio signal, 257 * such as alarm or ringtone. 258 * @param usage one of {@link AudioAttributes#USAGE_UNKNOWN}, 259 * {@link AudioAttributes#USAGE_MEDIA}, 260 * {@link AudioAttributes#USAGE_VOICE_COMMUNICATION}, 261 * {@link AudioAttributes#USAGE_VOICE_COMMUNICATION_SIGNALLING}, 262 * {@link AudioAttributes#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION}, 263 * {@link AudioAttributes#USAGE_NOTIFICATION_TELEPHONY_RINGTONE}, 264 * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_REQUEST}, 265 * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_INSTANT}, 266 * {@link AudioAttributes#USAGE_NOTIFICATION_COMMUNICATION_DELAYED}, 267 * {@link AudioAttributes#USAGE_NOTIFICATION_EVENT}, 268 * {@link AudioAttributes#USAGE_ASSISTANCE_ACCESSIBILITY}, 269 * {@link AudioAttributes#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE}, 270 * {@link AudioAttributes#USAGE_ASSISTANCE_SONIFICATION}, 271 * {@link AudioAttributes#USAGE_GAME}. 272 * @return the same Builder instance. 273 */ 274 public Builder setUsage(@AttributeUsage int usage) { 275 switch (usage) { 276 case USAGE_UNKNOWN: 277 case USAGE_MEDIA: 278 case USAGE_VOICE_COMMUNICATION: 279 case USAGE_VOICE_COMMUNICATION_SIGNALLING: 280 case USAGE_ALARM: 281 case USAGE_NOTIFICATION: 282 case USAGE_NOTIFICATION_TELEPHONY_RINGTONE: 283 case USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 284 case USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 285 case USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 286 case USAGE_NOTIFICATION_EVENT: 287 case USAGE_ASSISTANCE_ACCESSIBILITY: 288 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 289 case USAGE_ASSISTANCE_SONIFICATION: 290 case USAGE_GAME: 291 mUsage = usage; 292 break; 293 default: 294 mUsage = USAGE_UNKNOWN; 295 } 296 return this; 297 } 298 299 /** 300 * Sets the attribute describing the content type of the audio signal, such as speech, 301 * or music. 302 * @param contentType the content type values, one of 303 * {@link AudioAttributes#CONTENT_TYPE_MOVIE}, 304 * {@link AudioAttributes#CONTENT_TYPE_MUSIC}, 305 * {@link AudioAttributes#CONTENT_TYPE_SONIFICATION}, 306 * {@link AudioAttributes#CONTENT_TYPE_SPEECH}, 307 * {@link AudioAttributes#CONTENT_TYPE_UNKNOWN}. 308 * @return the same Builder instance. 309 */ 310 public Builder setContentType(@AttributeContentType int contentType) { 311 switch (contentType) { 312 case CONTENT_TYPE_UNKNOWN: 313 case CONTENT_TYPE_MOVIE: 314 case CONTENT_TYPE_MUSIC: 315 case CONTENT_TYPE_SONIFICATION: 316 case CONTENT_TYPE_SPEECH: 317 mContentType = contentType; 318 break; 319 default: 320 mUsage = CONTENT_TYPE_UNKNOWN; 321 } 322 return this; 323 } 324 325 /** 326 * Sets the combination of flags. 327 * @param flags the {@link AudioAttributes#FLAG_AUDIBILITY_ENFORCED} flag. 328 * @return the same Builder instance. 329 */ 330 public Builder setFlags(int flags) { 331 flags &= (AudioAttributes.FLAG_AUDIBILITY_ENFORCED | AudioAttributes.FLAG_SCO 332 | AudioAttributes.FLAG_SECURE); 333 mFlags |= flags; 334 return this; 335 } 336 337 /** 338 * @hide 339 * Add a custom tag stored as a string 340 * @param tag 341 * @return the same Builder instance. 342 */ 343 public Builder addTag(String tag) { 344 mTags.add(tag); 345 return this; 346 } 347 348 /** 349 * Adds attributes inferred from the legacy stream types. 350 * @param streamType one of {@link AudioManager#STREAM_VOICE_CALL}, 351 * {@link AudioManager#STREAM_SYSTEM}, {@link AudioManager#STREAM_RING}, 352 * {@link AudioManager#STREAM_MUSIC}, {@link AudioManager#STREAM_ALARM}, 353 * or {@link AudioManager#STREAM_NOTIFICATION}. 354 * @return the same Builder instance. 355 */ 356 public Builder setLegacyStreamType(int streamType) { 357 return setInternalLegacyStreamType(streamType); 358 } 359 360 /** 361 * @hide 362 * For internal framework use only, enables building from hidden stream types. 363 * @param streamType 364 * @return the same Builder instance. 365 */ 366 public Builder setInternalLegacyStreamType(int streamType) { 367 switch(streamType) { 368 case AudioSystem.STREAM_VOICE_CALL: 369 mContentType = CONTENT_TYPE_SPEECH; 370 break; 371 case AudioSystem.STREAM_SYSTEM_ENFORCED: 372 mFlags |= FLAG_AUDIBILITY_ENFORCED; 373 // intended fall through, attributes in common with STREAM_SYSTEM 374 case AudioSystem.STREAM_SYSTEM: 375 mContentType = CONTENT_TYPE_SONIFICATION; 376 break; 377 case AudioSystem.STREAM_RING: 378 mContentType = CONTENT_TYPE_SONIFICATION; 379 break; 380 case AudioSystem.STREAM_MUSIC: 381 mContentType = CONTENT_TYPE_MUSIC; 382 break; 383 case AudioSystem.STREAM_ALARM: 384 mContentType = CONTENT_TYPE_SONIFICATION; 385 break; 386 case AudioSystem.STREAM_NOTIFICATION: 387 mContentType = CONTENT_TYPE_SONIFICATION; 388 break; 389 case AudioSystem.STREAM_BLUETOOTH_SCO: 390 mContentType = CONTENT_TYPE_SPEECH; 391 mFlags |= FLAG_SCO; 392 break; 393 case AudioSystem.STREAM_DTMF: 394 mContentType = CONTENT_TYPE_SONIFICATION; 395 break; 396 case AudioSystem.STREAM_TTS: 397 mContentType = CONTENT_TYPE_SPEECH; 398 break; 399 default: 400 Log.e(TAG, "Invalid stream type " + streamType + " in for AudioAttributes"); 401 } 402 mUsage = usageForLegacyStreamType(streamType); 403 return this; 404 } 405 }; 406 407 @Override 408 public int describeContents() { 409 return 0; 410 } 411 412 /** 413 * @hide 414 * Used to indicate that when parcelling, the tags should be parcelled through the flattened 415 * formatted string, not through the array of strings. 416 * Keep in sync with frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp 417 * see definition of kAudioAttributesMarshallTagFlattenTags 418 */ 419 public final static int FLATTEN_TAGS = 0x1; 420 /** 421 * When adding tags for writeToParcel(Parcel, int), add them in the list of flags (| NEW_FLAG) 422 */ 423 private final static int ALL_PARCEL_FLAGS = FLATTEN_TAGS; 424 @Override 425 public void writeToParcel(Parcel dest, int flags) { 426 dest.writeInt(mUsage); 427 dest.writeInt(mContentType); 428 dest.writeInt(mFlags); 429 dest.writeInt(flags & ALL_PARCEL_FLAGS); 430 if ((flags & FLATTEN_TAGS) == 0) { 431 String[] tagsArray = new String[mTags.size()]; 432 mTags.toArray(tagsArray); 433 dest.writeStringArray(tagsArray); 434 } else if ((flags & FLATTEN_TAGS) == FLATTEN_TAGS) { 435 dest.writeString(mFormattedTags); 436 } 437 } 438 439 private AudioAttributes(Parcel in) { 440 mUsage = in.readInt(); 441 mContentType = in.readInt(); 442 mFlags = in.readInt(); 443 boolean hasFlattenedTags = ((in.readInt() & FLATTEN_TAGS) == FLATTEN_TAGS); 444 mTags = new HashSet<String>(); 445 if (hasFlattenedTags) { 446 mTags.add(in.readString()); 447 } else { 448 String[] tagsArray = in.readStringArray(); 449 for (int i = tagsArray.length - 1 ; i >= 0 ; i--) { 450 mTags.add(tagsArray[i]); 451 } 452 } 453 } 454 455 /** @hide */ 456 public static final Parcelable.Creator<AudioAttributes> CREATOR 457 = new Parcelable.Creator<AudioAttributes>() { 458 /** 459 * Rebuilds an AudioAttributes previously stored with writeToParcel(). 460 * @param p Parcel object to read the AudioAttributes from 461 * @return a new AudioAttributes created from the data in the parcel 462 */ 463 public AudioAttributes createFromParcel(Parcel p) { 464 return new AudioAttributes(p); 465 } 466 public AudioAttributes[] newArray(int size) { 467 return new AudioAttributes[size]; 468 } 469 }; 470 471 /** @hide */ 472 @Override 473 public String toString () { 474 return new String("AudioAttributes:" 475 + " usage=" + mUsage 476 + " content=" + mContentType 477 + " flags=0x" + Integer.toHexString(mFlags).toUpperCase() 478 + " tags=" + mTags); 479 } 480 481 /** @hide */ 482 public String usageToString() { 483 return usageToString(mUsage); 484 } 485 486 /** @hide */ 487 public static String usageToString(int usage) { 488 switch(usage) { 489 case USAGE_UNKNOWN: 490 return new String("USAGE_UNKNOWN"); 491 case USAGE_MEDIA: 492 return new String("USAGE_MEDIA"); 493 case USAGE_VOICE_COMMUNICATION: 494 return new String("USAGE_VOICE_COMMUNICATION"); 495 case USAGE_VOICE_COMMUNICATION_SIGNALLING: 496 return new String("USAGE_VOICE_COMMUNICATION"); 497 case USAGE_ALARM: 498 return new String("USAGE_ALARM"); 499 case USAGE_NOTIFICATION: 500 return new String("USAGE_NOTIFICATION"); 501 case USAGE_NOTIFICATION_TELEPHONY_RINGTONE: 502 return new String("USAGE_NOTIFICATION"); 503 case USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 504 return new String("USAGE_NOTIFICATION"); 505 case USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 506 return new String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT"); 507 case USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 508 return new String("USAGE_NOTIFICATION_COMMUNICATION_DELAYED"); 509 case USAGE_NOTIFICATION_EVENT: 510 return new String("USAGE_NOTIFICATION_EVENT"); 511 case USAGE_ASSISTANCE_ACCESSIBILITY: 512 return new String("USAGE_ASSISTANCE_ACCESSIBILITY"); 513 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 514 return new String("USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"); 515 case USAGE_ASSISTANCE_SONIFICATION: 516 return new String("USAGE_ASSISTANCE_SONIFICATION"); 517 case USAGE_GAME: 518 return new String("USAGE_GAME"); 519 default: 520 return new String("unknown usage " + usage); 521 } 522 } 523 524 /** @hide */ 525 public static int usageForLegacyStreamType(int streamType) { 526 switch(streamType) { 527 case AudioSystem.STREAM_VOICE_CALL: 528 return USAGE_VOICE_COMMUNICATION; 529 case AudioSystem.STREAM_SYSTEM_ENFORCED: 530 case AudioSystem.STREAM_SYSTEM: 531 return USAGE_ASSISTANCE_SONIFICATION; 532 case AudioSystem.STREAM_RING: 533 return USAGE_NOTIFICATION_TELEPHONY_RINGTONE; 534 case AudioSystem.STREAM_MUSIC: 535 return USAGE_MEDIA; 536 case AudioSystem.STREAM_ALARM: 537 return USAGE_ALARM; 538 case AudioSystem.STREAM_NOTIFICATION: 539 return USAGE_NOTIFICATION; 540 case AudioSystem.STREAM_BLUETOOTH_SCO: 541 return USAGE_VOICE_COMMUNICATION; 542 case AudioSystem.STREAM_DTMF: 543 return USAGE_VOICE_COMMUNICATION_SIGNALLING; 544 case AudioSystem.STREAM_TTS: 545 return USAGE_ASSISTANCE_ACCESSIBILITY; 546 default: 547 return USAGE_UNKNOWN; 548 } 549 } 550 551 /** @hide */ 552 public static int toLegacyStreamType(AudioAttributes aa) { 553 // flags to stream type mapping 554 if ((aa.getFlags() & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) { 555 return AudioSystem.STREAM_SYSTEM_ENFORCED; 556 } 557 if ((aa.getFlags() & FLAG_SCO) == FLAG_SCO) { 558 return AudioSystem.STREAM_BLUETOOTH_SCO; 559 } 560 561 // usage to stream type mapping 562 switch (aa.getUsage()) { 563 case USAGE_MEDIA: 564 case USAGE_GAME: 565 case USAGE_ASSISTANCE_ACCESSIBILITY: 566 case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 567 return AudioSystem.STREAM_MUSIC; 568 case USAGE_ASSISTANCE_SONIFICATION: 569 return AudioSystem.STREAM_SYSTEM; 570 case USAGE_VOICE_COMMUNICATION: 571 return AudioSystem.STREAM_VOICE_CALL; 572 case USAGE_VOICE_COMMUNICATION_SIGNALLING: 573 return AudioSystem.STREAM_DTMF; 574 case USAGE_ALARM: 575 return AudioSystem.STREAM_ALARM; 576 case USAGE_NOTIFICATION_TELEPHONY_RINGTONE: 577 return AudioSystem.STREAM_RING; 578 case USAGE_NOTIFICATION: 579 case USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 580 case USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 581 case USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 582 case USAGE_NOTIFICATION_EVENT: 583 return AudioSystem.STREAM_NOTIFICATION; 584 case USAGE_UNKNOWN: 585 default: 586 return AudioSystem.STREAM_MUSIC; 587 } 588 } 589 590 /** @hide */ 591 @IntDef({ 592 USAGE_UNKNOWN, 593 USAGE_MEDIA, 594 USAGE_VOICE_COMMUNICATION, 595 USAGE_VOICE_COMMUNICATION_SIGNALLING, 596 USAGE_ALARM, 597 USAGE_NOTIFICATION, 598 USAGE_NOTIFICATION_TELEPHONY_RINGTONE, 599 USAGE_NOTIFICATION_COMMUNICATION_REQUEST, 600 USAGE_NOTIFICATION_COMMUNICATION_INSTANT, 601 USAGE_NOTIFICATION_COMMUNICATION_DELAYED, 602 USAGE_NOTIFICATION_EVENT, 603 USAGE_ASSISTANCE_ACCESSIBILITY, 604 USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, 605 USAGE_ASSISTANCE_SONIFICATION, 606 USAGE_GAME 607 }) 608 @Retention(RetentionPolicy.SOURCE) 609 public @interface AttributeUsage {} 610 611 /** @hide */ 612 @IntDef({ 613 CONTENT_TYPE_UNKNOWN, 614 CONTENT_TYPE_SPEECH, 615 CONTENT_TYPE_MUSIC, 616 CONTENT_TYPE_MOVIE, 617 CONTENT_TYPE_SONIFICATION 618 }) 619 @Retention(RetentionPolicy.SOURCE) 620 public @interface AttributeContentType {} 621} 622