public class

AudioAttributesCompat

extends java.lang.Object

implements VersionedParcelable

 java.lang.Object

↳androidx.media.AudioAttributesCompat

Gradle dependencies

compile group: 'androidx.media', name: 'media', version: '1.6.0'

  • groupId: androidx.media
  • artifactId: media
  • version: 1.6.0

Artifact androidx.media:media:1.6.0 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.media:media com.android.support:support-media-compat

Androidx class mapping:

androidx.media.AudioAttributesCompat android.support.v4.media.AudioAttributesCompat

Overview

A class to encapsulate a collection of attributes describing information about an audio stream.

AudioAttributesCompat supersede the notion of stream types (see for instance AudioManager or AudioManager) for defining the behavior of audio playback. Attributes allow an application to specify more information than is conveyed in a stream type by allowing the application to define:

  • usage: "why" you are playing a sound, what is this sound used for. This is achieved with the "usage" information. Examples of usage are AudioAttributesCompat.USAGE_MEDIA and AudioAttributesCompat.USAGE_ALARM. These two examples are the closest to stream types, but more detailed use cases are available. Usage information is more expressive than a stream type, and allows certain platforms or routing policies to use this information for more refined volume or routing decisions. Usage is the most important information to supply in AudioAttributesCompat and it is recommended to build any instance with this information supplied, see AudioAttributesCompat.Builder for exceptions.
  • content type: "what" you are playing. The content type expresses the general category of the content. This information is optional. But in case it is known (for instance AudioAttributesCompat.CONTENT_TYPE_MOVIE for a movie streaming service or AudioAttributesCompat.CONTENT_TYPE_MUSIC for a music playback application) this information might be used by the audio framework to selectively configure some audio post-processing blocks.
  • flags: "how" is playback to be affected, see the flag definitions for the specific playback behaviors they control.

AudioAttributesCompat instance is built through its builder, AudioAttributesCompat.Builder. Also see android.media.AudioAttributes for the framework implementation of this class.

Summary

Fields
public static final intCONTENT_TYPE_MOVIE

Content type value to use when the content type is a soundtrack, typically accompanying a movie or TV program.

public static final intCONTENT_TYPE_MUSIC

Content type value to use when the content type is music.

public static final intCONTENT_TYPE_SONIFICATION

Content type value to use when the content type is a sound used to accompany a user action, such as a beep or sound effect expressing a key click, or event, such as the type of a sound for a bonus being received in a game.

public static final intCONTENT_TYPE_SPEECH

Content type value to use when the content type is speech.

public static final intCONTENT_TYPE_UNKNOWN

Content type value to use when the content type is unknown, or other than the ones defined.

public static final intFLAG_AUDIBILITY_ENFORCED

Flag defining a behavior where the audibility of the sound will be ensured by the system.

public static final intFLAG_HW_AV_SYNC

Flag requesting the use of an output stream supporting hardware A/V synchronization.

public AudioAttributesImplmImpl

public static final intUSAGE_ALARM

Usage value to use when the usage is an alarm (e.g.

public static final intUSAGE_ASSISTANCE_ACCESSIBILITY

Usage value to use when the usage is for accessibility, such as with a screen reader.

public static final intUSAGE_ASSISTANCE_NAVIGATION_GUIDANCE

Usage value to use when the usage is driving or navigation directions.

public static final intUSAGE_ASSISTANCE_SONIFICATION

Usage value to use when the usage is sonification, such as with user interface sounds.

public static final intUSAGE_ASSISTANT

Usage value to use for audio responses to user queries, audio instructions or help utterances.

public static final intUSAGE_GAME

Usage value to use when the usage is for game audio.

public static final intUSAGE_MEDIA

Usage value to use when the usage is media, such as music, or movie soundtracks.

public static final intUSAGE_NOTIFICATION

Usage value to use when the usage is notification.

public static final intUSAGE_NOTIFICATION_COMMUNICATION_DELAYED

Usage value to use when the usage is notification for a non-immediate type of communication such as e-mail.

public static final intUSAGE_NOTIFICATION_COMMUNICATION_INSTANT

Usage value to use when the usage is notification for an "instant" communication such as a chat, or SMS.

public static final intUSAGE_NOTIFICATION_COMMUNICATION_REQUEST

Usage value to use when the usage is a request to enter/end a communication, such as a VoIP communication or video-conference.

public static final intUSAGE_NOTIFICATION_EVENT

Usage value to use when the usage is to attract the user's attention, such as a reminder or low battery warning.

public static final intUSAGE_NOTIFICATION_RINGTONE

Usage value to use when the usage is telephony ringtone.

public static final intUSAGE_UNKNOWN

Usage value to use when the usage is unknown.

public static final intUSAGE_VOICE_COMMUNICATION

Usage value to use when the usage is voice communications, such as telephony or VoIP.

public static final intUSAGE_VOICE_COMMUNICATION_SIGNALLING

Usage value to use when the usage is in-call signalling, such as with a "busy" beep, or DTMF tones.

Constructors
publicAudioAttributesCompat()

Methods
public booleanequals(java.lang.Object o)

public intgetContentType()

Returns the content type.

public intgetFlags()

Returns the flags.

public intgetLegacyStreamType()

Returns a stream type passed to AudioAttributesCompat.Builder.setLegacyStreamType(int), or best guessing from flags and usage, or -1 if there is no converting logic in framework side (API 21+).

public intgetUsage()

Returns the usage.

public intgetVolumeControlStream()

Returns the stream type matching the given attributes for volume control.

public inthashCode()

public static voidsetForceLegacyBehavior(boolean force)

Prevent AudioAttributes from being used even on platforms that support it.

public java.lang.StringtoString()

public java.lang.Objectunwrap()

If the current SDK level is 21 or higher, return the AudioAttributes object inside this AudioAttributesCompat.

public static AudioAttributesCompatwrap(java.lang.Object aa)

Creates an AudioAttributesCompat given an API 21 AudioAttributes object.

from java.lang.Objectclone, finalize, getClass, notify, notifyAll, wait, wait, wait

Fields

public static final int CONTENT_TYPE_UNKNOWN

Content type value to use when the content type is unknown, or other than the ones defined.

public static final int CONTENT_TYPE_SPEECH

Content type value to use when the content type is speech.

public static final int CONTENT_TYPE_MUSIC

Content type value to use when the content type is music.

public static final int CONTENT_TYPE_MOVIE

Content type value to use when the content type is a soundtrack, typically accompanying a movie or TV program.

public static final int CONTENT_TYPE_SONIFICATION

Content type value to use when the content type is a sound used to accompany a user action, such as a beep or sound effect expressing a key click, or event, such as the type of a sound for a bonus being received in a game. These sounds are mostly synthesized or short Foley sounds.

public static final int USAGE_UNKNOWN

Usage value to use when the usage is unknown.

public static final int USAGE_MEDIA

Usage value to use when the usage is media, such as music, or movie soundtracks.

public static final int USAGE_VOICE_COMMUNICATION

Usage value to use when the usage is voice communications, such as telephony or VoIP.

public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING

Usage value to use when the usage is in-call signalling, such as with a "busy" beep, or DTMF tones.

public static final int USAGE_ALARM

Usage value to use when the usage is an alarm (e.g. wake-up alarm).

public static final int USAGE_NOTIFICATION

Usage value to use when the usage is notification. See other notification usages for more specialized uses.

public static final int USAGE_NOTIFICATION_RINGTONE

Usage value to use when the usage is telephony ringtone.

public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST

Usage value to use when the usage is a request to enter/end a communication, such as a VoIP communication or video-conference.

public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT

Usage value to use when the usage is notification for an "instant" communication such as a chat, or SMS.

public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED

Usage value to use when the usage is notification for a non-immediate type of communication such as e-mail.

public static final int USAGE_NOTIFICATION_EVENT

Usage value to use when the usage is to attract the user's attention, such as a reminder or low battery warning.

public static final int USAGE_ASSISTANCE_ACCESSIBILITY

Usage value to use when the usage is for accessibility, such as with a screen reader.

public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE

Usage value to use when the usage is driving or navigation directions.

public static final int USAGE_ASSISTANCE_SONIFICATION

Usage value to use when the usage is sonification, such as with user interface sounds.

public static final int USAGE_GAME

Usage value to use when the usage is for game audio.

public static final int USAGE_ASSISTANT

Usage value to use for audio responses to user queries, audio instructions or help utterances.

public static final int FLAG_AUDIBILITY_ENFORCED

Flag defining a behavior where the audibility of the sound will be ensured by the system.

public static final int FLAG_HW_AV_SYNC

Flag requesting the use of an output stream supporting hardware A/V synchronization.

public AudioAttributesImpl mImpl

Constructors

public AudioAttributesCompat()

Methods

public int getVolumeControlStream()

Returns the stream type matching the given attributes for volume control. Use this method to derive the stream type needed to configure the volume control slider in an with .
Do not use this method to set the stream type on an audio player object (e.g. , android.media.MediaPlayer) as this is deprecated; use AudioAttributes instead.

Returns:

a valid stream type for Activity or stream volume control that matches the attributes, or AudioManager if there isn't a direct match. Note that USE_DEFAULT_STREAM_TYPE is not a valid value for AudioManager.

public java.lang.Object unwrap()

If the current SDK level is 21 or higher, return the AudioAttributes object inside this AudioAttributesCompat. Otherwise null.

Returns:

the underlying AudioAttributes object or null

public int getLegacyStreamType()

Returns a stream type passed to AudioAttributesCompat.Builder.setLegacyStreamType(int), or best guessing from flags and usage, or -1 if there is no converting logic in framework side (API 21+).

Returns:

the stream type AudioManager

public static AudioAttributesCompat wrap(java.lang.Object aa)

Creates an AudioAttributesCompat given an API 21 AudioAttributes object.

Parameters:

aa: an instance of AudioAttributes.

Returns:

the new AudioAttributesCompat, or null on API < 21

public int getContentType()

Returns the content type.

Returns:

one of the values that can be set in AudioAttributesCompat.Builder.setContentType(int)

public int getUsage()

Returns the usage.

Returns:

one of the values that can be set in AudioAttributesCompat.Builder.setUsage(int)

public int getFlags()

Returns the flags.

Returns:

a combined mask of all flags

public int hashCode()

public java.lang.String toString()

public static void setForceLegacyBehavior(boolean force)

Prevent AudioAttributes from being used even on platforms that support it.

public boolean equals(java.lang.Object o)

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.media;

import static androidx.annotation.RestrictTo.Scope.LIBRARY;

import android.media.AudioAttributes;
import android.media.AudioManager;
import android.os.Build;
import android.util.SparseIntArray;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.versionedparcelable.ParcelField;
import androidx.versionedparcelable.VersionedParcelable;
import androidx.versionedparcelable.VersionedParcelize;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * A class to encapsulate a collection of attributes describing information about an audio stream.
 *
 * <p><code>AudioAttributesCompat</code> supersede the notion of stream types (see for instance
 * {@link AudioManager#STREAM_MUSIC} or {@link AudioManager#STREAM_ALARM}) for defining the behavior
 * of audio playback. Attributes allow an application to specify more information than is conveyed
 * in a stream type by allowing the application to define:
 *
 * <ul>
 * <li>usage: "why" you are playing a sound, what is this sound used for. This is achieved with
 * the "usage" information. Examples of usage are {@link #USAGE_MEDIA} and {@link
 * #USAGE_ALARM}. These two examples are the closest to stream types, but more detailed use
 * cases are available. Usage information is more expressive than a stream type, and allows
 * certain platforms or routing policies to use this information for more refined volume or
 * routing decisions. Usage is the most important information to supply in <code>
 * AudioAttributesCompat</code> and it is recommended to build any instance with this
 * information supplied, see {@link AudioAttributesCompat.Builder} for exceptions.
 * <li>content type: "what" you are playing. The content type expresses the general category of
 * the content. This information is optional. But in case it is known (for instance {@link
 * #CONTENT_TYPE_MOVIE} for a movie streaming service or {@link #CONTENT_TYPE_MUSIC} for a
 * music playback application) this information might be used by the audio framework to
 * selectively configure some audio post-processing blocks.
 * <li>flags: "how" is playback to be affected, see the flag definitions for the specific playback
 * behaviors they control.
 * </ul>
 *
 * <p><code>AudioAttributesCompat</code> instance is built through its builder, {@link
 * AudioAttributesCompat.Builder}. Also see {@link android.media.AudioAttributes} for the framework
 * implementation of this class.
 */
@VersionedParcelize(jetifyAs = "android.support.v4.media.AudioAttributesCompat")
public class AudioAttributesCompat implements VersionedParcelable {
    static final String TAG = "AudioAttributesCompat";

    /**
     * Content type value to use when the content type is unknown, or other than the ones defined.
     */
    public static final int CONTENT_TYPE_UNKNOWN = AudioAttributes.CONTENT_TYPE_UNKNOWN;
    /** Content type value to use when the content type is speech. */
    public static final int CONTENT_TYPE_SPEECH = AudioAttributes.CONTENT_TYPE_SPEECH;
    /** Content type value to use when the content type is music. */
    public static final int CONTENT_TYPE_MUSIC = AudioAttributes.CONTENT_TYPE_MUSIC;
    /**
     * Content type value to use when the content type is a soundtrack, typically accompanying a
     * movie or TV program.
     */
    public static final int CONTENT_TYPE_MOVIE = AudioAttributes.CONTENT_TYPE_MOVIE;
    /**
     * Content type value to use when the content type is a sound used to accompany a user action,
     * such as a beep or sound effect expressing a key click, or event, such as the type of a sound
     * for a bonus being received in a game. These sounds are mostly synthesized or short Foley
     * sounds.
     */
    public static final int CONTENT_TYPE_SONIFICATION = AudioAttributes.CONTENT_TYPE_SONIFICATION;

    /** Usage value to use when the usage is unknown. */
    public static final int USAGE_UNKNOWN = AudioAttributes.USAGE_UNKNOWN;
    /** Usage value to use when the usage is media, such as music, or movie soundtracks. */
    public static final int USAGE_MEDIA = AudioAttributes.USAGE_MEDIA;
    /** Usage value to use when the usage is voice communications, such as telephony or VoIP. */
    public static final int USAGE_VOICE_COMMUNICATION = AudioAttributes.USAGE_VOICE_COMMUNICATION;
    /**
     * Usage value to use when the usage is in-call signalling, such as with a "busy" beep, or DTMF
     * tones.
     */
    public static final int USAGE_VOICE_COMMUNICATION_SIGNALLING =
             AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING;
    /** Usage value to use when the usage is an alarm (e.g. wake-up alarm). */
    public static final int USAGE_ALARM = AudioAttributes.USAGE_ALARM;
    /**
     * Usage value to use when the usage is notification. See other notification usages for more
     * specialized uses.
     */
    public static final int USAGE_NOTIFICATION = AudioAttributes.USAGE_NOTIFICATION;
    /** Usage value to use when the usage is telephony ringtone. */
    public static final int USAGE_NOTIFICATION_RINGTONE =
             AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
    /**
     * Usage value to use when the usage is a request to enter/end a communication, such as a VoIP
     * communication or video-conference.
     */
    public static final int USAGE_NOTIFICATION_COMMUNICATION_REQUEST =
             AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
    /**
     * Usage value to use when the usage is notification for an "instant" communication such as a
     * chat, or SMS.
     */
    public static final int USAGE_NOTIFICATION_COMMUNICATION_INSTANT =
             AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
    /**
     * Usage value to use when the usage is notification for a non-immediate type of communication
     * such as e-mail.
     */
    public static final int USAGE_NOTIFICATION_COMMUNICATION_DELAYED =
             AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
    /**
     * Usage value to use when the usage is to attract the user's attention, such as a reminder or
     * low battery warning.
     */
    public static final int USAGE_NOTIFICATION_EVENT = AudioAttributes.USAGE_NOTIFICATION_EVENT;
    /** Usage value to use when the usage is for accessibility, such as with a screen reader. */
    public static final int USAGE_ASSISTANCE_ACCESSIBILITY =
             AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
    /** Usage value to use when the usage is driving or navigation directions. */
    public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE =
             AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
    /** Usage value to use when the usage is sonification, such as with user interface sounds. */
    public static final int USAGE_ASSISTANCE_SONIFICATION =
             AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
    /** Usage value to use when the usage is for game audio. */
    public static final int USAGE_GAME = AudioAttributes.USAGE_GAME;

    // usage not available to clients
    static final int USAGE_VIRTUAL_SOURCE = 15; // AudioAttributes.USAGE_VIRTUAL_SOURCE;
    /**
     * Usage value to use for audio responses to user queries, audio instructions or help
     * utterances.
     */
    public static final int USAGE_ASSISTANT = AudioAttributes.USAGE_ASSISTANT;

    /**
     * IMPORTANT: when adding new usage types, add them to SDK_USAGES and update SUPPRESSIBLE_USAGES
     * if applicable.
     */

    // private API
    private static final int SUPPRESSIBLE_NOTIFICATION = 1;

    private static final int SUPPRESSIBLE_CALL = 2;
    private static final SparseIntArray SUPPRESSIBLE_USAGES;

    // used by tests
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    static boolean sForceLegacyBehavior;

    static {
        SUPPRESSIBLE_USAGES = new SparseIntArray();
        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION, SUPPRESSIBLE_NOTIFICATION);
        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_RINGTONE, SUPPRESSIBLE_CALL);
        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_COMMUNICATION_REQUEST, SUPPRESSIBLE_CALL);
        SUPPRESSIBLE_USAGES.put(
                USAGE_NOTIFICATION_COMMUNICATION_INSTANT, SUPPRESSIBLE_NOTIFICATION);
        SUPPRESSIBLE_USAGES.put(
                USAGE_NOTIFICATION_COMMUNICATION_DELAYED, SUPPRESSIBLE_NOTIFICATION);
        SUPPRESSIBLE_USAGES.put(USAGE_NOTIFICATION_EVENT, SUPPRESSIBLE_NOTIFICATION);
    }

    @SuppressWarnings("unused")
    private static final int[] SDK_USAGES = {
            USAGE_UNKNOWN,
            USAGE_MEDIA,
            USAGE_VOICE_COMMUNICATION,
            USAGE_VOICE_COMMUNICATION_SIGNALLING,
            USAGE_ALARM,
            USAGE_NOTIFICATION,
            USAGE_NOTIFICATION_RINGTONE,
            USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
            USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
            USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
            USAGE_NOTIFICATION_EVENT,
            USAGE_ASSISTANCE_ACCESSIBILITY,
            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
            USAGE_ASSISTANCE_SONIFICATION,
            USAGE_GAME,
            USAGE_ASSISTANT,
    };

    /** Flag defining a behavior where the audibility of the sound will be ensured by the system. */
    public static final int FLAG_AUDIBILITY_ENFORCED = 0x1 << 0;

    // flags for @hide API so we can create a proper flags mask
    static final int FLAG_SECURE = 0x1 << 1;
    static final int FLAG_SCO = 0x1 << 2;
    static final int FLAG_BEACON = 0x1 << 3;

    /** Flag requesting the use of an output stream supporting hardware A/V synchronization. */
    public static final int FLAG_HW_AV_SYNC = 0x1 << 4;

    // more @hide flags
    static final int FLAG_HW_HOTWORD = 0x1 << 5;
    static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
    static final int FLAG_BYPASS_MUTE = 0x1 << 7;
    static final int FLAG_LOW_LATENCY = 0x1 << 8;
    static final int FLAG_DEEP_BUFFER = 0x1 << 9;

    static final int FLAG_ALL =
            (FLAG_AUDIBILITY_ENFORCED
                    | FLAG_SECURE
                    | FLAG_SCO
                    | FLAG_BEACON
                    | FLAG_HW_AV_SYNC
                    | FLAG_HW_HOTWORD
                    | FLAG_BYPASS_INTERRUPTION_POLICY
                    | FLAG_BYPASS_MUTE
                    | FLAG_LOW_LATENCY
                    | FLAG_DEEP_BUFFER);
    static final int FLAG_ALL_PUBLIC =
            (FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY);

    static final int INVALID_STREAM_TYPE = -1;  // AudioSystem.STREAM_DEFAULT

    /** @hide */
    // It should be public to allow Parcelizers which never be de/jetified can access the field.
    @RestrictTo(LIBRARY)
    @ParcelField(1)
    public AudioAttributesImpl mImpl;

    // WARNING: Adding a new ParcelField may break old library users (b/152830728)

    /** @hide */
    // It should be public to allow Parcelizers which never be de/jetified can access the
    // constructor.
    @RestrictTo(LIBRARY)
    public AudioAttributesCompat() {
    }

    AudioAttributesCompat(AudioAttributesImpl impl) {
        mImpl = impl;
    }

    /**
     * Returns the stream type matching the given attributes for volume control. Use this method to
     * derive the stream type needed to configure the volume control slider in an {@link
     * android.app.Activity} with {@link android.app.Activity#setVolumeControlStream(int)}. <br>
     * Do not use this method to set the stream type on an audio player object (e.g. {@link
     * android.media.AudioTrack}, {@link android.media.MediaPlayer}) as this is deprecated;
     * use <code>AudioAttributes</code> instead.
     *
     * @return a valid stream type for <code>Activity</code> or stream volume control that matches
     * the attributes, or {@link AudioManager#USE_DEFAULT_STREAM_TYPE} if there isn't a direct
     * match. Note that <code>USE_DEFAULT_STREAM_TYPE</code> is not a valid value for {@link
     * AudioManager#setStreamVolume(int, int, int)}.
     */
    public int getVolumeControlStream() {
        return mImpl.getVolumeControlStream();
    }

    // public API unique to AudioAttributesCompat

    /**
     * If the current SDK level is 21 or higher, return the {@link AudioAttributes} object inside
     * this {@link AudioAttributesCompat}. Otherwise <code>null</code>.
     *
     * @return the underlying {@link AudioAttributes} object or null
     */
    @Nullable
    public Object unwrap() {
        return mImpl.getAudioAttributes();
    }

    /**
     * Returns a stream type passed to {@link Builder#setLegacyStreamType(int)}, or best guessing
     * from flags and usage, or -1 if there is no converting logic in framework side (API 21+).
     *
     * @return the stream type {@see AudioManager}
     */
    public int getLegacyStreamType() {
        return mImpl.getLegacyStreamType();
    }

    /**
     * Creates an {@link AudioAttributesCompat} given an API 21 {@link AudioAttributes} object.
     *
     * @param aa an instance of {@link AudioAttributes}.
     * @return the new <code>AudioAttributesCompat</code>, or <code>null</code> on API &lt; 21
     */
    @Nullable
    public static AudioAttributesCompat wrap(@NonNull final Object aa) {
        if (sForceLegacyBehavior) {
            return null;
        }
        if (Build.VERSION.SDK_INT >= 26) {
            return new AudioAttributesCompat(new AudioAttributesImplApi26((AudioAttributes) aa));
        } else if (Build.VERSION.SDK_INT >= 21) {
            return new AudioAttributesCompat(new AudioAttributesImplApi21((AudioAttributes) aa));
        }
        return null;
    }

    // The rest of this file implements an approximation to AudioAttributes using old stream types

    /**
     * Returns the content type.
     *
     * @return one of the values that can be set in {@link Builder#setContentType(int)}
     */
    public int getContentType() {
        return mImpl.getContentType();
    }

    /**
     * Returns the usage.
     *
     * @return one of the values that can be set in {@link Builder#setUsage(int)}
     */
    public @AttributeUsage int getUsage() {
        return mImpl.getUsage();
    }

    /**
     * Returns the flags.
     *
     * @return a combined mask of all flags
     */
    public int getFlags() {
        return mImpl.getFlags();
    }

    /**
     * Builder class for {@link AudioAttributesCompat} objects.
     *
     * <p>example:
     *
     * <pre class="prettyprint">
     * new AudioAttributes.Builder()
     * .setUsage(AudioAttributes.USAGE_MEDIA)
     * .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
     * .build();
     * </pre>
     *
     * <p>By default all types of information (usage, content type, flags) conveyed by an <code>
     * AudioAttributesCompat</code> instance are set to "unknown". Unknown information will be
     * interpreted as a default value that is dependent on the context of use, for instance a {@link
     * android.media.MediaPlayer} will use a default usage of
     * {@link AudioAttributesCompat#USAGE_MEDIA}. See also {@link AudioAttributes.Builder}.
     */
    public static class Builder {
        final AudioAttributesImpl.Builder mBuilderImpl;
        /**
         * Constructs a new Builder with the defaults. By default, usage and content type are
         * respectively {@link AudioAttributesCompat#USAGE_UNKNOWN} and {@link
         * AudioAttributesCompat#CONTENT_TYPE_UNKNOWN}, and flags are 0. It is recommended to
         * configure the usage (with {@link #setUsage(int)}) or deriving attributes from a legacy
         * stream type (with {@link #setLegacyStreamType(int)}) before calling {@link #build()} to
         * override any default playback behavior in terms of routing and volume management.
         */
        public Builder() {
            if (sForceLegacyBehavior) {
                mBuilderImpl = new AudioAttributesImplBase.Builder();
            } else if (Build.VERSION.SDK_INT >= 26) {
                mBuilderImpl = new AudioAttributesImplApi26.Builder();
            } else if (Build.VERSION.SDK_INT >= 21) {
                mBuilderImpl = new AudioAttributesImplApi21.Builder();
            } else {
                mBuilderImpl = new AudioAttributesImplBase.Builder();
            }
        }

        /**
         * Constructs a new Builder from a given AudioAttributes
         *
         * @param aa the AudioAttributesCompat object whose data will be reused in the new Builder.
         */
        public Builder(AudioAttributesCompat aa) {
            if (sForceLegacyBehavior) {
                mBuilderImpl = new AudioAttributesImplBase.Builder(aa);
            } else if (Build.VERSION.SDK_INT >= 26) {
                mBuilderImpl = new AudioAttributesImplApi26.Builder(aa.unwrap());
            } else if (Build.VERSION.SDK_INT >= 21) {
                mBuilderImpl = new AudioAttributesImplApi21.Builder(aa.unwrap());
            } else {
                mBuilderImpl = new AudioAttributesImplBase.Builder(aa);
            }
        }

        /**
         * Combines all of the attributes that have been set and return a new {@link
         * AudioAttributesCompat} object.
         *
         * @return a new {@link AudioAttributesCompat} object
         */
        public AudioAttributesCompat build() {
            return new AudioAttributesCompat(mBuilderImpl.build());
        }

        /**
         * Sets the attribute describing what is the intended use of the the audio signal, such as
         * alarm or ringtone.
         *
         * @param usage one of {@link AudioAttributesCompat#USAGE_UNKNOWN}, {@link
         *              AudioAttributesCompat#USAGE_MEDIA}, {@link
         *              AudioAttributesCompat#USAGE_VOICE_COMMUNICATION}, {@link
         *              AudioAttributesCompat#USAGE_VOICE_COMMUNICATION_SIGNALLING}, {@link
         *              AudioAttributesCompat#USAGE_ALARM},
         *              {@link AudioAttributesCompat#USAGE_NOTIFICATION},
         *              {@link AudioAttributesCompat#USAGE_NOTIFICATION_RINGTONE}, {@link
         *              AudioAttributesCompat#USAGE_NOTIFICATION_COMMUNICATION_REQUEST}, {@link
         *              AudioAttributesCompat#USAGE_NOTIFICATION_COMMUNICATION_INSTANT}, {@link
         *              AudioAttributesCompat#USAGE_NOTIFICATION_COMMUNICATION_DELAYED}, {@link
         *              AudioAttributesCompat#USAGE_NOTIFICATION_EVENT}, {@link
         *              AudioAttributesCompat#USAGE_ASSISTANT}, {@link
         *              AudioAttributesCompat#USAGE_ASSISTANCE_ACCESSIBILITY}, {@link
         *              AudioAttributesCompat#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE}, {@link
         *              AudioAttributesCompat#USAGE_ASSISTANCE_SONIFICATION}, {@link
         *              AudioAttributesCompat#USAGE_GAME}.
         * @return the same Builder instance.
         */
        public Builder setUsage(@AttributeUsage int usage) {
            mBuilderImpl.setUsage(usage);
            return this;
        }

        /**
         * Sets the attribute describing the content type of the audio signal, such as speech, or
         * music.
         *
         * @param contentType the content type values, one of {@link
         *                    AudioAttributesCompat#CONTENT_TYPE_MOVIE}, {@link
         *                    AudioAttributesCompat#CONTENT_TYPE_MUSIC}, {@link
         *                    AudioAttributesCompat#CONTENT_TYPE_SONIFICATION}, {@link
         *                    AudioAttributesCompat#CONTENT_TYPE_SPEECH}, {@link
         *                    AudioAttributesCompat#CONTENT_TYPE_UNKNOWN}.
         * @return the same Builder instance.
         */
        public Builder setContentType(@AttributeContentType int contentType) {
            mBuilderImpl.setContentType(contentType);
            return this;
        }

        /**
         * Sets the combination of flags.
         *
         * <p>This is a bitwise OR with the existing flags.
         *
         * @param flags a combination of {@link AudioAttributesCompat#FLAG_AUDIBILITY_ENFORCED},
         *              {@link AudioAttributesCompat#FLAG_HW_AV_SYNC}.
         * @return the same Builder instance.
         */
        public Builder setFlags(int flags) {
            mBuilderImpl.setFlags(flags);
            return this;
        }

        /**
         * Sets attributes as inferred from the legacy stream types.
         *
         * <p>Warning: do not use this method in combination with setting any other attributes such
         * as usage, content type, or flags, as this method will overwrite (the more accurate)
         * information describing the use case previously set in the Builder.
         * In general, avoid using it and prefer setting usage and content type directly with
         * {@link #setUsage(int)} and {@link #setContentType(int)}.
         *
         * <p>Use this method when building an {@link AudioAttributes} instance to initialize some
         * of the attributes by information derived from a legacy stream type.
         *
         * @param streamType one of <code>AudioManager.STREAM_*</code>
         * @return this same Builder instance.
         */
        public Builder setLegacyStreamType(int streamType) {
            mBuilderImpl.setLegacyStreamType(streamType);
            return this;
        }
    }

    @Override
    public int hashCode() {
        return mImpl.hashCode();
    }

    @Override
    public String toString() {
        return mImpl.toString();
    }

    static String usageToString(int usage) {
        switch (usage) {
            case USAGE_UNKNOWN:
                return "USAGE_UNKNOWN";
            case USAGE_MEDIA:
                return "USAGE_MEDIA";
            case USAGE_VOICE_COMMUNICATION:
                return "USAGE_VOICE_COMMUNICATION";
            case USAGE_VOICE_COMMUNICATION_SIGNALLING:
                return "USAGE_VOICE_COMMUNICATION_SIGNALLING";
            case USAGE_ALARM:
                return "USAGE_ALARM";
            case USAGE_NOTIFICATION:
                return "USAGE_NOTIFICATION";
            case USAGE_NOTIFICATION_RINGTONE:
                return "USAGE_NOTIFICATION_RINGTONE";
            case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
                return "USAGE_NOTIFICATION_COMMUNICATION_REQUEST";
            case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
                return "USAGE_NOTIFICATION_COMMUNICATION_INSTANT";
            case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
                return "USAGE_NOTIFICATION_COMMUNICATION_DELAYED";
            case USAGE_NOTIFICATION_EVENT:
                return "USAGE_NOTIFICATION_EVENT";
            case USAGE_ASSISTANCE_ACCESSIBILITY:
                return "USAGE_ASSISTANCE_ACCESSIBILITY";
            case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
                return "USAGE_ASSISTANCE_NAVIGATION_GUIDANCE";
            case USAGE_ASSISTANCE_SONIFICATION:
                return "USAGE_ASSISTANCE_SONIFICATION";
            case USAGE_GAME:
                return "USAGE_GAME";
            case USAGE_ASSISTANT:
                return "USAGE_ASSISTANT";
            default:
                return "unknown usage " + usage;
        }
    }

    abstract static class AudioManagerHidden {
        public static final int STREAM_BLUETOOTH_SCO = 6;
        public static final int STREAM_SYSTEM_ENFORCED = 7;
        public static final int STREAM_TTS = 9;
        public static final int STREAM_ACCESSIBILITY = 10;

        private AudioManagerHidden() {
        }
    }

    /**
     * Prevent AudioAttributes from being used even on platforms that support it.
     *
     * @hide For testing only.
     */
    @RestrictTo(LIBRARY)
    public static void setForceLegacyBehavior(boolean force) {
        sForceLegacyBehavior = force;
    }

    int getRawLegacyStreamType() {
        return mImpl.getRawLegacyStreamType();
    }

    static int toVolumeStreamType(
            boolean fromGetVolumeControlStream, int flags, @AttributeUsage int usage) {
        // flags to stream type mapping
        if ((flags & FLAG_AUDIBILITY_ENFORCED) == FLAG_AUDIBILITY_ENFORCED) {
            return fromGetVolumeControlStream
                    ? AudioManager.STREAM_SYSTEM
                    : AudioManagerHidden.STREAM_SYSTEM_ENFORCED;
        }
        if ((flags & FLAG_SCO) == FLAG_SCO) {
            return fromGetVolumeControlStream
                    ? AudioManager.STREAM_VOICE_CALL
                    : AudioManagerHidden.STREAM_BLUETOOTH_SCO;
        }

        // usage to stream type mapping
        switch (usage) {
            case USAGE_MEDIA:
            case USAGE_GAME:
            case USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
            case USAGE_ASSISTANT:
                return AudioManager.STREAM_MUSIC;
            case USAGE_ASSISTANCE_SONIFICATION:
                return AudioManager.STREAM_SYSTEM;
            case USAGE_VOICE_COMMUNICATION:
                return AudioManager.STREAM_VOICE_CALL;
            case USAGE_VOICE_COMMUNICATION_SIGNALLING:
                return fromGetVolumeControlStream
                        ? AudioManager.STREAM_VOICE_CALL
                        : AudioManager.STREAM_DTMF;
            case USAGE_ALARM:
                return AudioManager.STREAM_ALARM;
            case USAGE_NOTIFICATION_RINGTONE:
                return AudioManager.STREAM_RING;
            case USAGE_NOTIFICATION:
            case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
            case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
            case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
            case USAGE_NOTIFICATION_EVENT:
                return AudioManager.STREAM_NOTIFICATION;
            case USAGE_ASSISTANCE_ACCESSIBILITY:
                return AudioManagerHidden.STREAM_ACCESSIBILITY;
            case USAGE_UNKNOWN:
                return AudioManager.STREAM_MUSIC;
            default:
                if (fromGetVolumeControlStream) {
                    throw new IllegalArgumentException(
                            "Unknown usage value " + usage + " in audio attributes");
                } else {
                    return AudioManager.STREAM_MUSIC;
                }
        }
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof AudioAttributesCompat)) {
            return false;
        }
        final AudioAttributesCompat that = (AudioAttributesCompat) o;
        if (this.mImpl == null) {
            return that.mImpl == null;
        }
        return this.mImpl.equals(that.mImpl);
    }

    /** @hide */
    @IntDef({
            USAGE_UNKNOWN,
            USAGE_MEDIA,
            USAGE_VOICE_COMMUNICATION,
            USAGE_VOICE_COMMUNICATION_SIGNALLING,
            USAGE_ALARM,
            USAGE_NOTIFICATION,
            USAGE_NOTIFICATION_RINGTONE,
            USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
            USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
            USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
            USAGE_NOTIFICATION_EVENT,
            USAGE_ASSISTANCE_ACCESSIBILITY,
            USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
            USAGE_ASSISTANCE_SONIFICATION,
            USAGE_GAME,
            USAGE_ASSISTANT,
    })
    @RestrictTo(LIBRARY)
    @Retention(RetentionPolicy.SOURCE)
    public @interface AttributeUsage {
    }

    /** @hide */
    @IntDef({
            CONTENT_TYPE_UNKNOWN,
            CONTENT_TYPE_SPEECH,
            CONTENT_TYPE_MUSIC,
            CONTENT_TYPE_MOVIE,
            CONTENT_TYPE_SONIFICATION
    })
    @Retention(RetentionPolicy.SOURCE)
    @RestrictTo(LIBRARY)
    public @interface AttributeContentType {
    }
}